为 keyboardWillShowNotification 设置 UIScrollView 的 contentInset 不能正常工作
Posted
技术标签:
【中文标题】为 keyboardWillShowNotification 设置 UIScrollView 的 contentInset 不能正常工作【英文标题】:Setting UIScrollView's contentInset for keyboardWillShowNotification not working properly 【发布时间】:2019-11-29 10:23:36 【问题描述】:我有一个 ViewController 具有以下结构((x)
表示级别):
UIViewController (1)
- NavigationBar (2)
- UIScrollView (2)
- UIView (3)
- UITextField (4)
- UITextField (4)
- UITextField (4)
- UITextField (4)
- UIButton (4)
4
级别的所有元素在垂直方向上相互限制,间距为 16。
4
级别的第一个和最后一个元素被限制在 UIView 的 (3
) 顶部和底部。
UIView (3
) 的顶部和底部被限制为 UIScrollView (2
)。
UIScrollView (2
) 被限制在 NavigationBar 的底部 (2
) 和 superview 的底部 (1
)
(当然还有必要的水平约束!)
UIView (3
) 有以下约束:
在viewController的viewDidLoad
中,我称之为:
registerForKeyboardWillShowNotification(self.scrollView)
registerForKeyboardWillHideNotification(self.scrollView)
其中registerForKeyboard...ShowNotification
是UIViewController
的扩展:
extension UIViewController
/// Act when keyboard is shown, by adding contentInsets to the scrollView.
func registerForKeyboardWillShowNotification(_ scrollView: UIScrollView, usingBlock block: ((CGSize?) -> Void)? = nil)
_ = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification,
object: nil, queue: nil)
notification in
let userInfo = notification.userInfo!
let keyboardSize = (userInfo[UIResponder.keyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue.size
let contentInsets = UIEdgeInsets(top: scrollView.contentInset.top,
left: scrollView.contentInset.left,
bottom: keyboardSize.height,
right: scrollView.contentInset.right)
scrollView.contentInset = contentInsets
block?(keyboardSize)
/// Act when keyboard is hidden, by removing contentInsets from the scrollView.
func registerForKeyboardWillHideNotification(_ scrollView: UIScrollView, usingBlock block: ((CGSize?) -> Void)? = nil)
_ = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification,
object: nil, queue: nil)
notification in
let userInfo = notification.userInfo!
let keyboardSize = (userInfo[UIResponder.keyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue.size
let contentInsets = UIEdgeInsets(top: scrollView.contentInset.top,
left: scrollView.contentInset.left,
bottom: 0,
right: scrollView.contentInset.right)
scrollView.contentInset = contentInsets
block?(keyboardSize)
但是,当键盘显示时,它并没有插入 scrollView(够了)。我调试了一下,是这样的:
普通键盘:height = 216
带建议栏的常规键盘:height = 260
带建议栏的 iPhone X 键盘:height = 291
我首先虽然建议栏可能是问题,但事实并非如此。
在registerForKeyboardWillShowNotification
中,我将bottom: keyboardSize.height
更改为bottom: keyboardSize.height + 30
,结果完全相同(我看到按钮的相同部分部分隐藏在键盘后面)。一旦我添加了 50 个或更多,它最终似乎会产生微小的差异。
keyboardDidShowNotification
而不是keyboardWillShowNotification
,但这并没有什么不同。
我尝试了keyboardFrameBeginUserInfoKey
而不是keyboardFrameEndUserInfoKey
,但这并没有什么不同。
我在这里错过了什么?
【问题讨论】:
你的 UIView 约束是什么? 我编辑了问题并添加了 UIView 约束。 UIView 的高度呢? 这是从它的内容(TextFields / Button)派生的。因为它对那些有 24 的顶部和底部约束。 首先解决约束错误,我认为这是主要问题 【参考方案1】:很遗憾,我无法解决这个问题,我不确定为什么它不能按预期工作。
但是,通过在 UIScrollView 中使用 UIStackView,我得到了预期的行为。我使用this article 作为参考。
界面布局
UIViewController (1) 导航栏 (2) UIScrollView (2) UIStackView (3) UITextField (4) UITextField (4) UITextField (4) UITextField (4) UIButton (4)UIScrollView
leading
和trailing
被16 约束到superView。
ScrollView 的 top
被 0 限制在导航栏的底部。
ScrollView 的 bottom
被 0 约束到 superView 的底部。
UIStackView
leading
和 trailing
被 0 约束到滚动视图。
StackView 的宽度与 scrollView 相同。
StackView 的 top
和 bottom
被 24 约束到滚动视图,以获得所需的导航栏间距以及按钮和键盘之间的间距。
StackView 设置为axis=vertical
、alignment=fill
、distribution=fill
、spacing=24
。
导航栏
NavigationBar 是一个自定义类,它从其内容派生其高度。这没有设置高度约束,但占位符高度为 100。NavigationBar 将填满整个屏幕。这可以通过删除占位符高度并添加 any 低优先级的高度约束(在本例中为1
)来解决。
应用键盘插入的初始代码现在可以工作了。
/// Act when keyboard is shown, by adding contentInsets to the scrollView.
func registerForKeyboardWillShowNotification(_ scrollView: UIScrollView, usingBlock block: ((CGSize?) -> Void)? = nil)
_ = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification,
object: nil, queue: nil)
notification in
let userInfo = notification.userInfo!
let keyboardSize = (userInfo[UIResponder.keyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue.size
let contentInsets = UIEdgeInsets(top: scrollView.contentInset.top,
left: scrollView.contentInset.left,
bottom: keyboardSize.height,
right: scrollView.contentInset.right)
scrollView.contentInset = contentInsets
block?(keyboardSize)
【讨论】:
以上是关于为 keyboardWillShowNotification 设置 UIScrollView 的 contentInset 不能正常工作的主要内容,如果未能解决你的问题,请参考以下文章
为啥每次选择另一个 TextField 时都会调用 KeyboardWillShowNotification?
KeyboardWillShowNotification 不适用于 iOS > 6.1
将 A 转换为 1 B 转换为 2 ... Z 转换为 26,然后将 AA 转换为 27 AB 转换为 28(Excel 中列引用的列索引)