iOS避免键盘遮挡输入方案
项目中经常会遇到这样的问题:一个tableView中有大量的textField,当点击屏幕底部的textfield时,由于键盘弹出挡住了textfield输入框里的内容,造成很差的用户体验,如下图,点击价格那一行,会出现图二这种效果(弹出的键盘完全遮盖了输入)。
图一:
图二:
解决思路:自定义一个textfield,声明一个公用方法 - (void)adjustTextFieldFrameWhenBeginEdtingWithView: keyBoardHeight: 并实现它,这个方法的作用是调整controller的view的y值使整个view上移,让被点击的textfield显示出来,建议在controller的view的textfield的代理方法 -(void)textFieldDidBeginEditing: 中获取自定义的textfield,并调用它的此方法(开始编辑时就调整view的y值)。
1.自定义textfield:
实现公用方法: - (void)adjustTextFieldFrameWhenBeginEdtingWithView:
1 - (void)adjustTextFieldFrameWhenBeginEdtingWithView:(UIView *)view keyBoardHeight:(CGFloat)keyboadHeight 2 { 3 // 将控制器view保存起来 4 self.adjustView = view; 5 6 // 将textfield的坐标转换到控制器view坐标系中 7 CGRect selfFrame = [self convertRect:self.bounds toView:view]; 8 9 // 键盘的y值 10 CGFloat keyBoardY = 0; 11 12 13 keyBoardY = [UIScreen mainScreen].bounds.size.height - keyboadHeight ; 14 15 16 17 // 控制器view 要调整的高度 18 CGFloat adjustY = selfFrame.origin.y + selfFrame.size.height + MARGIN - keyBoardY; 19 20 21 22 if (adjustY > 0) { // 调整高度大于0 23 24 [UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 25 26 view.y = - adjustY; 27 } completion:^(BOOL finished) { 28 29 }]; 30 }else{ 31 [UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 32 view.y = 0; 33 } completion:^(BOOL finished) { 34 35 }]; 36 } 37 38 39 }
第13行用到了键盘的高度keyboadHeight,所以我们还需要在控制器中得到键盘的高度。
2.在控制器中获取键盘高度
在控制器的viewDidLoad方法中,注册通知(监听键盘出现的通知)。
//增加监听,当键盘出现或改变时收出消息 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
当键盘弹出时,获取键盘高度,并将键盘高度传入定义好的block
//当键盘出现或改变时调用 - (void)keyboardWillShow:(NSNotification *)aNotification { //获取键盘的高度 NSDictionary *userInfo = [aNotification userInfo]; NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey]; CGRect keyboardRect = [aValue CGRectValue]; CGFloat keyboadHeight = keyboardRect.size.height; // 调用保存好的block并将键盘高度传入 self.editingBlock(keyboadHeight); }
3.在控制器中调用textfield的自适应方法 - (void)adjustTextFieldFrameWhenBeginEdtingWithView: keyBoardHeight:
在控制器的textdelegate方法 - (void)textFieldDidBeginEditing: 中,定义block,在block中调用自定义textfield的自适应方法 - (void)adjustTextFieldFrameWhenBeginEdtingWithView: keyBoardHeight: ,并传入键盘高度。
之所以用block,是因为方法 - (void)textFieldDidBeginEditing: 被调用时,还没有获取到键盘高度,所以先将代码保存为block,等获取到键盘高度后再传入键盘高度,调用textfield的自适应键盘高度的方法 - (void)adjustTextFieldFrameWhenBeginEdtingWithView: keyBoardHeight:
block中调用自定义textfield的 - (void)adjustTextFieldFrameWhenBeginEdtingWithView: keyBoardHeight: 方法,并把键盘高度作为参数传入自定义textfield。
1 #pragma YDTextFieldDelegate 2 3 - (void)textFieldDidBeginEditing:(UITextField *)textField 4 { 5 YDTextField *tf = (YDTextField *)textField; 6 7 __weak typeof(self) weakSelf = self; 8 9 // 定义block,等待keyboardWillShow:方法获取键盘高度后调用 10 self.editingBlock = ^(CGFloat keyboadHeight){ 11 12 // 此处调用自定义textfield的自适应方法 13 [tf adjustTextFieldFrameWhenBeginEdtingWithView:weakSelf.view keyBoardHeight:keyboadHeight]; 14 15 }; 16 17 }
4. 输入完成后处理
在控制器viewDidLoad方法中,注册通知,监听键盘消失。
// 当键盘消失时响应 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
键盘消失后,将调整后的view还原。
// 当键盘消失时调用 - (void)keyboardWillHide:(NSNotification *)note { if ([note.name isEqualToString:UIKeyboardWillShowNotification]) { }else{ [UIView animateWithDuration:0.25 animations:^{ self.view.y = 0; } completion:^(BOOL finished) { }]; } }
如此就完成了textfield的自适应,每次点击底部textfield,view会根据textfield的位置上移一段距离,不被键盘遮盖,效果如下:
图三:
图四:
附上demo代码:
控制器中代码:
1 // 2 // ViewController.m 3 // TextfieldDemo 4 // 5 // Created by heyode on 16/5/20. 6 // Copyright © 2016年 heyode. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 #import "YDTextField.h" 11 #import "UIView+frame.h" 12 // 键盘和当前活动textfield的间距 13 #define MARGIN 15 14 15 //定义随机色 16 #define randomColor [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1]; 17 18 typedef void(^textFieldDidBeginEditingBlock)(CGFloat keyboadHeight); 19 #define BASECOUNT 30 20 21 @interface ViewController ()<UITableViewDelegate,UITableViewDataSource,UITextFieldDelegate> 22 /** tableView */ 23 @property (nonatomic,weak) UITableView *tableView; 24 25 /** 数据源 */ 26 @property (nonatomic,strong) NSMutableArray *datas; 27 28 /** block */ 29 @property (nonatomic,copy) textFieldDidBeginEditingBlock editingBlock; 30 31 32 @end 33 34 @implementation ViewController 35 36 - (void)viewDidLoad { 37 [super viewDidLoad]; 38 39 [self setUpDataSouce]; 40 [self setUpTableView]; 41 42 [self setUpNotification]; 43 } 44 45 - (void)setUpNotification 46 { 47 //增加监听,当键盘出现或改变时收出消息 48 [[NSNotificationCenter defaultCenter] addObserver:self 49 selector:@selector(keyboardWillShow:) 50 name:UIKeyboardWillShowNotification 51 object:nil]; 52 53 // 当键盘消失时响应 54 [[NSNotificationCenter defaultCenter] addObserver:self 55 selector:@selector(keyboardWillHide:) 56 name:UIKeyboardWillHideNotification object:nil]; 57 58 } 59 60 61 // 当键盘消失时调用 62 - (void)keyboardWillHide:(NSNotification *)note 63 { 64 if ([note.name isEqualToString:UIKeyboardWillShowNotification]) { 65 66 }else{ 67 [UIView animateWithDuration:0.25 animations:^{ 68 self.view.y = 0; 69 } completion:^(BOOL finished) { 70 71 }]; 72 } 73 } 74 75 //当键盘出现或改变时调用 76 - (void)keyboardWillShow:(NSNotification *)aNotification 77 { 78 //获取键盘的高度 79 NSDictionary *userInfo = [aNotification userInfo]; 80 NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey]; 81 CGRect keyboardRect = [aValue CGRectValue]; 82 CGFloat keyboadHeight = keyboardRect.size.height; 83 84 // 调用保存好的block并将键盘高度传入 85 self.editingBlock(keyboadHeight); 86 } 87 88 - (void)setUpTableView 89 { 90 UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 91 tableView.delegate = self; 92 tableView.dataSource = self; 93 [self.view addSubview:tableView]; 94 95 } 96 97 98 - (void)setUpDataSouce 99 { 100 self.datas = [NSMutableArray array]; 101 102 for (int i = 0; i < 20; i++) { 103 NSString *str = [NSString stringWithFormat:@"%i",i]; 104 [self.datas addObject:str]; 105 } 106 107 } 108 109 #pragma UITableviewDatasouce 110 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 111 { 112 return self.datas.count; 113 } 114 115 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 116 { 117 118 119 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; 120 if (cell == nil) { 121 cell = [[UITableViewCell alloc] initWithStyle:0 reuseIdentifier:@"cell"]; 122 } 123 124 125 for (id view in cell.contentView.subviews) { 126 [(UIView *)view removeFromSuperview]; 127 } 128 129 130 cell.textLabel.text = self.datas[indexPath.row]; 131 132 YDTextField *tf = [[YDTextField alloc] initWithFrame:CGRectMake(50, (cell.height - cell.height - 2)/2, cell.width , cell.height - 2)]; 133 tf.tag = indexPath.row + BASECOUNT; 134 135 tf.backgroundColor = randomColor; 136 tf.delegate = self; 137 138 [cell.contentView addSubview:tf]; 139 return cell; 140 } 141 142 #pragma YDTextFieldDelegate 143 144 - (void)textFieldDidBeginEditing:(UITextField *)textField 145 { 146 YDTextField *tf = (YDTextField *)textField; 147 148 __weak typeof(self) weakSelf = self; 149 150 // 定义block,等待keyboardWillShow:方法获取键盘高度后调用 151 self.editingBlock = ^(CGFloat keyboadHeight){ 152 153 // 此处调用自定义textfield的自适应方法 154 [tf adjustTextFieldFrameWhenBeginEdtingWithView:weakSelf.view keyBoardHeight:keyboadHeight]; 155 156 }; 157 158 } 159 160 161 @end
自定义textfield代码:
1 // 2 // YDTextField.m 3 // TextfieldDemo 4 // 5 // Created by heyode on 16/5/20. 6 // Copyright © 2016年 heyode. All rights reserved. 7 // 8 9 #import "YDTextField.h" 10 #import "UIView+frame.h" 11 12 // 键盘和当前活动textfield的间距 13 #define MARGIN 15 14 15 @interface YDTextField() 16 @property (weak, nonatomic) UIView *adjustView; 17 /**键盘高度 */ 18 @property (nonatomic,assign) CGFloat keyboadHeight; 19 20 @end 21 22 @implementation YDTextField 23 24 25 - (instancetype)initWithFrame:(CGRect)frame 26 { 27 if (self = [super initWithFrame:frame]) { 28 [self initialize]; 29 30 } 31 return self; 32 } 33 34 - (void)awakeFromNib 35 { 36 37 [self initialize]; 38 } 39 40 - (void)layoutSubviews 41 { 42 [super layoutSubviews]; 43 } 44 45 - (void)initialize 46 { 47 48 // 点击return时,结束编辑状态 49 [self addTarget:self action:@selector(endEditing:) forControlEvents:UIControlEventEditingDidEndOnExit]; 50 } 51 52 53 54 55 56 - (void)adjustTextFieldFrameWhenBeginEdtingWithView:(UIView *)view keyBoardHeight:(CGFloat)keyboadHeight 57 { 58 // 将控制器view保存起来 59 self.adjustView = view; 60 61 // 将textfield的坐标转换到控制器view坐标系中 62 CGRect selfFrame = [self convertRect:self.bounds toView:view]; 63 64 // 键盘的y值 65 CGFloat keyBoardY = 0; 66 67 68 keyBoardY = [UIScreen mainScreen].bounds.size.height - keyboadHeight ; 69 70 71 72 // 控制器view 要调整的高度 73 CGFloat adjustY = selfFrame.origin.y + selfFrame.size.height + MARGIN - keyBoardY; 74 75 76 77 if (adjustY > 0) { // 调整高度大于0 78 79 [UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 80 81 view.y = - adjustY; 82 } completion:^(BOOL finished) { 83 84 }]; 85 }else{ 86 [UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 87 view.y = 0; 88 } completion:^(BOOL finished) { 89 90 }]; 91 } 92 93 94 } 95 96 97 98 99 100 @end