键盘出现时调整屏幕大小

时间:2015-06-07 08:58:48

标签: ios swift autolayout

我正在构建一个聊天应用。键盘出现时我必须移动文本字段。我使用以下代码执行此操作:

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的大小。

以下是屏幕截图之前之后

http://imgim.com/iossimulatorscreenshot7haz2015114958.png http://imgim.com/iossimulatorscreenshot7haz2015115000.png

我正在使用自动布局。

如何解决此问题?

5 个答案:

答案 0 :(得分:15)

您可以创建表格视图底部自动布局约束的插座。

然后只需使用此代码:

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
}

您可以尝试使用此代码设置插图。我自己还没试过,但它应该是那样的。

编辑:根据nacho4d

的建议更改持续时间

答案 1 :(得分:11)

2017

基于Eendje的概念.........

1)将KUIViewController复制并粘贴到您的项目中,

2)创建约束 - 它只是您内容的“底部约束”

3)不要忘记简单地将约束ID拖到bottomConstraintForKeyboard

那么“你应该调整哪个视图?”

注意,您可以使用.view - 视图控制器的主视图 - 遗憾的是,您无法在iOS中调整.view的大小!

因此,只需将UIView命名为“holder”。

它位于.view内。

将你的一切都放在持有人手中。

持有人当然会对.view上下/左/右四个简单约束。

这里的“持有人”的底部约束确实是bottomConstraintForKeyboard

(当然,通常情况下,当kayboard到达时,你想要“一切”压扁。在不寻常的情况下,你可能更喜欢让其他特定的东西向上移动,剩下的就是其余的。如果你想这样做,在使用KUIViewController方法时你有足够的灵活性。你可以将约束附加到你想要的任何东西。当然,几乎总是它只是“整个屏幕” - 因此只是有一个包含所有东西的“持有者”,并附加那个。)

问题2 ...单击“背景”清除键盘

通常在现代用户体验中,如果你点击“背景”(所以:远离任何按钮,输入字段等),它应该关闭键盘。

KUIViewController完全自动化了这种需求。你什么都不做,这是自动的。

class KUIViewController: UIViewController {

    @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
    }
}

你可以

...在键盘可能出现的任何地方使用KUIViewController。

class AddCustomer: KUIViewController, SomeProtocol {

class CustomerPicker: KUIViewController {

在这些屏幕上:

  1. 当键盘在那里时,页面(您的。holder视图)会自动调整大小以允许键盘。它会很好地制作动画。

  2. 当用户点击“关闭”(点击“背景”)时,它会关闭键盘。

  3. 详细信息 - (不幸的是)点击您的内容也会关闭键盘。 (他们都得到了这个活动。)然而:确实,这几乎总是正常的Apple风格的正确行为:试一试。没有简单的方法可以避免这种情况。请务必阅读@iPruch答案以获取示例。

答案 2 :(得分:2)

来自@Fattie的消息:

  

详细信息 - (不幸的是)点击您的内容也会关闭键盘。 (他们都得到了这个事件。)然而,这几乎总是正确的行为;试试看。没有理由避免这种情况,所以不要理会它并使用Apple-flow。

这可以通过实施以下 UIGestureRecognizerDelegate 的方法来解决:

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

这样,如果用户触摸任何UIControl(UIButton,UITextField等),手势识别器将不会调用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)
}
}

答案 3 :(得分:1)

如果您不想自己与之抗争,可能会发现TPKeyboardAvoiding框架很有用

只需按照“安装说明”进行操作即可。即将适当的.h / .m文件拖放到项目中,然后让ScrollView / TableView成为如下的子类:

Custom Class

答案 4 :(得分:1)

也许会帮助别人。 您完全可以完全不用界面构建器来实现所需的行为

首先,您将需要创建约束并计算安全区域插入量,以正确支持无按钮设备

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)

将其下移