我们在iOS的开发过程中,经常要在包含UIScrollView的view中监听键盘的通知,有时候会出现一些bug,比方说UIKeyboardWillShowNotification可能会调用多次。
通过这篇文章我们来讨论几个经常出现的问题,并且了解一下对应的解决方案。
到公众号【iOS开发栈】学习更多SwiftUI、iOS开发相关内容。
UIScrollView退出键盘
拖动UIScrollView退出键盘的方法:
typedef NS_ENUM(NSInteger, UIScrollViewKeyboardDismissMode) {
UIScrollViewKeyboardDismissModeNone,
UIScrollViewKeyboardDismissModeOnDrag, // dismisses the keyboard when a drag begins
UIScrollViewKeyboardDismissModeInteractive, // the keyboard follows the dragging touch off screen, and may be pulled upward again to cancel the dismiss
}
@property(nonatomic) UIScrollViewKeyboardDismissMode keyboardDismissMode // 默认是None,UIScrollView和Keyboar不会有任何交互效果
UIScrollViewKeyboardDismissModeOnDrag当开始拖动时,keyboard会退出屏幕。在iOS14的模拟器上动画有点不流畅。UIScrollViewKeyboardDismissModeInteractive当拖动手势进入键盘区域时,键盘会跟随拖动上升或者下降。
UIKeyboardWillShowNotification多次重复通知
多个TextField或者TextView之间切换时,UIKeyboardWillShowNotification、UIKeyboardWillChangeFrameNotification每次都会调用(但是UIKeyboardWillHideNotification却不会调用),当你使用上面提到的UIScrollViewKeyboardDismissModeInteractive时,通知甚至会在一个动画过程中频繁调用。
我们在处理一些业务逻辑的时候需要谨记这个特点,不要寄希望于只会调用一次。比方说要在UIKeyboardWillShowNotification的回调中把某个视图上移。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willShow:) name:UIKeyboardWillShowNotification object:nil]; // 订阅通知
❌
- (void)willShow:(NSNotification *)noti {
NSLog(@"willShow");
CGRect keyboarFrame = [noti.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect bottomViewFrame = _bottomView.frame;
bottomViewFrame.origin.y -= keyboarFrame.size.height;
_bottomView.frame = bottomViewFrame;
}
✅
// 使用固定高度的方法
- (void)willShow:(NSNotification *)noti {
NSLog(@"willShow");
CGRect keyboarFrame = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect bottomViewFrame = _bottomView.frame;
bottomViewFrame.origin.y = self.view.bounds.size.height - keyboarFrame.size.height - _bottomView.bounds.size.height;
_bottomView.frame = bottomViewFrame;
}
✅
// 使用全局变量的方法
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didHide:) name:UIKeyboardDidHideNotification object:nil]; // 订阅键盘消失的通知
static BOOL keyboarShow = NO;
- (void)willShow:(NSNotification *)noti {
NSLog(@"willShow");
if (keyboarShow == YES) {
return;
}
keyboarShow = YES;
CGRect keyboarFrame = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect bottomViewFrame = _bottomView.frame;
bottomViewFrame.origin.y = self.view.bounds.size.height - keyboarFrame.size.height - _bottomView.bounds.size.height;
_bottomView.frame = bottomViewFrame;
}
- (void)didHide:(NSNotification *)noti {
NSLog(@"didHide");
keyboarShow = NO;
}
点击UIScrollView触发UIKeyboardWillShowNotification通知
点击TextFiled或者TextView后,再点击UIScrollView,UIKeyboardWillShowNotification的回调会被触发,我不能确定造成这个现象的原因是什么,不过猜测是因为iOS的事件管理系统的内部bug导致的。解决这个问题的终极方法和我们上面⬆️用的方法是一样的。
到公众号【iOS开发栈】学习更多SwiftUI、iOS开发相关内容。
文章首发在我的个人技术博客