ios - 当被键盘覆盖时,TextField 向上移动并没有保持原位
问题描述
我正在尝试解决常见问题,以便在 TextField 被键盘覆盖时向上移动。基本上,我遵循了移动位于键盘下方的内容中的 Apple 文档
但我没有使用 ScrollView,在主视图中只有两个 TextFiled。
当它被键盘覆盖时,下一个会向上移动,并且在 iPhone 8 或 SE 上完美运行(具有锐利的屏幕角,主视图和 SafeArea 相同)。
我在 iPhone X、XS 或 11 上遇到问题(那些带有 Face ID 缺口和圆角屏幕角的设备,其中安全区域和主视图不一样)。
在这些 iPhone 上,TextField 最初向上移动到所需位置,但在触摸键盘后(键入字母后),它会立即向下跳一些像素并再次隐藏在键盘后面。
这是我正在处理的代码:
//
// ViewController.swift
// TextFields
//
// Created by Manoli on 24/04/2020.
// Copyright © 2020 macForce. All rights reserved.
//
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var upperTextField: UITextField!
@IBOutlet weak var lowerTextField: UITextField!
var activeTextField: UITextField?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
upperTextField.delegate = self
lowerTextField.delegate = self
registerForKeyboardNotifications()
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
activeTextField = nil
textField.resignFirstResponder()
return true
}
func textFieldDidBeginEditing(_ textField: UITextField) {
activeTextField = textField
}
func registerForKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc func keyboardWillShow(_ notification: NSNotification) {
let keyboardSpacing: CGFloat = 8.0 // Standard value for spacing between keyboard and textfield
guard let userInfo = notification.userInfo,
let keyboardFrameValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue
else { return }
let keyboardFrame = keyboardFrameValue.cgRectValue
guard let activeTextFieldFrame = activeTextField?.frame else { return }
let positionShift = activeTextFieldFrame.origin.y + activeTextFieldFrame.height - keyboardFrame.origin.y + keyboardSpacing
if positionShift > 0 {
view.frame.origin.y = -positionShift
}
}
@objc func keyboardWillHide(_ notification: NSNotification) {
view.frame.origin.y = 0
}
}
在这里,我有GitHub 上整个项目的链接。
有谁知道为什么这只会在某些类型的 iPhone 屏幕上出现问题?我在这段代码中使用的想法有什么问题吗?
非常感谢任何建议或建议,祝大家有美好的一天。
更新:
我发现如果 TextFields 的垂直约束是针对 Superview 而不是针对 Safe Area 设置的,它可以正常工作(也在 iPhone X 及更高版本上)。所以我现在已经相应地更新了 GitHub 上的项目。(我唯一不喜欢的是对 Superview 的垂直约束不是对称的,它们在 iPhone SE 和 8 及以下看起来不太正确。)
更新:
现在尝试使用容器视图底部约束和安全区域差异的不同方法来计算在usingConstraints分支中向上移动的 TextFiled。它适用于所有可能的屏幕类型,但不能使用键盘进行动画处理。
ToDo:仍然需要弄清楚如何根据键盘对这个约束变化进行动画处理。
解决方案
func textFieldShouldBeginEditing(_ textField: UITextField)
{
activeTextField = textField
}
func showLoginKeyBoard()
{
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
}
@objc func keyboardWillShow(notification: NSNotification)
{
if activeTextField == upperTextField
{
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
{
if self.view.frame.origin.y == 0
{
self.view.frame.origin.y -= keyboardSize.height
}
}
}
if activeTextField == lowerTextField
{
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
{
if self.view.frame.origin.y == 0
{
self.view.frame.origin.y -= keyboardSize.height + 50
}
}
}
}
func hideLoginKeyboard()
{
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
let tap: UITapGestureRecognizer = UITapGestureRecognizer(
target: self,
action: #selector(UIViewController.keyboardWillHide))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
self.view.endEditing(true)
}
@objc func keyboardWillHide(notification: NSNotification)
{
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1), execute:
{
if self.view.frame.origin.y != 0
{
UIView.animate(withDuration: 0.3, delay: 0.0, animations:
{
self.view.frame.origin.y = 0
})
}
})
}
func deregisterFromKeyboardNotifications()
{
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
override func viewDidDisappear(_ animated: Bool)
{
deregisterFromKeyboardNotifications()
}
推荐阅读
- git - 约克托。git命令生成的包版本
- sapui5 - 如何从表格中隐藏“全选”复选框?
- vue.js - 无状态(受控)输入
- c# - C# - 使用用户控件中的 NotifyIcon
- postgresql - pg_dump 与数据库“db_name”的连接失败:致命:用户“postgres”的对等身份验证失败
- spring - 考虑在你的配置中定义一个“net.corda.core.messaging.CordaRPCOps”类型的bean
- gojs - 使用箭头键移动选择时,SelectionMoved 侦听器不起作用
- node.js - 如何覆盖 TextChannel 权限
- javascript - 即使在添加 $(document).ready(function () 之后,javascript 也可以在控制台中工作,但不能在页面上
- c# - 为什么我的应用程序重复某些操作 4 次?