如何解决为什么在 iOS14或至少 iOS14.4中,keyboardWillShowNotification 被触发两次,而在 iOS13 中只触发一次?
为什么在 iOS14(或至少 iOS14.4 iPhone 12 模拟器)中,keyboardWillShowNotification 被触发两次,而在 iOS13 中只触发一次?
我的最终目标是使键盘隐藏的可见文本字段。
如果我按照以下步骤操作,这会使我的表单在 iOS14 上行为不端:
请注意,视图向上滚动到上一个点击的文本字段(在本例中是最顶部的)。
用户界面:
代码:
class ViewController: UIViewController {
@IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
register()
}
override func viewWilldisappear(_ animated: Bool) {
super.viewWilldisappear(animated)
unregister()
}
func register() {
NotificationCenter.default.addobserver(self,selector: #selector(keyboardWillShow(notification:)),name: UIResponder.keyboardWillShowNotification,object: nil)
NotificationCenter.default.addobserver(self,selector: #selector(keyboardWillHide(notification:)),name: UIResponder.keyboardWillHideNotification,object: nil)
}
func unregister() {
NotificationCenter.default.removeObserver(self,object: nil)
NotificationCenter.default.removeObserver(self,object: nil)
}
@objc func keyboardWillShow(notification: NSNotification) {
let keyboardFrame = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)
let keyboardSize = keyboardFrame?.size
print("keyboardWillShow " + String(describing: keyboardSize))
let contentInsets = UIEdgeInsets(top: 0.0,left: 0.0,bottom: keyboardSize!.height,right: 0.0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
}
@objc func keyboardWillHide(notification: NSNotification) {
print("keyboardWillHide")
let contentInsets = UIEdgeInsets(top: 0.0,bottom: 0.0,right: 0.0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
}
}
输出:
keyboardWillShow Optional((390.0,336.0))
keyboardWillShow Optional((390.0,336.0))
输出 2 和 3 是当我点击底部的文本字段时。在这 2 个中,第一个对应于最顶部的文本字段,第二个对应于底部的文本字段。
并且滚动会自动滚动到最顶部的文本字段,而不是根本不滚动,因为用户点击了底部的文本字段。
解决方法
iOS 14 中似乎存在一个(或两个)错误(我正在 14.3 上进行测试)。
试试这个例子 - 它添加了一个全尺寸滚动视图,其中包含一个垂直堆栈视图,其中 8 个文本字段间隔 75 磅:
class KeyBoardTestViewController: UIViewController {
let scrollView = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
let stack = UIStackView()
stack.axis = .vertical
stack.spacing = 75
scrollView.translatesAutoresizingMaskIntoConstraints = false
stack.translatesAutoresizingMaskIntoConstraints = false
let safeG = view.safeAreaLayoutGuide
let contentG = scrollView.contentLayoutGuide
scrollView.addSubview(stack)
view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: safeG.topAnchor),scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor),scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor),scrollView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor),stack.topAnchor.constraint(equalTo: contentG.topAnchor,constant: 20.0),stack.leadingAnchor.constraint(equalTo: contentG.leadingAnchor,stack.trailingAnchor.constraint(equalTo: contentG.trailingAnchor,stack.bottomAnchor.constraint(equalTo: contentG.bottomAnchor,constant: -20.0),stack.widthAnchor.constraint(equalToConstant: 200.0),])
for i in 1...8 {
let tf = UITextField()
tf.borderStyle = .roundedRect
tf.text = "\(i)"
stack.addArrangedSubview(tf)
}
}
}
请注意没有键盘显示/隐藏处理。
当你运行它时,点击顶部的文本字段(里面有一个“1”)。键盘将显示。
现在,无需输入任何内容,向下滚动...因为我们没有调整滚动视图的内容插入,您将只能向下滚动到第 5 个或第 6 个文本字段。
点击最低的可见文本字段 --- 滚动视图将滚动,因此顶部的文本字段再次可见,而“文本字段 5”仍然是第一响应者。
如果您滚动/点击/滚动/点击...键盘将保持可见,但上一个第一响应者文本字段将滚动到视图中。
但是,只要您在字段中输入任何内容,一切都会恢复正常。
现在,我们将使用相同的类,但我们将添加键盘通知处理:
class KeyBoardTestViewController: UIViewController {
let scrollView = UIScrollView()
var firstTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let stack = UIStackView()
stack.axis = .vertical
stack.spacing = 75
scrollView.translatesAutoresizingMaskIntoConstraints = false
stack.translatesAutoresizingMaskIntoConstraints = false
let safeG = view.safeAreaLayoutGuide
let contentG = scrollView.contentLayoutGuide
scrollView.addSubview(stack)
view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: safeG.topAnchor),])
for i in 1...8 {
let tf = UITextField()
tf.borderStyle = .roundedRect
tf.text = "\(i)"
stack.addArrangedSubview(tf)
if i == 1 {
firstTextField = tf
}
}
register()
}
func register() {
NotificationCenter.default.addObserver(self,selector: #selector(keyboardWillShow(notification:)),name: UIResponder.keyboardWillShowNotification,object: nil)
NotificationCenter.default.addObserver(self,selector: #selector(keyboardWillHide(notification:)),name: UIResponder.keyboardWillHideNotification,object: nil)
}
@objc func keyboardWillShow(notification: NSNotification) {
let keyboardFrame = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)
let keyboardSize = keyboardFrame?.size
print("keyboardWillShow " + String(describing: keyboardSize))
// only change scroll view insets if .bottom != keyboard height
if scrollView.contentInset.bottom != keyboardSize?.height {
print("setting insets")
let contentInsets = UIEdgeInsets(top: 0.0,left: 0.0,bottom: keyboardSize!.height,right: 0.0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
}
}
@objc func keyboardWillHide(notification: NSNotification) {
print("keyboardWillHide")
let contentInsets = UIEdgeInsets(top: 0.0,bottom: 0.0,right: 0.0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
}
}
我们会看到相同的(错误的)行为......我们会看到“double will show”通知被触发。我添加了一个 if
子句,所以我们只在键盘框架发生变化时才更改内容插入,因此我们排除了罪魁祸首。
同样,只要我们在任何文本字段中输入一个字符,预期行为就会恢复正常——AND 我们不再收到“double will show”通知。
不幸的是,在尝试了几种不同的方法来强制之后,我还没有找到解决方法:(
,好的,谢谢大家的关注。
为了尽量减少这种行为,我们解决的是设置滚动视图以在拖动时关闭 KB。这会将“双重呼叫”移动到键盘隐藏而不是显示时。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。