我有一个具有以下结构的视图控制器((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
( 被限制在导航栏的底部 (2
( 和超级视图的底部 (1
( - (当然,也有必要的水平约束!
UIView (3
( 具有以下约束:
- 对所有子视图的前导约束 0 。
- 所有子视图的尾随约束为 0。
- UIButton的底部空间为24(应添加一些额外的间距( 顶部
- 空间 24 到最顶层的 UIText字段(顶部间距(
- 顶部空间 0 到 superView (UIScrollView(
- 底部空间 0 到 superView (UIScrollView(
- "等宽 - 减去 32"到导航栏(所以 - 固定宽度(
在 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)
}
}
}
但是,当键盘显示时,它不会插入滚动视图(足够(。我调试了,情况是这样的:
- 普通键盘:
height = 216
- 带建议栏的普通键盘:
height = 260
- 带建议栏的iPhone X键盘:
height = 291
我首先认为建议栏可能是问题所在,但事实并非如此。
registerForKeyboardWillShowNotification
年,我将bottom: keyboardSize.height
更改为bottom: keyboardSize.height + 30
,这给出了完全相同的结果(我看到按钮的相同部分部分隐藏在键盘后面(。一旦我添加 50 或更多,它似乎终于产生了一点不同。
- 而不是
keyboardWillShowNotification
我尝试keyboardDidShowNotification
,这没有区别。 - 而不是
keyboardFrameEndUserInfoKey
我尝试keyboardFrameBeginUserInfoKey
,这没有区别。
我在这里错过了什么?
不幸的是,我无法解决这个问题,我不确定为什么这不能按预期工作。
但是,我通过使用UIScrollView中的UIStackView获得了预期的行为。我用这篇文章作为参考。
用户界面布局
- UIView控制器 (1(
- 导航栏 (2(
- UIScrollView (2(
- UIStackView (3(
- 用户界面扩展字段 (4(
- 用户界面扩展字段 (4(
- 用户界面扩展字段 (4(
- 用户界面扩展字段 (4(
- UI布顿 (4(
UIScrollView
- ScrollView 的
leading
和trailing
被限制为16到超级视图。 - ScrollView 的
top
在导航栏底部以0限制。 - ScrollView 的
bottom
被限制为0到超级视图的底部。
UIStackView
- StackView 的
leading
和trailing
在滚动视图中被限制为0。 - StackView 的宽度与滚动视图相等。
- StackView 的
top
和bottom
被限制为24到滚动视图,以获得导航栏以及按钮和键盘之间的所需间距。 - 堆栈视图设置为
axis=vertical
、alignment=fill
、distribution=fill
、spacing=24
。
导航栏
导航栏是一个自定义类,其高度来自其内容。这没有设置高度约束,而是占位符高度 100。导航栏将填满整个屏幕。这可以通过删除占位符高度并添加任何具有低优先级(在本例中为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)
}
}