使用Swift使用键盘移动视图

Ale*_*ole 257 uikit uikeyboard nsnotificationcenter ios swift

我有一个应用程序,在视图的下半部分有一个文本字段.这意味着当我输入文本字段时键盘覆盖文本字段.

如何在打字时向上移动视图以便我可以看到我正在键入的内容,然后在键盘消失时将其移回原来的位置?

我到处都看,但所有解决方案似乎都在Obj-C中,我还没有完全转换.

任何帮助将不胜感激.

Bor*_*ris 671

这是一个解决方案,无需处理从一个textField到另一个textField的切换:

 override func viewDidLoad() {
        super.viewDidLoad()
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)            
    }   

func keyboardWillShow(notification: NSNotification) {            
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y -= keyboardSize.height
    }            
}

func keyboardWillHide(notification: NSNotification) {
    self.view.frame.origin.y = 0
}
Run Code Online (Sandbox Code Playgroud)

要解决此问题,请keyboardWillShow/Hide使用以下代码替换这两个函数:

func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        if view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

func keyboardWillHide(notification: NSNotification) {
    if view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑SWIFT 3.0:

override func viewDidLoad() {
    super.viewDidLoad()            
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)    
}

@objc func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑SWIFT 4.0:

override func viewDidLoad() {
    super.viewDidLoad()            
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)    
}

@objc func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑SWIFT 4.2:

override func viewDidLoad() {
    super.viewDidLoad()            
    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) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果用户在键盘存在时触摸另一个文本字段,则视图将被进一步向上推动,这会导致黑色区域(键盘的大小) - 我们需要通过使用跟踪键盘是否存在的变量来修复它.例如,如果keyboardPresent == true则不要移动视图原点等 (50认同)
  • 获取键盘大小时,需要使用`UIKeyboardFrameEndUserInfoKey`而不是'UIKeyboardFrameBeginUserInfoKey`.我不知道为什么目前,但前者会产生更一致的结果. (31认同)
  • 只有一个建议,所以你不必像我那样调试很多.如果您在同一屏幕上有多个uitextfields,键盘大小可能会有所不同(根据您的设置,它不显示某些输入的建议),因此建议每次都设置self.view.frame.origin.y = 0你解雇了键盘.例如,它会显示您的电子邮件文本字段的内容,因此键盘大小会增加,并且它不会显示密码字段的建议,因此键盘大小会减少. (10认同)
  • @Matthew Lin使用布尔值,所以函数keyboardWillShow和hide只能工作一次 (3认同)
  • 请用`UIKeyboardFrameEndUserInfoKey`替换`UIKeyboardFrameBeginUserInfoKey`.第一个给出键盘的起始帧,有时为零,而第二个给出键盘的结束帧. (3认同)
  • 你如何处理多个 textFields?例如,如果您只想在一个 textField 上执行此操作? (2认同)
  • 此代码再次被基于陷阱的设备破坏:( (2认同)
  • 我所做的唯一修改是更改“ keyboardWillHide”中的代码,其中原点与此self.view.frame.origin.y = 0关联 (2认同)
  • 为什么要这么难?我想要做的就是在键盘出现时将我的应用程序向上移动。stackoverflow 上有一百万个不同的答案,而且所有这些答案似乎都有无法正常工作的边缘情况。 (2认同)
  • 如果我们在视图的上半部分也有一些文本字段怎么办 我知道只有当文本字段在视图的下半部分时此解决方案才有效 我想知道如果我们在视图中有一个从上到下的文本字段列表会怎样 (2认同)

gam*_*ill 81

最简单的方法,甚至不需要任何代码:

  1. 如果您还没有使用Spring动画框架,请下载KeyboardLayoutConstraint.swift并将文件添加(拖放)到您的项目中.
  2. 在故事板中,为视图或文本字段创建底部约束,选择约束(双击它),然后在Identity Inspector中,将其类从NSLayoutConstraint更改为KeyboardLayoutConstraint.
  3. 完成!

该对象将与键盘同步自动向上移动.

  • 要选择底部约束,您还可以转到Size Inspector,然后双击列表中的约束 - http://www.raywenderlich.com/wp-content/uploads/2015/09/043_constraints-232x500.png (4认同)
  • 这是最佳解决方案,所提供的代码不会硬编码任何值,例如动画的长度或曲线,或键盘的大小.这也很容易理解. (4认同)
  • 这对我来说非常完美.它实际上是一个两步过程.1.添加KeyboardLayoutConstraint.swift,2.在故事板中,为视图或文本字段创建底部约束.注意:我删除了约束并在视图或文本字段的底部添加了一个约束,并将其类从NSLayoutConstraint更改为KeyboardLayoutConstraint.然后上面的任何视图/文本字段等我只是通过单个KeyboardLayoutConstraint将该项目的约束连接到项目,结果是当键盘出现/消失时,视图中的所有项目都向上/向下移动 (3认同)
  • 这对我有用,但是在键盘顶部和scrollView底部之间有50px的额外空间。我想知道是否是由于我使用的安全区域底部限制。有人碰到这个吗? (3认同)

Dan*_*ieu 67

此线程上的一个流行答案使用以下代码:

func keyboardWillShow(sender: NSNotification) {
    self.view.frame.origin.y -= 150
}
func keyboardWillHide(sender: NSNotification) {
    self.view.frame.origin.y += 150
}
Run Code Online (Sandbox Code Playgroud)

将静态量偏移视图存在明显问题.它在一台设备上看起来不错,但在任何其他尺寸配置上看起来都很糟糕.您需要获得键盘高度并将其用作偏移值.

这是一个适用于所有设备的解决方案,可以处理用户在键入时隐藏预测文本字段的边缘情况.

需要注意的是,我们将self.view.window作为对象参数传递.这将为我们提供键盘数据,例如它的高度!

@IBOutlet weak var messageField: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: self.view.window)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: self.view.window)
}

func keyboardWillHide(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!
    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    self.view.frame.origin.y += keyboardSize.height
}
Run Code Online (Sandbox Code Playgroud)

我们将使它在所有设备上看起来都很漂亮,并处理用户添加或删除预测文本字段的情况.

func keyboardWillShow(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!
    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    let offset: CGSize = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue.size

    if keyboardSize.height == offset.height {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y -= keyboardSize.height
        })
    } else {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y += keyboardSize.height - offset.height
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

删除观察员

在离开视图之前不要忘记删除观察者,以防止传输不必要的消息.

override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: self.view.window)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: self.view.window)
}
Run Code Online (Sandbox Code Playgroud)

根据评论中的问题进行更新:

如果您有两个或更多文本字段,则可以检查view.frame.origin.y是否为零.

func keyboardWillShow(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!

    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    let offset: CGSize = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue.size

    if keyboardSize.height == offset.height {
        if self.view.frame.origin.y == 0 {
            UIView.animateWithDuration(0.1, animations: { () -> Void in
                self.view.frame.origin.y -= keyboardSize.height
            })
        }
    } else {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y += keyboardSize.height - offset.height
        })
    }
     print(self.view.frame.origin.y)
}
Run Code Online (Sandbox Code Playgroud)


use*_*173 29

将其添加到viewcontroller.奇迹般有效.只需调整值即可.

override func viewDidLoad() {
    super.viewDidLoad()        
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name:NSNotification.Name.UIKeyboardWillShow, object: nil);
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name:NSNotification.Name.UIKeyboardWillHide, object: nil);
}

@objc func keyboardWillShow(sender: NSNotification) {
    self.view.frame.origin.y -= 150
}
@objc func keyboardWillHide(sender: NSNotification) {
    self.view.frame.origin.y += 150
}
Run Code Online (Sandbox Code Playgroud)

  • 不要这样做!你不能认为键盘是一定的尺寸. (4认同)
  • 它可能不适用于"自动布局",因此请考虑将其停用. (2认同)
  • 应该使用keyboardSize.当您在设备上有附件视图和不同的键盘高度时会发生什么?分离键盘? (2认同)

小智 23

我改进了一个答案,使其可以在一个页面上使用不同的键盘和不同的textview /字段:

添加观察员:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

func keyboardWillHide() {
    self.view.frame.origin.y = 0
}

func keyboardWillChange(notification: NSNotification) {

    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if YOURTEXTVIEW.isFirstResponder {
            self.view.frame.origin.y = -keyboardSize.height
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

删除观察员:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案比接受的答案效果更好.接受的答案显示键盘只有一次对我来说是一个bug :) (2认同)

Sai*_*daf 21

斯威夫特 5.0:

经过 4-5 个小时的战斗,我得到了一个简单的 UIViewController 扩展,它的代码很简单,就像魅力一样

* 当 TextField 位于键盘上方时,视图不应移动

*无需为 NSLayoutConstraint 设置常量值

*无需第三方库

*无需动画代码

* 也适用于 tableview

*这适用于自动布局/自动调整大小

extension UIViewController {
    func addKeyboardObserver() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardNotifications(notification:)),
                                               name: UIResponder.keyboardWillChangeFrameNotification,
                                               object: nil)
    }

    func removeKeyboardObserver(){
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    }

    // This method will notify when keyboard appears/ dissapears
    @objc func keyboardNotifications(notification: NSNotification) {

        var txtFieldY : CGFloat = 0.0  //Using this we will calculate the selected textFields Y Position
        let spaceBetweenTxtFieldAndKeyboard : CGFloat = 5.0 //Specify the space between textfield and keyboard


        var frame = CGRect(x: 0, y: 0, width: 0, height: 0)
        if let activeTextField = UIResponder.currentFirst() as? UITextField ?? UIResponder.currentFirst() as? UITextView {
            // Here we will get accurate frame of textField which is selected if there are multiple textfields
            frame = self.view.convert(activeTextField.frame, from:activeTextField.superview)
            txtFieldY = frame.origin.y + frame.size.height
        }

        if let userInfo = notification.userInfo {
            // here we will get frame of keyBoard (i.e. x, y, width, height)
            let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
            let keyBoardFrameY = keyBoardFrame!.origin.y
            let keyBoardFrameHeight = keyBoardFrame!.size.height

            var viewOriginY: CGFloat = 0.0
            //Check keyboards Y position and according to that move view up and down
            if keyBoardFrameY >= UIScreen.main.bounds.size.height {
                viewOriginY = 0.0
            } else {
                // if textfields y is greater than keyboards y then only move View to up
                if txtFieldY >= keyBoardFrameY {

                    viewOriginY = (txtFieldY - keyBoardFrameY) + spaceBetweenTxtFieldAndKeyboard

                    //This condition is just to check viewOriginY should not be greator than keyboard height
                    // if its more than keyboard height then there will be black space on the top of keyboard.
                    if viewOriginY > keyBoardFrameHeight { viewOriginY = keyBoardFrameHeight }
                }
            }

            //set the Y position of view
            self.view.frame.origin.y = -viewOriginY
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

添加 UIResponder 的这个扩展来获取选择了哪个 TextField

extension UIResponder {

    static weak var responder: UIResponder?

    static func currentFirst() -> UIResponder? {
        responder = nil
        UIApplication.shared.sendAction(#selector(trap), to: nil, from: nil, for: nil)
        return responder
    }

    @objc private func trap() {
        UIResponder.responder = self
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在您的任何 ViewController 中使用它

   override func viewWillAppear(_ animated: Bool) {
        self.addKeyboardObserver()
    }

    override func viewWillDisappear(_ animated: Bool) {
        self.removeKeyboardObserver()
    }
Run Code Online (Sandbox Code Playgroud)
  • 注册此通知 func viewWillAppear(_ animated: Bool)

  • 注销此通知 func viewWillDisappear(_ animated:Bool)

    在此处下载演示


Ali*_*RAL 15

对于黑屏错误 (Swift 4和4.2).

我修复了黑屏问题.在经过验证的解决方案中,点击后键盘高度会发生变化,这会导致黑屏.

必须使用UIKeyboardFrameEndUserInfoKey而不是UIKeyboardFrameBeginUserInfoKey

var isKeyboardAppear = false

override func viewDidLoad() {
    super.viewDidLoad() 
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

@objc func keyboardWillShow(notification: NSNotification) {
    if !isKeyboardAppear {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            if self.view.frame.origin.y == 0{
                self.view.frame.origin.y -= keyboardSize.height
            }
        }
        isKeyboardAppear = true
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if isKeyboardAppear {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            if self.view.frame.origin.y != 0{
                self.view.frame.origin.y += keyboardSize.height
            }
        }
         isKeyboardAppear = false
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这不会修复 iPhone X 和更新版本上键盘所在的黑色区域。每次键盘出现和消失时,主视图都会向下滑动。 (2认同)

Amr*_*fie 12

我看到所有答案都是通过键盘高度的值来移动视图本身.好吧,我有一个精心设计的答案,如果您正在使用约束,即autolayout通过将约束值(例如底部或顶部约束)更改为预定义值来移动视图,或者您可以使用键盘大小值,则可能非常有用.

在此示例中,我使用从文本字段到底部布局视图的底部约束,初始值为175.

@IBOutlet weak var bottomConstraint: NSLayoutConstraint!

override func viewDidLoad() {
    super.viewDidLoad()        
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil);
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil);
}

func keyboardWillShow(notification: NSNotification) {
    //To retrieve keyboard size, uncomment following line
    //let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
    bottomConstraint.constant = 260
    UIView.animateWithDuration(0.3) {
        self.view.layoutIfNeeded()
    }
}

func keyboardWillHide(notification: NSNotification) {
    //To retrieve keyboard size, uncomment following line
    //let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
    bottomConstraint.constant = 175
    UIView.animateWithDuration(0.3) {
        self.view.layoutIfNeeded()
    }
}
Run Code Online (Sandbox Code Playgroud)


Iva*_*and 9

我们定义KeyboardWillHideNotification的方式发生了一些变化.

此解决方案适用于Swift 4.2:

NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)


@objc func keyboardWillShow(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        self.view.frame.origin.y -= keyboardSize.height
    }
}

@objc func keyboardWillHide(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        self.view.frame.origin.y += keyboardSize.height
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果我的textField位于视图顶部,该怎么办?我的意思是如果有原点Y = 0的文本字段。然后textField上升了,我看不到它 (2认同)

wee*_*gee 8

不是广告,促销或垃圾邮件,而是一个好的解决方案。我知道这个问题有将近30个答案,我非常震惊,以至于没有人提到过这个美丽的GitHub项目,它可以为您做得更好,甚至做得更好。所有的答案只是将视图向上移动。我刚刚使用此IQKeyboardManager解决了所有问题。它拥有13000多颗星。
如果使用swift,只需将其添加到您的podfile中

pod 'IQKeyboardManagerSwift'
Run Code Online (Sandbox Code Playgroud)

然后在您的AppDelegate.swift中执行 import IQKeyboardManagerSwift

import IQKeyboardManagerSwift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

      IQKeyboardManager.shared.enable = true // just add this line

      return true
    }
}
Run Code Online (Sandbox Code Playgroud)

添加该行IQKeyboardManager.shared.enable = true以启用它。
如果要进行生产,则必须使用此解决方案。

  • 非常感谢您指出这个精彩的图书馆。这个库最终是苹果从未提供解决方案的所有与键盘相关的废话的最终答案。现在我将在我的所有项目中使用它,无论是新的还是旧的,并节省时间和头痛,这个键盘出现,消失或不消失,或者如何隐藏它,以及为什么它重叠,自从那天我正在为 iPhone 编程。 (3认同)
  • 这个答案需要更高,更高。 (3认同)
  • 这在使用多个编辑文本时非常有效,这节省了我的时间 (2认同)

Pav*_*vic 6

对于Swift 3,我创建了一个UIViewController子类,因为我需要在所有View Controller中保持常量行为.

class SomeClassVC: UIViewController {

  //MARK: - Lifecycle
  override func viewDidLoad() {
    super.viewDidLoad()

    addKeyboardObservers()
  }

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    removeKeyboardObservers()
  }

  //MARK: - Overrides
  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    view.endEditing(true)
  }

  //MARK: - Help
  func addKeyboardObservers() {
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
  }

  func removeKeyboardObservers() {
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: self.view.window)
  }

  func keyboardWillShow(notification: NSNotification) {
    let keyboardHeight = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.height
    UIView.animate(withDuration: 0.1, animations: { () -> Void in
      self.view.window?.frame.origin.y = -1 * keyboardHeight!
      self.view.layoutIfNeeded()
    })
  }

  func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.1, animations: { () -> Void in
      self.view.window?.frame.origin.y = 0
      self.view.layoutIfNeeded()
    })
  }

  func resignTextFieldFirstResponders() {
    for textField in self.view.subviews where textField is UITextField {
      textField.resignFirstResponder()
    }
  }

  func resignAllFirstResponders() {
      view.endEditing(true)
  }
}
Run Code Online (Sandbox Code Playgroud)


Que*_*n N 6

经过验证的答案没有考虑到文本字段的位置,并且存在一些错误(双位移,永远不会回到主要位置,即使texfield位于视图顶部也位移...)

这个想法是:

  • 获取焦点TextField的绝对Y位置
  • 获取键盘高度
  • 获得ScreenHeight
  • 然后计算键盘位置和文本字段之间的距离(如果<0->向上移动视图)
  • 使用UIView.transform代替UIView.frame.origin.y-= ..,因为使用UIView.transform = .identity可以更轻松地返回到原始位置

那么我们将能够仅在必要时移动视图,并在特定位置移动视图以使聚焦的texField恰好位于键盘上方

这是代码:

斯威夫特4

class ViewController: UIViewController, UITextFieldDelegate {

var textFieldRealYPosition: CGFloat = 0.0

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(VehiculeViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(VehiculeViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)

  // Delegate all textfields

}


@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        let distanceBetweenTextfielAndKeyboard = self.view.frame.height - textFieldRealYPosition - keyboardSize.height
        if distanceBetweenTextfielAndKeyboard < 0 {
            UIView.animate(withDuration: 0.4) {
                self.view.transform = CGAffineTransform(translationX: 0.0, y: distanceBetweenTextfielAndKeyboard)
            }
        }
    }
}


@objc func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.4) {
        self.view.transform = .identity
    }
}


func textFieldDidBeginEditing(_ textField: UITextField) {
  textFieldRealYPosition = textField.frame.origin.y + textField.frame.height
  //take in account all superviews from textfield and potential contentOffset if you are using tableview to calculate the real position
}
Run Code Online (Sandbox Code Playgroud)

}


Ant*_*tzi 6

所以其他答案似乎都没有正确。

iOS 上的良好行为键盘应该:

  • 当键盘改变大小时自动调整大小(是的,它可以)
  • 以与键盘相同的速度制作动画
  • 使用与键盘相同的曲线制作动画
  • 如果相关,请尊重安全区域。
  • 也适用于 iPad/Undocked 模式

我的代码使用NSLayoutConstraint声明为@IBOutlet

@IBOutlet private var bottomLayoutConstraint: NSLayoutConstraint!
Run Code Online (Sandbox Code Playgroud)

您还可以使用变换、视图偏移,.... 我认为使用约束更容易。它通过在底部设置约束来工作,如果您的常量不是 0/不在底部,您可能需要更改代码。

这是代码:

// In ViewDidLoad
    NotificationCenter.default.addObserver(self, selector: #selector(?MyViewController.keyboardDidChange), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)


@objc func keyboardDidChange(notification: Notification) {
    let userInfo = notification.userInfo! as [AnyHashable: Any]
    let endFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
    let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber
    let animationCurve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as! NSNumber
    bottomLayoutConstraint.constant = view.frame.height - endFrame.origin.y - view.safeAreaInsets.bottom // If your constraint is not defined as a safeArea constraint you might want to skip the last part.
    // Prevents iPad undocked keyboard.
    guard endFrame.height != 0, view.frame.height == endFrame.height + endFrame.origin.y else {
        bottomLayoutConstraint.constant = 0
        return
    }
    UIView.setAnimationCurve(UIView.AnimationCurve(rawValue: animationCurve.intValue)!)
    UIView.animate(withDuration: animationDuration.doubleValue) {
        self.view.layoutIfNeeded()
        // Do additional tasks such as scrolling in a UICollectionView
    }
}
Run Code Online (Sandbox Code Playgroud)


Gra*_*ark 5

我注意到其他答案涉及从视图中删除一些顶部.如果你想简单地调整视图大小而不删除任何内容,只需尝试这种方法:)

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.setTranslatesAutoresizingMaskIntoConstraints(true)
        self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.height - keyboardSize.height)
    }
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.collectionView.setTranslatesAutoresizingMaskIntoConstraints(false)
        self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.height + keyboardSize.height)
    }
}
Run Code Online (Sandbox Code Playgroud)


ing*_*nti 5

我给初学者的两分钱:在上面的示例中,有人更改坐标,其他人使用“自动调整蒙版”和其他约束:

正如 Apple 所说,不要混合这 3 种逻辑。如果您在 Storyboard 中有约束,请不要尝试更改 x/y。它绝对不起作用。