Skip to content
This repository has been archived by the owner on Oct 19, 2023. It is now read-only.

Add changeable buttons property and (optionally) animate button changes #7

Merged
merged 4 commits into from
Jun 25, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Hope you enjoy it! Please Fork and send Pull Requests!
##Contributors
- [Rudd Fawcett (@ruddfawcett)] (https://github.com/ruddfawcett) - Creator (Version 1.0)
- [Brandon Butler (@Hackmodford)] (https://github.com/Hackmodford) - Heavy Contributor (Version 1.1)
- [Jesús A. Álvarez (@zydeco)] (https://github.com/zydeco) - Contributor

##License

Expand Down
4 changes: 4 additions & 0 deletions RFKeyboardToolbar/RFKeyboardToolbar.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

@interface RFKeyboardToolbar : UIView

@property (nonatomic, strong) NSArray *buttons;

+ (instancetype)toolbarViewWithButtons:(NSArray *)buttons;

- (void)setButtons:(NSArray *)buttons animated:(BOOL)animated;

@end
72 changes: 68 additions & 4 deletions RFKeyboardToolbar/RFKeyboardToolbar.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ @interface RFKeyboardToolbar ()
@property (nonatomic,strong) UIView *toolbarView;
@property (nonatomic,strong) UIScrollView *scrollView;
@property (nonatomic,strong) CALayer *topBorder;
@property (nonatomic,strong) NSArray *buttonsToAdd;

@end

Expand All @@ -26,7 +25,7 @@ + (instancetype)toolbarViewWithButtons:(NSArray *)buttons {
- (id)initWithButtons:(NSArray*)buttons {
self = [super initWithFrame:CGRectMake(0, 0, self.window.rootViewController.view.bounds.size.width, 40)];
if (self) {
_buttonsToAdd = buttons;
_buttons = [buttons copy];
self.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
[self addSubview:[self inputAccessoryView]];
}
Expand Down Expand Up @@ -62,12 +61,19 @@ - (UIScrollView*)fakeToolbar {
_scrollView.showsHorizontalScrollIndicator = NO;
_scrollView.contentInset = UIEdgeInsetsMake(6.0f, 0.0f, 8.0f, 6.0f);

[self addButtons];

return _scrollView;
}

- (void)addButtons
{
NSUInteger index = 0;
NSUInteger originX = 8;

CGRect originFrame;

for (RFToolbarButton *eachButton in _buttonsToAdd) {
for (RFToolbarButton *eachButton in _buttons) {
originFrame = CGRectMake(originX, 0, eachButton.frame.size.width, eachButton.frame.size.height);
eachButton.frame = originFrame;

Expand All @@ -80,8 +86,66 @@ - (UIScrollView*)fakeToolbar {
CGSize contentSize = _scrollView.contentSize;
contentSize.width = originX - 8;
_scrollView.contentSize = contentSize;
}

- (void)setButtons:(NSArray*)buttons
{
[_buttons makeObjectsPerformSelector:@selector(removeFromSuperview)];
_buttons = [buttons copy];
[self addButtons];
}

- (void)setButtons:(NSArray *)buttons animated:(BOOL)animated
{
if (animated == NO)
{
self.buttons = buttons;
return;
}

return _scrollView;
NSMutableSet *removeButtons = [NSMutableSet setWithArray:_buttons];
[removeButtons minusSet:[NSSet setWithArray:buttons]];
NSMutableSet *addButtons = [NSMutableSet setWithArray:buttons];
[addButtons minusSet:[NSSet setWithArray:_buttons]];
_buttons = [buttons copy];

// calculate end frames
NSUInteger originX = 8;
NSUInteger index = 0;
NSMutableArray *buttonFrames = [NSMutableArray arrayWithCapacity:_buttons.count];
for (RFToolbarButton *button in _buttons) {
CGRect frame = CGRectMake(originX, 0, button.frame.size.width, button.frame.size.height);
[buttonFrames addObject:[NSValue valueWithCGRect:frame]];

originX += button.bounds.size.width + 8;
index++;
}

CGSize contentSize = _scrollView.contentSize;
contentSize.width = originX - 8;
if (contentSize.width > _scrollView.contentSize.width)
_scrollView.contentSize = contentSize;

// make added buttons appear from the right
[addButtons enumerateObjectsUsingBlock:^(RFToolbarButton *button, BOOL *stop) {
button.frame = CGRectMake(originX, 0, button.frame.size.width, button.frame.size.height);
[_scrollView addSubview:button];
}];

// animate
[UIView animateWithDuration:0.2 animations:^{
[removeButtons enumerateObjectsUsingBlock:^(RFToolbarButton *button, BOOL *stop) {
button.alpha = 0;
}];

[_buttons enumerateObjectsUsingBlock:^(RFToolbarButton *button, NSUInteger idx, BOOL *stop) {
button.frame = [buttonFrames[idx] CGRectValue];
}];

_scrollView.contentSize = contentSize;
} completion:^(BOOL finished) {
[removeButtons makeObjectsPerformSelector:@selector(removeFromSuperview)];
}];
}

@end
2 changes: 1 addition & 1 deletion RFKeyboardToolbarDemo/RFKeyboardToolbar/ViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
@interface ViewController : UIViewController <UITextViewDelegate>

@end
66 changes: 64 additions & 2 deletions RFKeyboardToolbarDemo/RFKeyboardToolbar/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,29 @@ @interface ViewController ()

@end

@implementation UITextView (InsertWord)

- (void)insertWord:(NSString*)word
{
// insert a word into the field, adding a space before and/or after it as necessary
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSRange selectedRange = self.selectedRange;
NSString *text = self.text;
BOOL hasSpaceBefore = selectedRange.location == 0 || [whitespace characterIsMember:[text characterAtIndex:selectedRange.location-1]];
BOOL hasSpaceAfter = selectedRange.location+selectedRange.length == text.length || [whitespace characterIsMember:[text characterAtIndex:selectedRange.location+selectedRange.length]];

NSMutableString *wordText = word.mutableCopy;
if (!hasSpaceBefore) [wordText insertString:@" " atIndex:0];
if (!hasSpaceAfter) [wordText appendString:@" "];
[self insertText:wordText];
}

@end

@implementation ViewController
{
RFKeyboardToolbar *keyboardToolbar;
}

- (void)viewDidLoad
{
Expand All @@ -32,9 +54,49 @@ - (void)viewDidLoad
[_textView insertText:@"You pressed a button!"];
} forControlEvents:UIControlEventTouchUpInside];

_textView.inputAccessoryView = [RFKeyboardToolbar toolbarViewWithButtons:@[exampleButton]];

keyboardToolbar = [RFKeyboardToolbar toolbarViewWithButtons:@[exampleButton]];
_textView.inputAccessoryView = keyboardToolbar;
_textView.delegate = self;

[self.view addSubview:_textView];
}

- (void)textViewDidChange:(UITextView *)textView
{
// count words
NSArray *allWords = [textView.text.lowercaseString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSCountedSet *words = [NSCountedSet new];
for (__strong NSString *word in allWords) {
word = [word stringByTrimmingCharactersInSet:[NSCharacterSet punctuationCharacterSet]];
if (word.length == 0) continue;
[words addObject:word];
}

// dictionary of existing words => buttons
NSDictionary *oldButtons = [NSDictionary dictionaryWithObjects:keyboardToolbar.buttons forKeys:[keyboardToolbar.buttons valueForKey:@"title"]];

// create new buttons
NSMutableArray *newButtons = [NSMutableArray arrayWithCapacity:words.count];
for (NSString *word in words) {
// create or reuse button
RFToolbarButton *button = oldButtons[word];
if (button == nil) {
button = [RFToolbarButton buttonWithTitle:word];
[button addEventHandler:^{
[_textView insertWord:word];
} forControlEvents:UIControlEventTouchUpInside];
}
[newButtons addObject:button];
}

// sort by frequency and alphabetically
[newButtons sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSUInteger count1 = [words countForObject:[obj1 title]];
NSUInteger count2 = [words countForObject:[obj2 title]];
if (count1 == count2) return [[obj1 title] compare:[obj2 title]];
return count1 > count2 ? NSOrderedAscending : NSOrderedDescending;
}];
[keyboardToolbar setButtons:newButtons animated:YES];
}

@end