【问题标题】:TextField moved up when covered by keyboard doesn't stay in position被键盘覆盖时 TextField 向上移动不保持原位
【发布时间】:2020-08-08 13:25:27
【问题描述】:

我正在尝试解决常见问题,以便在 TextField 被键盘覆盖时向上移动。基本上我已经从Moving Content That Is Located Under the Keyboard

关注了苹果的文档

但我没有使用 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 上有 link to whole project

有谁知道为什么这只会在某些类型的 iPhone 屏幕上出现问题?我在这段代码中使用的想法有什么问题吗?

非常感谢您的任何建议或建议,祝大家有美好的一天。

更新:

我发现如果 TextFields 的垂直约束是针对 Superview 而不是针对 Safe Area 设置的,它可以正常工作(也在 iPhone X 及更高版本上)。所以我现在已经相应地更新了project on GitHub。 (我唯一不喜欢的是对 Superview 的垂直约束不是对称的,而且它们在 iPhone SE 和 8 及以下看起来不太正确。)

更新:

现在尝试使用不同的方法使用容器视图底部约束和安全区域差异来计算在 usingConstraints 分支中向上移动的 TextFiled。它适用于所有可能的屏幕类型但不能使用键盘制作动画

ToDo:还是要弄清楚如何根据键盘来动画这个约束变化。

【问题讨论】:

  • 我发现唯一不同的屏幕尺寸是 11Pro,即使是 11Pro Plus 也与 6、7、8、X、XR、11 几乎相同...... .

标签: ios swift keyboard textfield


【解决方案1】:
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()
}

【讨论】:

  • 感谢您的回复。我已经尝试过您的代码,但必须更正 textFieldShouldBeginEditing 函数,它应该返回 -> Bool。我猜你也在考虑行动:#selector(ViewController.keyboardWillHide) 不是 UIViewController。当我尝试它时,它似乎并没有更好地工作。在 iPhone X 及更高版本的键盘上敲击一些字母后,lowerTextFiled 也会跳下,键盘和移位视图之间也有额外的黑色间隙。当 upperTextFiled 处于活动状态时,您的代码正在移动视图,它没有被键盘覆盖,这样它实际上就被移出了视线。
  • 是的 return (activeTextField != nil) for shouldBeginEditing。将 +50 更改为 -50 甚至 view.frame.height /8 或任何合适的数量。
  • TextFields 应该同时移动,除非它们被限制在不同的视图中。将 hideKeyboard() 放在 didEndEditing 中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-22
相关资源
最近更新 更多