iOS完美實現輸入框隨鍵盤無縫滑動的效果_KLCPopKeyBoard
阿新 • • 發佈:2019-02-16
iOS中UITextField控制元件和UITextView控制元件經常需要對鍵盤做彈起和退出動作,一般使用的是becomeFirstResponder和resignFirstResponder方法,但是這樣也有明顯的缺點,就是會在鍵盤的彈起退出過程中經常出現黑邊,或者斷層,導致效果很不好看,在網上找了些資料,自己做了一個自定義的輸入框來解決這個問題,效果類似於微信和QQ的聊天框。
KLCPopKeyBoard.h
#import <UIKit/UIKit.h> @class KLCPopKeyBoard; @protocol KLCPopKeyBoardDelegate <NSObject> - (void)popKeyBoard:(KLCPopKeyBoard *)popKeyBoard didClickSend:(BOOL)didClickSend; - (void)popKeyBoardHide; - (void)popKeyBoardShow; @end @interface KLCPopKeyBoard : UIView @property (nonatomic, weak) id<KLCPopKeyBoardDelegate> delegate; @property (nonatomic, copy) NSString *content;//輸入框內容 @property (nonatomic, copy) NSString *placeholder; - (instancetype)initWithPlaceholder:(NSString *)placeholder buttonTitle:(NSString *)buttonTitle; //成對使用,可以保證一直在螢幕中出現 - (void)viewWillAppear; - (void)viewWillDisAppear; //成對使用,可以保證單次顯示 - (void)show; - (void)hide; //推出鍵盤和退出鍵盤 - (void)pushKeyboard; - (void)hideKeyboard; @end
KLCPopKeyBoard.m
#import "KLCPopKeyBoard.h" #define KeyBoardHeight 44 #define FullScreen_Height [[UIScreen mainScreen] bounds].size.height #define FullScreen_Width [[UIScreen mainScreen] bounds].size.width static inline UIViewAnimationOptions NgAnimationOptionsWithCurve(UIViewAnimationCurve curve) { switch (curve) { case UIViewAnimationCurveEaseInOut: return UIViewAnimationOptionCurveEaseInOut; case UIViewAnimationCurveEaseIn: return UIViewAnimationOptionCurveEaseIn; case UIViewAnimationCurveEaseOut: return UIViewAnimationOptionCurveEaseOut; case UIViewAnimationCurveLinear: return UIViewAnimationOptionCurveLinear; } return 0; } @interface KLCPopKeyBoard()<UITextFieldDelegate> { UIView *_bgView; UITextField *_field; UIButton *_button; NSString *_placeholder; NSString *_buttonTitle; //BOOL _willHidden; } @end @implementation KLCPopKeyBoard - (instancetype)init { self = [super init]; if (self) { _placeholder = @""; _buttonTitle = @"傳送"; [self setupUI]; } return self; } - (instancetype)initWithPlaceholder:(NSString *)placeholder buttonTitle:(NSString *)buttonTitle { self = [super init]; if (self) { _placeholder = placeholder; _buttonTitle = buttonTitle; [self setupUI]; } return self; } - (void)setupUI { self.frame = CGRectMake(0, FullScreen_Height - KeyBoardHeight, FullScreen_Width, KeyBoardHeight); _bgView = [[UIView alloc]init]; _bgView.frame = self.bounds; _bgView.backgroundColor = [UIColor whiteColor]; [self addSubview:_bgView]; UIView *line = [[UIView alloc]init]; line.frame = CGRectMake(0, 0, FullScreen_Width, 0.5); line.backgroundColor = [UIColor blackColor]; [_bgView addSubview:line]; CGFloat height = 30; CGFloat topMargin = (KeyBoardHeight - height)/2; CGFloat leftMargin = 10; CGFloat buttonWidth = 44; CGFloat buttonHeight = 30; _field = [[UITextField alloc]init]; _field.frame = CGRectMake(leftMargin, topMargin, FullScreen_Width - leftMargin*3 - buttonWidth, height); _field.backgroundColor = [UIColor whiteColor]; _field.textColor = [UIColor blackColor]; _field.font = [UIFont systemFontOfSize:14]; _field.returnKeyType = UIReturnKeyDone; _field.layer.cornerRadius = 3; _field.clipsToBounds = YES; _field.delegate = self; _field.placeholder = _placeholder; [_bgView addSubview:_field]; _button = [[UIButton alloc]init]; _button.frame = CGRectMake(CGRectGetMaxX(_field.frame)+leftMargin, topMargin, buttonWidth, buttonHeight); [_button setTitle:_buttonTitle forState:UIControlStateNormal]; _button.titleLabel.font = [UIFont systemFontOfSize:14]; _button.backgroundColor = [UIColor yellowColor]; [_button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; _button.layer.cornerRadius = 3; _button.clipsToBounds = YES; [_button addTarget:self action:@selector(didClickButton:) forControlEvents:UIControlEventTouchUpInside]; [_bgView addSubview:_button]; } #pragma mark -傳送 - (void)didClickButton:(UIButton *)btn { _content = _field.text; if ([_delegate respondsToSelector:@selector(popKeyBoard:didClickSend:)]) { [_delegate popKeyBoard:self didClickSend:YES]; _field.text = nil; [self hideKeyboard]; } } - (void)setPlaceholder:(NSString *)placeholder { _placeholder = placeholder; _field.placeholder = placeholder; } #pragma mark - 展示控制 - (void)viewWillAppear { [self show]; } - (void)viewWillDisAppear { [self hide]; } - (void)show { dispatch_async(dispatch_get_main_queue(), ^{ for (UIView *view in [UIApplication sharedApplication].keyWindow.subviews) { if ([view isKindOfClass:[KLCPopKeyBoard class]]) { return; } } [[UIApplication sharedApplication].keyWindow addSubview:self]; [[UIApplication sharedApplication].keyWindow bringSubviewToFront:self]; }); } -(void)hide { dispatch_async(dispatch_get_main_queue(), ^{ [self removeFromSuperview]; }); /* if ([_field isFirstResponder]) { _willHidden = YES; [self hideKeyboard]; } else { dispatch_async(dispatch_get_main_queue(), ^{ [self removeFromSuperview]; }); }*/ } #pragma mark - 推出和退出鍵盤 - (void)pushKeyboard { if (![_field isFirstResponder]) { [_field becomeFirstResponder]; if ([_delegate respondsToSelector:@selector(popKeyBoardShow)]) { // [_delegate popKeyBoardShow]; } } } - (void)hideKeyboard { if ([_field isFirstResponder]) { [_field resignFirstResponder]; if ([_delegate respondsToSelector:@selector(popKeyBoardHide)]) { [_delegate popKeyBoardHide]; } } } #pragma mark - 鍵盤監聽 - (void)startListenKeyboard { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardDidShow:) name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardDidHide:) name:UIKeyboardDidHideNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil]; } - (void)endListenKeyboard { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)onKeyboardWillShow:(NSNotification *)note { } - (void)onKeyboardDidShow:(NSNotification *)note { } - (void)onKeyboardWillHide:(NSNotification *)note { if ([_delegate respondsToSelector:@selector(popKeyBoardHide)]) { [_delegate popKeyBoardHide]; } } - (void)onKeyboardDidHide:(NSNotification *)note { } - (void)onKeyboardWillChangeFrame:(NSNotification *)note { //Log("%@",note.userInfo); [self captureKeyboardFrameWithInfo:note.userInfo]; } - (void)onKeyboardDidChangeFrame:(NSNotification *)note { //Log("%@",note.userInfo); //[self captureKeyboardFrameWithInfo:note.userInfo]; } - (void)captureKeyboardFrameWithInfo:(NSDictionary *)info { CGRect _endFrame = [info[UIKeyboardFrameEndUserInfoKey] CGRectValue]; NSTimeInterval _animationDuration = [info[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationCurve animationCurve = (UIViewAnimationCurve)[info[UIKeyboardAnimationCurveUserInfoKey] integerValue]; [UIView animateWithDuration:_animationDuration delay:0 options:NgAnimationOptionsWithCurve(animationCurve) animations:^{ CGRect myFrame = self.frame; myFrame.origin.y = _endFrame.origin.y - KeyBoardHeight; self.frame = myFrame; } completion:^(BOOL finished) { /*if (_willHidden) { dispatch_async(dispatch_get_main_queue(), ^{ [self removeFromSuperview]; }); _willHidden = NO; }*/ }]; } #pragma mark - TextField delegate -(BOOL)textFieldShouldBeginEditing:(UITextField *)textField { if ([_delegate respondsToSelector:@selector(popKeyBoardHide)]) { [_delegate popKeyBoardShow]; } [self startListenKeyboard]; return YES; } -(BOOL)textFieldShouldEndEditing:(UITextField *)textField { return YES; } -(void)textFieldDidEndEditing:(UITextField *)textField { self.content = textField.text; [self endListenKeyboard]; } -(BOOL)textFieldShouldReturn:(UITextField *)textField { // [textField resignFirstResponder]; // if ([_delegate respondsToSelector:@selector(popKeyBoard:didClickSend:)]) { // [_delegate popKeyBoard:self didClickSend:YES]; // _field.text = nil; // if ([_delegate respondsToSelector:@selector(popKeyBoardHide)]) { // [_delegate popKeyBoardHide]; // } // } [self didClickButton:nil]; return YES; } @end