IM中输入框的优化方案实现

IM中输入框的优化方案实现

以下图的输入框为例

stand

输入框的呈现方式选择

以下两个方法对比

  • Keyboard的inputAccessoryView

相对推荐的方法,有更好的丰富的交互效果

可以与scrollView的一些属性直接绑定

  • InputView的frame适应

传统的方法

优点:灵活控制显示位置

缺点:过多的计算frame

###InputAccessoryView方式

案例见GitHub的Demo

iOS的输入源都有输入源(keyboard及keyboard的配件InputAccessoryView),那通常的方法是输入源控件(Textfield、TextView等)使用一般的InputView的frame适应

解释几个技巧点

  • InputView( 输入源 )的父视图作为该InputView的InputAccessoryView,要避免相互引用
  • 巧用第三方不可见的InputView在适当时间点转移第一响应者给可见的InputView
  • 完成编辑时去除第一响应者(注意iOS9下键盘响应逻辑视图层级都发生了变化)

主要代码

simulator screen shot nov 27 2015 4 17 38 pm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 单例初始化
+ (UUInputAccessoryView*)sharedView {
static dispatch_once_t once;
static UUInputAccessoryView *sharedView;
dispatch_once(&once, ^ {
sharedView = [[UUInputAccessoryView alloc] init];
sharedView->btnBack = [UIButton buttonWithType:UIButtonTypeCustom];
sharedView->btnBack.frame = CGRectMake(0, 0, UUIAV_MAIN_W, UUIAV_MAIN_H);
[sharedView->btnBack addTarget:sharedView action:@selector(dismiss) forControlEvents:UIControlEventTouchUpInside];
sharedView->btnBack.backgroundColor=[UIColor clearColor];
UIToolbar *toolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, UUIAV_MAIN_W, 44)];
sharedView->inputView = [[UITextField alloc]initWithFrame:CGRectMake(UUIAV_Edge_Hori, UUIAV_Edge_Vert, UUIAV_MAIN_W-UUIAV_Btn_W-4*UUIAV_Edge_Hori, UUIAV_Btn_H)];
sharedView->inputView.borderStyle = UITextBorderStyleRoundedRect;
sharedView->inputView.returnKeyType = UIReturnKeyDone;
sharedView->inputView.clearButtonMode = UITextFieldViewModeWhileEditing;
sharedView->inputView.enablesReturnKeyAutomatically = YES;
sharedView->inputView.delegate = sharedView;
[toolbar addSubview:sharedView->inputView];
sharedView->assistView = [[UITextField alloc]init];
sharedView->assistView.delegate = sharedView;
sharedView->assistView.returnKeyType = UIReturnKeyDone;
sharedView->assistView.enablesReturnKeyAutomatically = YES;
[sharedView->btnBack addSubview:sharedView->assistView];
sharedView->assistView.inputAccessoryView = toolbar;
sharedView->BtnSave = [UIButton buttonWithType:UIButtonTypeCustom];
sharedView->BtnSave.frame = CGRectMake(UUIAV_MAIN_W-UUIAV_Btn_W-2*UUIAV_Edge_Hori, UUIAV_Edge_Vert, UUIAV_Btn_W, UUIAV_Btn_H);
sharedView->BtnSave.backgroundColor = [UIColor clearColor];
[sharedView->BtnSave setTitle:@"确定" forState:UIControlStateNormal];
[sharedView->BtnSave setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[sharedView->BtnSave addTarget:sharedView action:@selector(Done) forControlEvents:UIControlEventTouchUpInside];
[toolbar addSubview:sharedView->BtnSave];
});
CGRectGetHeight([UIScreen mainScreen].bounds);
return sharedView;
}

实现逻辑代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
+ (void)showKeyboardType:(UIKeyboardType)type content:(NSString *)content Block:(UUInputAccessoryBlock)block
{
[[UUInputAccessoryView sharedView] show:block
keyboardType:type
content:content];
}
- (void)show:(UUInputAccessoryBlock)block keyboardType:(UIKeyboardType)type content:(NSString *)content
{
UIWindow *window=[UIApplication sharedApplication].keyWindow;
[window addSubview:btnBack];
inputBlock = block;
inputView.text = content;
inputView.keyboardType = type;
assistView.keyboardType = type;
[assistView becomeFirstResponder];
shouldDismiss = NO;
[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardDidShowNotification
object:nil
queue:nil
usingBlock:^(NSNotification * _Nonnull note) {
if (!shouldDismiss) {
[inputView becomeFirstResponder];
}
}];
}
- (void)Done
{
[inputView resignFirstResponder];
!inputBlock ?: inputBlock(inputView.text);
[self dismiss];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self Done];
return NO;
}
- (void)dismiss
{
shouldDismiss = YES;
[inputView resignFirstResponder];
[btnBack removeFromSuperview];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

InputView的frame适应

案例见GitHub的Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 键盘响应布局
@objc func keyboardFrameChanged(notification: NSNotification) {
let dict = NSDictionary(dictionary: notification.userInfo!)
let keyboardValue = dict.objectForKey(UIKeyboardFrameEndUserInfoKey) as! NSValue
let bottomDistance = mainScreenSize().height - keyboardValue.CGRectValue().origin.y
let duration = Double(dict.objectForKey(UIKeyboardAnimationDurationUserInfoKey) as! NSNumber)
UIView.animateWithDuration(duration, animations: {
self.inputViewConstraint!.constant = -bottomDistance
self.view.layoutIfNeeded()
}, completion: {
(value: Bool) in
self.chatTableView.scrollToBottom(animation: true)
})
}

ScrollView下拉动态修改keyboard(InputView)的frame

常见隐藏keyboard的一些方式

  • TouchBeigin
  • DidDrag
  • EndDrag
  • Interactive

iOS7 开始,ScrollView提供

1
2
3
4
5
6
@available(iOS 7.0, *)
public enum UIScrollViewKeyboardDismissMode : Int {
case None
case OnDrag // dismisses the keyboard when a drag begins
case Interactive // the keyboard follows the dragging touch off screen, and may be pulled upward again to cancel the dismiss
}

所以在ScrollView上添加scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.Interactive就可以了。
效果详见iOS7及以上原生设备的短信滑动消失键盘的交互