ios 使用 Swift 通过键盘移动视图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26070242/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 02:50:48  来源:igfitidea点击:

Move view with keyboard using Swift

iosswiftuikitnsnotificationcenteruikeyboard

提问by Alex Catchpole

I have an app that has a text field on the lower half of the view. This means that when I go to type in the text field the keyboard covers the textfield.

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

How would I go about moving the view upwards while typing so I can see what i'm typing and then moving it back down to its original place when the keyboard disappears?

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

I've looked everywhere but all the solutions appear to be in Obj-C which I can't quite convert just yet.

我到处找,但所有的解决方案似乎都在 Obj-C 中,我还不能完全转换。

Any help would be greatly appreciated.

任何帮助将不胜感激。

回答by Boris

Here is a solution, without handling the switch from one textField to another:

这是一个解决方案,无需处理从一个 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?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y -= keyboardSize.height
    }            
}

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

To solve this, replace the two functions keyboardWillShow/Hidewith these:

要解决此问题,请将这两个函数替换为keyboardWillShow/Hide

func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] 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
    }
}

EDIT FOR SWIFT 3.0:

为 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?[UIKeyboardFrameEndUserInfoKey] 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
    }
}

EDIT FOR SWIFT 4.0:

为 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?[UIKeyboardFrameEndUserInfoKey] 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
    }
}

EDIT FOR SWIFT 4.2:

为 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.keyboardFrameEndUserInfoKey] 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
    }
}

回答by gammachill

Easiest way that doesn't even require any code:

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

  1. Download KeyboardLayoutConstraint.swiftand add (drag & drop) the file into your project, if you're not using the Spring animation framework already.
  2. In your storyboard, create a bottom constraint for the View or Textfield, select the constraint (double-click it) and in the Identity Inspector, change its class from NSLayoutConstraint to KeyboardLayoutConstraint.
  3. Done!
  1. 如果您尚未使用 Spring 动画框架,请下载KeyboardLayoutConstraint.swift并将文件添加(拖放)到您的项目中。
  2. 在您的故事板中,为 View 或 Textfield 创建一个底部约束,选择该约束(双击它)并在 Identity Inspector 中,将其类从 NSLayoutConstraint 更改为 KeyboardLayoutConstraint。
  3. 完毕!

The object will auto-move up with the keyboard, in sync.

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

回答by Dan Beaulieu

One of the popular answers on this thread uses the following code:

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

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

There's an obvious problem with offsetting your view by a static amount. It'll look nice on one device but will look bad on any other size configuration. You'll need to get the keyboards height and use that as your offset value.

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

Here's a solution that works on all devicesand handles the edge-case where the user hides the predictive text field while typing.

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

Solution

解决方案

Important to note below, we're passing self.view.window in as our object parameter. This will provide us with data from our Keyboard, such as its height!

重要的是要注意下面,我们将 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
}

We'll make it look nice on all devices and handle the case where the user adds or removes the predictive text field.

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

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

Remove Observers

移除观察者

Don't forget to remove your observers before you leave the view to prevent unnecessary messages from being transmitted.

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

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


Update based on question from comments:

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

If you have two or more text-fields, you can check to see if your view.frame.origin.y is at zero.

如果您有两个或更多文本字段,您可以检查您的 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)
}

回答by user3677173

Add this to your viewcontroller. Works like a charm. Just adjust the values.

将此添加到您的视图控制器。奇迹般有效。只需调整值。

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
}

回答by scipianne

I improved one of the answers a bit to make it work with different keyboards & different textviews/fields on one page:

我稍微改进了其中一个答案,使其在一页上与不同的键盘和不同的文本视图/字段一起使用:

Add observers:

添加观察者:

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

Remove observers:

移除观察者:

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

回答by weegee

Not an advertisement or promotion or spam, just a good solution. I know that this question has nearly 30 answers and I'm so shocked that no one even mentioned once about this beautiful GitHub projectthat does it all for you and even better. All the answers just move the view upwards. I just solved all my problems with this IQKeyboardManager. It has 13000+ stars.
Just add this in your podfile if you are using swift

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

pod 'IQKeyboardManagerSwift'

and then inside your AppDelegate.swift do import IQKeyboardManagerSwift

然后在你的 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
    }
}

Add the line IQKeyboardManager.shared.enable = trueto enable it
This solution is a must if you are going for production.

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

回答by Ali Ihsan URAL

For Black Screen Error( Swift 4 & 4.2 ).

对于黑屏错误(Swift 4 & 4.2)

I fixed the black screen problem. In the verified solution The keyboard height changes after tapping and this is causing black screen.

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

Have to use UIKeyboardFrameEndUserInfoKeyinstead of UIKeyboardFrameBeginUserInfoKey

必须使用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
    }
}

回答by Amro Shafie

I see all answers are moving the view itself by the value of the keyboard height. Well, I have an elaborate answer, which could be useful if you are using constraints i.e autolayout, that moves a view by changing its constraint value (bottom or top constraints for example) by a predefined value or you can use keyboard size value.

我看到所有答案都通过键盘高度的值移动视图本身。好吧,我有一个详细的答案,如果您使用约束,即autolayout通过将其约束值(例如底部或顶部约束)更改为预定义值来移动视图,这可能会很有用,或者您可以使用键盘大小值。

In this example, I use bottom constraint from the textfield to Bottom Layout View with initial value of 175.

在这个例子中,我使用了从文本字段到底部布局视图的底部约束,初始值为 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()
    }
}

回答by Ivan Le Hjelmeland

There have been som changes to how we define the KeyboardWillHideNotification.

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

This solution works with Swift 4.2:

此解决方案适用于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
    }
}

回答by Pavle Mijatovic

For Swift 3, I made a UIViewController subclass since I needed constant behavior in all View Controllers.

对于 Swift 3,我创建了一个 UIViewController 子类,因为我需要在所有视图控制器中保持不变的行为。

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