swift 出现键盘时调整屏幕大小

cyvaqqii  于 2023-09-30  发布在  Swift
关注(0)|答案(5)|浏览(137)

我正在开发一个聊天应用。当键盘出现时,我必须移动文本字段。我用下面的代码来做这件事:

func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        if let keyboardSize =  (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            kbHeight = keyboardSize.height
            self.animateTextField(true)
        }
    }
}
func keyboardWillHide(notification: NSNotification) {
    self.animateTextField(false)
}

func animateTextField(up: Bool) {
    var movement = (up ? -kbHeight : kbHeight)

    UIView.animateWithDuration(0.3, animations: {
        self.view.frame = CGRectOffset(self.view.frame, 0, movement)
    })
}

但是当我使用这个代码时,第一条消息不显示。我想我必须调整tableview的大小。
以下是屏幕截图之前之后键盘出现:

我使用自动布局。
如何解决这个问题?

os8fio9y

os8fio9y1#

2023更新

正确使用约束...

只有一种方法可以正确处理iOS中的这种混乱。

1.将下面的KUIViewController粘贴到您的项目中,
1.创建一个非常简单的约束,即“内容的底部”。
1.将该约束拖到bottomConstraintForKeyboard
KUIViewController将自动和正确地调整您的内容视图在任何时候
所有的一切都是自动的。

所有Apple行为都是以标准方式正确处理的,例如按下按钮等。

你已经100%完成了。

那么“你应该调整哪个视图的大小?“

不能使用.view...
因为...你不能在iOS中调整.view的大小!!!
只需创建一个名为“保持器”的UIView。它位于.view内部。

  • 把你所有的东西都放进“保持器”里 *

保持器当然会有四个简单的约束top/bottom/left/right到.view

对“保持器”的底部约束实际上是bottomConstraintForKeyboard

  • 你完了 *

给客人寄账单然后去喝酒。
没什么可做的了

class KUIViewController: UIViewController {

    // KBaseVC is the KEYBOARD variant BaseVC. more on this later

    @IBOutlet var bottomConstraintForKeyboard: NSLayoutConstraint!

    @objc func keyboardWillShow(sender: NSNotification) {
        let i = sender.userInfo!
        let s: TimeInterval = (i[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
        let k = (i[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height
        bottomConstraintForKeyboard.constant = k
        // Note. that is the correct, actual value. Some prefer to use:
        // bottomConstraintForKeyboard.constant = k - bottomLayoutGuide.length
        UIView.animate(withDuration: s) { self.view.layoutIfNeeded() }
    }

    @objc func keyboardWillHide(sender: NSNotification) {
        let info = sender.userInfo!
        let s: TimeInterval = (info[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
        bottomConstraintForKeyboard.constant = 0
        UIView.animate(withDuration: s) { self.view.layoutIfNeeded() }
    }

    @objc func clearKeyboard() {
        view.endEditing(true)
        // (subtle iOS bug/problem in obscure cases: see note below
        // you may prefer to add a short delay here)
    }

    func keyboardNotifications() {
        NotificationCenter.default.addObserver(self,
            selector: #selector(keyboardWillShow),
            name: UIResponder.keyboardWillShowNotification,
            object: nil)
        NotificationCenter.default.addObserver(self,
            selector: #selector(keyboardWillHide),
            name: UIResponder.keyboardWillHideNotification,
            object: nil)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        keyboardNotifications()
        let t = UITapGestureRecognizer(target: self, action: #selector(clearKeyboard))
        view.addGestureRecognizer(t)
        t.cancelsTouchesInView = false
    }
}

很简单

在任何可能出现键盘的位置使用KUIViewController。

class AddCustomer: KUIViewController, SomeProtocol {

class EnterPost: KUIViewController {

class EditPurchase: KUIViewController {

在那些屏幕上,关于键盘,所有的东西现在都是完全自动的。
你完了
呼。

  • 次要脚注-背景点击 * 正确 * 关闭键盘。这包括落在您的“内容”上的点击。这是 * 正确的苹果行为 *。任何不寻常的变化,从这将需要大量的非常反苹果定制编程。
  • 非常小的脚注-所以,屏幕上的任何和所有按钮将工作100%正确的每一次。然而,在嵌套的(!)嵌套(!)滚动视图,并嵌套(!)页面视图容器(!!),你可能会发现一个按钮似乎不起作用。这似乎基本上是一个(模糊!)问题在当前的iOS中。如果你遇到这个令人难以置信的晦涩问题,幸运的是,解决方案很简单。看看函数clearKeyboard(),只需添加一个短延迟,就完成了。
@objc func clearKeyboard() {
    DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
        self.view.endEditing(true)
    }
}

(来自用户@wildcat12 https://stackoverflow.com/a/57698468/294884的一个很好的提示)

kse8i1jr

kse8i1jr2#

可以创建表视图底部自动布局约束的出口。
然后简单地使用这个代码:

func keyboardWillShow(sender: NSNotification) {
    let info = sender.userInfo!
    var keyboardSize = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height
    bottomConstraint.constant = keyboardSize - bottomLayoutGuide.length

    let duration: TimeInterval = (info[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue

    UIView.animate(withDuration: duration) { self.view.layoutIfNeeded() }
}

func keyboardWillHide(sender: NSNotification) {
    let info = sender.userInfo!
    let duration: TimeInterval = (info[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
    bottomConstraint.constant = 0

    UIView.animate(withDuration: duration) { self.view.layoutIfNeeded() }
}

如果创建底部约束时遇到问题:
在故事板中

  • 选择搜索栏。
  • 在右下角,你会看到3个图标。点击中间的一个看起来像|-[]-|
  • 在弹出窗口的顶部,有4个框。在底部输入0。
  • 约束已创建!

现在你可以把它拖到你的视图控制器中,并把它添加为一个插座。
另一种解决方案是设置tableView.contentInset.bottom。但我以前没这么做过。如果你愿意,我可以试着解释。

使用inset:

func keyboardWillShow(sender: NSNotification) {
    let info = sender.userInfo!
    let keyboardSize = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height

    tableView.contentInset.bottom = keyboardSize
}

func keyboardWillHide(sender: NSNotification) {
    tableView.contentInset.bottom = 0
}

您可以尝试使用此代码设置插入。我自己还没有试过,但应该是这样的。
编辑:根据nacho 4d的建议更改了持续时间

1cklez4t

1cklez4t3#

来自@胖子的留言:
一个细节-(不幸的是)点击你的内容也会解雇键盘。(他们都得到了事件。)然而,这几乎总是正确的行为;给予看.没有合理的是要避免这一点,所以忘记它,去与苹果流。
可以通过实现以下UIGestureRecognizerDelegate的方法来解决:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        return !(touch.view?.isKind(of: UIControl.self) ?? true)
    }

这样,如果用户触摸任何UIControl(UIButton、xmlextField等),手势识别器将不会调用clearKeyboard()方法。
要使其工作,请记住在类定义中或使用扩展来子类化UIGestureRecognizerDelegate。然后,在viewDidLoad()中,您应该将手势识别器委托分配为self。
准备复制和粘贴代码:

// 1. Subclass UIGestureRecognizerDelegate
class KUIViewController: UIViewController, UIGestureRecognizerDelegate {

@IBOutlet var bottomConstraintForKeyboard: NSLayoutConstraint!

func keyboardWillShow(sender: NSNotification) {
    let i = sender.userInfo!
    let k = (i[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height
    bottomConstraintForKeyboard.constant = k - bottomLayoutGuide.length
    let s: TimeInterval = (i[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
    UIView.animate(withDuration: s) { self.view.layoutIfNeeded() }
}

func keyboardWillHide(sender: NSNotification) {
    let info = sender.userInfo!
    let s: TimeInterval = (info[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
    bottomConstraintForKeyboard.constant = 0
    UIView.animate(withDuration: s) { self.view.layoutIfNeeded() }
}

func keyboardNotifications() {
    NotificationCenter.default.addObserver(self,
        selector: #selector(keyboardWillShow),
        name: Notification.Name.UIKeyboardWillShow,
        object: nil)
    NotificationCenter.default.addObserver(self,
        selector: #selector(keyboardWillHide),
        name: Notification.Name.UIKeyboardWillHide,
        object: nil)
}

func clearKeyboard() {
    view.endEditing(true)
}

override func viewDidLoad() {
    super.viewDidLoad()
    keyboardNotifications()
    let t = UITapGestureRecognizer(target: self, action: #selector(clearKeyboard))
    view.addGestureRecognizer(t)
    t.cancelsTouchesInView = false

    // 2. Set the gesture recognizer's delegate as self
    t.delegate = self
}

// 3. Implement this method from UIGestureRecognizerDelegate
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    return !(touch.view?.isKind(of: UIControl.self) ?? true)
}
}
jyztefdp

jyztefdp4#

也许它会帮助某人。您可以实现所需的行为而无需使用接口构建器
首先,您需要创建一个约束,并计算安全区域插入,以支持无按钮设备正确

var container: UIView!
var bottomConstraint: NSLayoutConstraint!
let safeInsets = UIApplication.shared.windows[0].safeAreaInsets

然后在代码中初始化它

container = UIView()
bottomConstraint = container.bottomAnchor.constraint(equalTo: view.bottomAnchor)

将其附加到视图并激活

view.addSubview(container)

NSLayoutConstraint.activate([
       ...

       container.leadingAnchor.constraint(equalTo: view.leadingAnchor),
       container.trailingAnchor.constraint(equalTo: view.trailingAnchor),
       container.topAnchor.constraint(equalTo: view.topAnchor),
       bottomConstraint,

       ...
 ])

最后

@objc func keyboardWillShow(notification: NSNotification) {
       if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {

       if bottomConstraint.constant == 0 {
          bottomConstraint.constant = -keyboardSize.height + safeInsets.bottom     
          view.layoutIfNeeded()
       }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
       bottomConstraint.constant = 0
       view.layoutIfNeeded()
}

另外,如果视图是可滚动的,并且您希望使用键盘将其向上移动,并在键盘隐藏时返回到初始位置,则可以更改视图的contentOffset

view.contentOffset = CGPoint(x: view.contentOffset.x, y: view.contentOffset.y + keyboardSize.height - safeInsets.bottom)

用于向上滚动,以及

view.contentOffset = CGPoint(x: view.contentOffset.x, y: view.contentOffset.y - keyboardSize.height + safeInsets.bottom)

把它移下来

bbmckpt7

bbmckpt75#

如果您不想亲自处理这个问题,您可能会发现TPKeyboardAvoiding框架很有用。
只需遵循“安装说明”即可。将适当的.h/.m文件拖放到你的项目中,然后使你的ScrollView / TableView成为一个子类,如下所示:

相关问题