Last active
December 31, 2020 14:29
-
-
Save matt-curtis/28461ec559d495101be8 to your computer and use it in GitHub Desktop.
Done Button for UIKeyboard NumberPad (must be set as inputAccessoryView)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <UIKit/UIKit.h> | |
@interface NumberPadDoneBtn : UIView | |
@end | |
@interface NumberPadButton : UIButton | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "NumberPadDoneBtn.h" | |
@implementation NumberPadDoneBtn { | |
NumberPadButton *doneBtn; | |
} | |
#pragma mark - | |
#pragma mark Initialization/Deallocation | |
- (id) initWithFrame:(CGRect)frame { | |
self = [super initWithFrame:CGRectMake(0, 0, 1, 1)]; | |
if(!self) return self; | |
self.clipsToBounds = false; | |
// Create UIButton | |
doneBtn = [NumberPadButton new]; | |
doneBtn.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:16.0f]; | |
[doneBtn setTitle:@"DONE" forState:UIControlStateNormal]; | |
[doneBtn addTarget:self action:@selector(stopEditing) forControlEvents:UIControlEventTouchUpInside]; | |
[self addSubview:doneBtn]; | |
// Register for UIKeyboard frame changes... | |
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardFrameChanged:) name:UIKeyboardWillChangeFrameNotification object:nil]; | |
return self; | |
} | |
- (void) dealloc { | |
[[NSNotificationCenter defaultCenter] removeObserver:self]; | |
} | |
#pragma mark - | |
#pragma mark View Layouting | |
- (void) keyboardFrameChanged:(NSNotification*)notification { | |
// Calc View Height | |
float height; float width; | |
if(UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)){ | |
width = CGRectGetWidth([UIScreen mainScreen].bounds); | |
height = CGRectGetHeight([notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]); | |
} else { | |
width = CGRectGetHeight([UIScreen mainScreen].bounds); | |
height = CGRectGetWidth([notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]); | |
} | |
// Calc Button Frame | |
// @Byte - ಠ_ಠ | |
float btnHeight = height/4; // Four Rows | |
float btnWidth = (width/3)-2; // Three Columns - 2px to account for lines | |
doneBtn.frame = CGRectMake(0, (height-btnHeight)+1, btnWidth, btnHeight); | |
// Set Button Text Color to adapt to keyboard type.. | |
if([self findFirstResponderIn:nil].keyboardAppearance == UIKeyboardAppearanceDark){ | |
doneBtn.tintColor = [UIColor colorWithRed:97/255.0f green:97/255.0f blue:97/255.0f alpha:1.0f]; | |
[doneBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; | |
} else { | |
doneBtn.tintColor = [UIColor whiteColor]; | |
[doneBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; | |
} | |
} | |
- (BOOL) pointInside:(CGPoint)point withEvent:(UIEvent *)event { | |
if(CGRectContainsPoint(doneBtn.frame, point)){ | |
return true; | |
// Normally a touch wouldn't register on the UIButton, as it's not in frame/bounds. This fixes that. | |
} | |
return [super pointInside:point withEvent:event]; | |
} | |
#pragma mark - | |
#pragma mark Responder Management/Retreival | |
- (UIView<UITextInputTraits>*) findFirstResponderIn:(UIView*)view { | |
if(view == nil) view = [self currentWindow]; | |
UIView<UITextInputTraits> *firstResponder; | |
for (UIView *iView in view.subviews){ | |
if([iView isFirstResponder]){ | |
return firstResponder = (UIView<UITextInputTraits>*)iView; | |
} else if(!firstResponder && iView.subviews.count > 0){ | |
firstResponder = [self findFirstResponderIn:iView]; | |
} | |
} | |
return firstResponder; | |
} | |
- (UIWindow*) currentWindow { | |
NSArray *windows = [UIApplication sharedApplication].windows; | |
for(UIWindow *window in windows){ | |
if(!window.hidden && window.isKeyWindow) return window; | |
} | |
return nil; | |
} | |
- (void) stopEditing { | |
[[self findFirstResponderIn:nil] resignFirstResponder]; | |
} | |
@end | |
@implementation NumberPadButton | |
- (void) setHighlighted:(BOOL)highlighted { | |
if (highlighted){ | |
self.backgroundColor = self.tintColor; | |
} else { | |
self.backgroundColor = [UIColor clearColor]; | |
} | |
} | |
@end |
Awesome!! Thank You :)
Well done
Be careful: this solution isn't working on iOS8.
Hai This button is displayed button action is not working from iOS8.3
Not working on iOS 8.3
Yes. Looks like a problem . Any fixes ?
Won't work when use third-party input method
On iOS 8.3,it displays great but can't touch.
Hello everyone - I wouldn't really recommend using this solution because it's unstable, but I'll look into getting this working. The best alternative is likely using a UIWindow, or manipulating pointInside:/hitTest.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very simple UIView subclass that adds a Done button for the NumberPad. Relies on
NSNotificationCenter
(and iOS continuing to giveinputAccessoryView
's a higher place in the view hierarchy than theUIKeyboard
). YourUITextField
orUITextView
'sinputAccessoryView
must be set to an instance of it.Next step is figure out how to make frame rotations nicer. Currently it stutters tad bit as
UIKeyboardWillChangeFrameNotification
is sent after rotation completes. UIKeyboard changes the width of theinputAccessoryView
during rotation, so overridingsetFrame:
setting alpha to0
and fading it back inUIKeyboardWillChangeFrameNotification
is one approach.Feel free to extend! This doesn't adapt to situations where you need your
inputAccessoryView
set to something else, however it is simple enough to convert it into an encapsulation view with proper adjustments for resulting frame changes.