当视图控制器内部有滚动视图时处理键盘事件
Handling keyboard events when view controller has a scrollview inside
在我的项目中,有一个嵌入在选项卡栏控制器中的视图控制器。这个视图控制器有一个显示抽屉的按钮(滑入视图)。为此,我正在使用 this 第三方库。从现在开始,我将把它称为面板视图控制器。
这个面板视图控制器是一个简单的视图控制器,里面有一个滚动视图。滚动视图中有一个堆栈视图。所有其他子视图(绿色和橙色视图)都通过堆栈视图进行布局。
橙色视图的底部有一个文本字段。我编写了以下代码来处理键盘事件,将文本字段移动到键盘上方并向下移动。
@objc private func didReceiveKeyboardNotification(_ notification: Notification) {
if
let userInfo = notification.userInfo,
let endValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue,
let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double,
let curve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt {
// Transform the keyboard's frame into our view's coordinate system
let endRect = view.convert(endValue.cgRectValue, from: view.window)
// Find out how much the keyboard overlaps the scroll view
// We can do this because our scroll view's frame is already in our view's coordinate system
let keyboardOverlap = scrollView.frame.maxY - endRect.origin.y
// Set the scroll view's content inset to avoid the keyboard
// Don't forget the scroll indicator too!
scrollView.contentInset.bottom = keyboardOverlap
scrollView.verticalScrollIndicatorInsets.bottom = keyboardOverlap
UIView.animate(withDuration: duration, delay: 0, options: UIView.AnimationOptions(rawValue: curve), animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
}
关闭键盘后,视图应向下移回初始位置。问题是滚动视图没有重置到原始位置。如您所见,文本字段最终低于初始位置。
我不知道这里有什么问题。
尝试IQKeyboardManager。我有一个类似的问题,这没有任何代码就解决了,它工作正常。
您的 didReceiveKeyboardNotification
方法存在问题。您正在使用相同的方法来处理 show/hide 键盘,并且在这两种情况下,您都使用 scrollView.contentInset.bottom = keyboardOverlap
因此在键盘隐藏之后您的插入将被设置为 0。这是更正确的方法:
if notification.name == UIResponder.keyboardWillHideNotification {
let inset = tabBarController?.tabBar.frame.size.height as! CGFloat //Tabbar height
scrollView.contentInset.bottom = inset
scrollView.verticalScrollIndicatorInsets.bottom = inset
}
if notification.name == UIResponder.keyboardWillShowNotification {
scrollView.contentInset.bottom = keyboardOverlap
scrollView.verticalScrollIndicatorInsets.bottom = keyboardOverlap
}
在我的项目中,有一个嵌入在选项卡栏控制器中的视图控制器。这个视图控制器有一个显示抽屉的按钮(滑入视图)。为此,我正在使用 this 第三方库。从现在开始,我将把它称为面板视图控制器。
这个面板视图控制器是一个简单的视图控制器,里面有一个滚动视图。滚动视图中有一个堆栈视图。所有其他子视图(绿色和橙色视图)都通过堆栈视图进行布局。
橙色视图的底部有一个文本字段。我编写了以下代码来处理键盘事件,将文本字段移动到键盘上方并向下移动。
@objc private func didReceiveKeyboardNotification(_ notification: Notification) {
if
let userInfo = notification.userInfo,
let endValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue,
let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double,
let curve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt {
// Transform the keyboard's frame into our view's coordinate system
let endRect = view.convert(endValue.cgRectValue, from: view.window)
// Find out how much the keyboard overlaps the scroll view
// We can do this because our scroll view's frame is already in our view's coordinate system
let keyboardOverlap = scrollView.frame.maxY - endRect.origin.y
// Set the scroll view's content inset to avoid the keyboard
// Don't forget the scroll indicator too!
scrollView.contentInset.bottom = keyboardOverlap
scrollView.verticalScrollIndicatorInsets.bottom = keyboardOverlap
UIView.animate(withDuration: duration, delay: 0, options: UIView.AnimationOptions(rawValue: curve), animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
}
关闭键盘后,视图应向下移回初始位置。问题是滚动视图没有重置到原始位置。如您所见,文本字段最终低于初始位置。
我不知道这里有什么问题。
尝试IQKeyboardManager。我有一个类似的问题,这没有任何代码就解决了,它工作正常。
您的 didReceiveKeyboardNotification
方法存在问题。您正在使用相同的方法来处理 show/hide 键盘,并且在这两种情况下,您都使用 scrollView.contentInset.bottom = keyboardOverlap
因此在键盘隐藏之后您的插入将被设置为 0。这是更正确的方法:
if notification.name == UIResponder.keyboardWillHideNotification {
let inset = tabBarController?.tabBar.frame.size.height as! CGFloat //Tabbar height
scrollView.contentInset.bottom = inset
scrollView.verticalScrollIndicatorInsets.bottom = inset
}
if notification.name == UIResponder.keyboardWillShowNotification {
scrollView.contentInset.bottom = keyboardOverlap
scrollView.verticalScrollIndicatorInsets.bottom = keyboardOverlap
}