【问题标题】:Move a view up only when the keyboard covers an input field仅当键盘覆盖输入字段时才向上移动视图
【发布时间】:2015-05-03 00:20:37
【问题描述】:

我正在尝试为 iPhone 构建一个输入屏幕。屏幕有许多输入字段。其中大部分位于屏幕顶部,但底部有两个字段。 当用户试图编辑屏幕底部的文本时,键盘会弹出并覆盖屏幕。 我找到了一个简单的解决方案,可以在发生这种情况时向上移动屏幕,但结果是屏幕总是向上移动,并且当用户尝试编辑这些字段时,屏幕顶部的字段会移到无法触及的范围内.

有没有办法让屏幕在底部字段被编辑时移动?

我使用了我找到的这个代码here

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(sender: NSNotification) {
    self.view.frame.origin.y -= 150
}

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

【问题讨论】:

  • 也许您可以使用 func textFieldDidBeginEditing(textField: UITextField!) { } 来检测哪个文本字段已开始编辑并进行键盘隐藏/显示
  • 我忘了说我是 Swift 新手 :( 检查这个的正确语法是什么?(如何在这个函数中获取字段名称?)

标签: ios swift keyboard xcode6


【解决方案1】:

this document by Apple 很好地解释了您的问题。此页面上的示例代码(Listing 4-1)完全符合您的需要,仅当当前编辑应该在键盘下时才会滚动您的视图。你只需要把你需要的控件放在一个scrollView中。 唯一的问题是这是 Objective-C,我认为你在 Swift 中需要它..so..这里是:

声明一个变量

var activeField: UITextField?

然后添加这些方法

 func registerForKeyboardNotifications()
{
    //Adding notifies on keyboard appearing
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
}


func deregisterFromKeyboardNotifications()
{
    //Removing notifies on keyboard appearing
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}

func keyboardWasShown(notification: NSNotification)
{
    //Need to calculate keyboard exact size due to Apple suggestions
    self.scrollView.scrollEnabled = true
    var info : NSDictionary = notification.userInfo!
    var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size
    var contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0)

    self.scrollView.contentInset = contentInsets
    self.scrollView.scrollIndicatorInsets = contentInsets

    var aRect : CGRect = self.view.frame
    aRect.size.height -= keyboardSize!.height
    if let activeFieldPresent = activeField
    {
        if (!CGRectContainsPoint(aRect, activeField!.frame.origin))
        {
            self.scrollView.scrollRectToVisible(activeField!.frame, animated: true)
        }
    }


}


func keyboardWillBeHidden(notification: NSNotification)
{
    //Once keyboard disappears, restore original positions
    var info : NSDictionary = notification.userInfo!
    var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size
    var contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, -keyboardSize!.height, 0.0)
    self.scrollView.contentInset = contentInsets
    self.scrollView.scrollIndicatorInsets = contentInsets
    self.view.endEditing(true)
    self.scrollView.scrollEnabled = false

}

func textFieldDidBeginEditing(textField: UITextField!)
{
    activeField = textField
}

func textFieldDidEndEditing(textField: UITextField!)
{
    activeField = nil
}

请务必将您的 ViewController 声明为 UITextFieldDelegate 并在您的初始化方法中设置正确的委托: 例如:

self.you_text_field.delegate = self

记得在 viewInit 上调用 registerForKeyboardNotifications,在退出时调用 deregisterFromKeyboardNotifications

编辑/更新:Swift 4.2 语法

func registerForKeyboardNotifications(){
    //Adding notifies on keyboard appearing
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIResponder.keyboardWillHideNotification, object: nil)
}

func deregisterFromKeyboardNotifications(){
    //Removing notifies on keyboard appearing
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIResponder.keyboardWillHideNotification, object: nil)
}

@objc func keyboardWasShown(notification: NSNotification){
    //Need to calculate keyboard exact size due to Apple suggestions
    self.scrollView.isScrollEnabled = true
    var info = notification.userInfo!
    let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
    let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize!.height, right: 0.0)

    self.scrollView.contentInset = contentInsets
    self.scrollView.scrollIndicatorInsets = contentInsets

    var aRect : CGRect = self.view.frame
    aRect.size.height -= keyboardSize!.height
    if let activeField = self.activeField {
        if (!aRect.contains(activeField.frame.origin)){
            self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
        }
    }
}

@objc func keyboardWillBeHidden(notification: NSNotification){
    //Once keyboard disappears, restore original positions
    var info = notification.userInfo!
    let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
    let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -keyboardSize!.height, right: 0.0)
    self.scrollView.contentInset = contentInsets
    self.scrollView.scrollIndicatorInsets = contentInsets
    self.view.endEditing(true)
    self.scrollView.isScrollEnabled = false
}

func textFieldDidBeginEditing(_ textField: UITextField){
    activeField = textField
}

func textFieldDidEndEditing(_ textField: UITextField){
    activeField = nil
}

【讨论】:

  • 您必须在 viewDidLoad 调用 registerForKeyboardNotifications,因此您将在通知中心添加一个观察者,以了解键盘何时出现或从屏幕上消失。当这些通知触发时,将调用方法keyboardWasShown 和keyboardWillBeHidden,然后滚动视图将相应地移动到键盘大小。您可以在此处找到有关 NotificationCenter 的更多详细信息:developer.apple.com/library/mac/documentation/Cocoa/Reference/…
  • 谢谢,这正是我想要的——苹果推荐的解决方案。但是,就我而言,我已经有一个跨越可视区域的滚动视图。此代码将在键盘隐藏后禁用滚动。我删除了“self.scrollView.scrollEnabled = false”,它仍然不会滚动。对我有用的是“self.scrollView.contentInset = UIEdgeInsetsZero;” keyboardWillHide 事件中的这一行
  • 完美的代码。但我需要使用UIKeyboardFrameEndUserInfoKey 而不是UIKeyboardFrameBeginUserInfoKey,因为后者返回高度0。并将命中点更改为底部而不是原点。 if let activeField = self.activeField { var point = activeField.frame.origin point.y += activeField.frame.size.height if (!aRect.contains(point)){ self.scrollView.scrollRectToVisible(activeField.frame, animated: true) } }
  • @MaX:它应该可以工作,但如果你想要一个 Swift4 解决方案,你可以查看Matt Neuburg 的书中的this iOS example,我建议所有 iOS 开发人员 :)
  • @MaX 我不确定这是否只是 swift 4 的事情,但似乎正在发生的事情是在调用 keyboardWillShow 方法之后调用了 textField's didBeginEditing 方法。结果,activeField 变量仍然为零,这意味着不会发生自动滚动。我的解决方案是将activeField = textField 调用放在textField 的shouldBeginEditing 方法中。这解决了调用顺序问题。
【解决方案2】:

这是我的 2 美分:

你试过了吗:https://github.com/hackiftekhar/IQKeyboardManager

非常容易安装 Swift 或 Objective-C。

这里是如何工作的:

IQKeyboardManager (Swift):- IQKeyboardManagerSwift 可通过 CocoaPods 获得,要安装它,只需将以下行添加到您的 Podfile:(#236)

pod 'IQKeyboardManagerSwift'

在 AppDelegate.swift 中,只需导入 IQKeyboardManagerSwift 框架并启用 IQKeyboardManager。

import IQKeyboardManagerSwift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

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

    IQKeyboardManager.sharedManager().enable = true
    // For Swift 4, use this instead
    // IQKeyboardManager.shared.enable = true


    return true
    }
}

仅此而已。简单!

【讨论】:

  • 完美。这应该是默认内置的。看起来可笑,它不是。
  • 这实在是太荒谬了,它很容易实现而且很有效,而且你还可以轻松地在多个文本字段之间切换
  • 切换到多个文本字段不起作用?键盘上没有箭头显示在文本字段之间移动。
  • 这是一个了不起的解决方案,谢谢!我花了一些功夫来正确设置 CocoaPods,因为它们对我来说是全新的。在我设置好之后,实际上只需要 2 行代码就可以实现它,而且它马上就完美地工作了。非常感谢!
  • 这在 Swift 4.1 中对我不起作用 IQKeyboardManager.sharedManager().enable = true 已切换到 IQKeyboardManager.shared.enable = true
【解决方案3】:

我发现最适合我的是这个:

func textFieldDidBeginEditing(textField: UITextField) {
    if textField == email || textField == password {
        animateViewMoving(true, moveValue: 100)
    }
}

func textFieldDidEndEditing(textField: UITextField) {
    if textField == email || textField == password {
        animateViewMoving(false, moveValue: 100)
    }
}

func animateViewMoving (up:Bool, moveValue :CGFloat){
    let movementDuration:NSTimeInterval = 0.3
    let movement:CGFloat = ( up ? -moveValue : moveValue)

    UIView.beginAnimations("animateView", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(movementDuration)

    self.view.frame = CGRectOffset(self.view.frame, 0, movement)
    UIView.commitAnimations()
}

您还可以更改高度值。如果要对所有文本字段使用“if 语句”,请删除它。

您甚至可以将它用于所有需要用户输入的控件,例如 TextView。

【讨论】:

  • 直接移动 UIView 框架并不是一个很好的解决方案。此外,这包括特定于此用例的硬编码值。我会鼓励人们不要实施这样的解决方案,而是做一些更接近于接受的答案中描述的最佳实践的事情。
  • @MobileVet 明白了,但这是可行的。
  • 惊人的独立逻辑,无需更改我们的代码
【解决方案4】:

有没有办法让屏幕在编辑底部字段时移动?

我遇到了类似的问题,并找到了一个非常简单的解决方案不使用使用滚动视图,而是使用keyboardWillShow/Hide 方法中的if 语句。

func keyboardWillShow(notification: NSNotification) {
    if bottomText.editing{
        self.view.window?.frame.origin.y = -1 * getKeyboardHeight(notification)
    }
}

func keyboardWillHide(notification: NSNotification) {
    if self.view.window?.frame.origin.y != 0 {
        self.view.window?.frame.origin.y += getKeyboardHeight(notification)
    }
}

这对我来说是一个很好的解决方案,因为我只有两个文本字段。

向上移动整个视图:仅在编辑某些文本字段(底部文本)时

向下移动整个视图:仅当视图不在原始位置时

【讨论】:

    【解决方案5】:

    当键盘出现时,只需使用这个扩展来移动任何 UIView。

    extension UIView {
        func bindToKeyboard(){
            NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillChange(_:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
        }
    
        @objc func keyboardWillChange(_ notification: NSNotification){
            let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
            let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
            let beginningFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
            let endFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
    
            let deltaY = endFrame.origin.y - beginningFrame.origin.y
    
            UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
                self.frame.origin.y += deltaY
            }, completion: nil)
        }
    }
    

    然后在您的 viewdidload 中将您的视图绑定到键盘

    UiView.bindToKeyboard()
    

    【讨论】:

    • 即使不需要它也会向上移动视图,如果文本字段位于视图顶部,它将向上移动并且不可见。这不是一个好的解决方案。
    • 代码需要更新,这里修复stackoverflow.com/questions/52316676/…
    【解决方案6】:

    为什么不在 UITableViewController 中实现呢?键盘显示时不会隐藏任何文本字段。

    【讨论】:

    • 这实际上是最简单和最健壮的方法。它甚至适用于使用自定义 InputView 而不是默认键盘的控件(UIKeyboard 通知不适用于这些)
    • 如果表格视图是嵌入的(而不是“整个页面”),您必须小心的问题。对于任何被此绊倒的人,解决方案在thisthis 等帖子中进行了解释。希望它可以帮助处理“所有 Apple 中最愚蠢的问题”的人!
    【解决方案7】:

    Swift 4(**更新)带扩展**

    1. 在一个容器中添加按钮
    2. 将容器的底部约束与 IBOutlet containerBtmConstrain 连接
    3. inViewDidLoad

      self.containerDependOnKeyboardBottomConstrain = containerBtmConstrain
      self.watchForKeyboard() 
      
    4. 添加以下扩展

      import UIKit
      
      private var xoAssociationKeyForBottomConstrainInVC: UInt8 = 0
      
      extension UIViewController {
      
          var containerDependOnKeyboardBottomConstrain :NSLayoutConstraint! {
              get {
                  return objc_getAssociatedObject(self, &xoAssociationKeyForBottomConstrainInVC) as? NSLayoutConstraint
              }
              set(newValue) {
                  objc_setAssociatedObject(self, &xoAssociationKeyForBottomConstrainInVC, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
              }
          }
      
          func watchForKeyboard() {
              NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWasShown(notification:)), name:UIResponder.keyboardWillShowNotification, object: nil);
              NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(notification:)), name:UIResponder.keyboardWillHideNotification, object: nil);
          }
      
          @objc func keyboardWasShown(notification: NSNotification) {
              let info = notification.userInfo!
              guard let keyboardFrame: CGRect = (info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {
                return
              }
      
              UIView.animate(withDuration: 0.3, animations: { () -> Void in
                  self.containerDependOnKeyboardBottomConstrain.constant = -keyboardFrame.height
                  self.view.layoutIfNeeded()
              })
          }
      
          @objc func keyboardWillHide(notification: NSNotification) {
              UIView.animate(withDuration: 0.3, animations: { () -> Void in
                  self.containerDependOnKeyboardBottomConstrain.constant = 0
                  self.view.layoutIfNeeded()
              })
          }
      }
      

    【讨论】:

    • 谢谢,伙计。这都是关于正确的钥匙。我正在使用 UIKeyboardFrameBeginUserInfoKey,现在使用 UIKeyboardFrameEndUserInfoKey 可以优雅地处理它。
    【解决方案8】:

    我使用 SwiftLint,它在接受答案的格式方面存在一些问题。具体来说:

    冒号前没有空格, 没有强制铸造, 更喜欢 UIEdgeInset(top: etc... 而不是 UIEdgeInsetMake。

    这里是 Swift 3 的更新

    func registerForKeyboardNotifications() {
        //Adding notifies on keyboard appearing
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }
    
    func deregisterFromKeyboardNotifications() {
        //Removing notifies on keyboard appearing
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }
    
    func keyboardWasShown(notification: NSNotification) {
        //Need to calculate keyboard exact size due to Apple suggestions
        scrollView?.isScrollEnabled = true
        var info = notification.userInfo!
        if let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size {
            let contentInsets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize.height, right: 0.0)
    
            scrollView?.contentInset = contentInsets
            scrollView?.scrollIndicatorInsets = contentInsets
    
            var aRect: CGRect = self.view.frame
            aRect.size.height -= keyboardSize.height
            if let activeField = self.activeField {
                if !aRect.contains(activeField.frame.origin) {
                    self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
                }
            }
        }
    }
    
    func keyboardWillBeHidden(notification: NSNotification) {
        //Once keyboard disappears, restore original positions
        var info = notification.userInfo!
        if let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size {
            let contentInsets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -keyboardSize.height, right: 0.0)
            scrollView?.contentInset = contentInsets
            scrollView?.scrollIndicatorInsets = contentInsets
        }
    
        view.endEditing(true)
        scrollView?.isScrollEnabled = false
    }
    
    func textFieldDidBeginEditing(_ textField: UITextField) {
        activeField = textField
    }
    
    func textFieldDidEndEditing(_ textField: UITextField) {
        activeField = nil
    }
    

    【讨论】:

      【解决方案9】:

      Swift:您可以通过检查正在呈现的文本字段来做到这一点。

      @objc func keyboardWillShow(notification: NSNotification) {
          if self.textField.isFirstResponder == true {
              self.view.frame.origin.y -= 150
           }
      }
      
      @objc func keyboardWillHide(notification: NSNotification){
          if self.textField.isFirstResponder == true {
             self.view.frame.origin.y += 150
          }
      }
      

      【讨论】:

        【解决方案10】:

        我认为这个条款是错误的:

        if (!CGRectContainsPoint(aRect, activeField!.frame.origin))
        

        虽然 activeField 的原点可能在键盘上方,但 maxY 可能不在...

        我会为 activeField 创建一个“最大”点并检查它是否在键盘 Rect 中。

        【讨论】:

          【解决方案11】:

          由于没有关于如何在 Combine 中执行此操作的答案,因此这是我使用的方法。

          1. 我们创建了一个发布者来监听通知、显示和隐藏。
          2. 为了展示,我们从通知userInfo 中获取键盘框架,并检查current active responder 是否包含在其中。如果它被覆盖,则返回键盘框架高度。如果没有覆盖返回0,我们不想移动框架。对于隐藏通知,我们只需返回 0。
          private var keyboardHeightPublisher: AnyPublisher<CGFloat, Never> {
              Publishers.Merge(
                  NotificationCenter.default
                      .publisher(for: UIResponder.keyboardWillShowNotification)
                      .compactMap { $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect }
                      .map { $0.intersects(self.view.firstResponder!.frame) ? $0.height : 0 }
                      .map { $0 * -1 },
                  NotificationCenter.default
                      .publisher(for: UIResponder.keyboardWillHideNotification)
                      .map { _ in CGFloat(0) }
              ).eraseToAnyPublisher()
          }
          

          viewDidLoad 中,我们只需订阅发布者相应地更改视图框架。

          override func viewDidLoad() {
              super.viewDidLoad()
          
              keyboardHeightPublisher.sink{ [weak self] height in
                  self?.view.frame.origin.y = height
              }.store(in: &cancelables)
          }
          

          编辑
          当心!如果firstResponder在子视图中,则必须计算与整个屏幕对应的框架以检查它们是否真正相交。
          示例:

          let myViewGlobalFrame = myView.convert(myView.frame, to: parentView)
          

          【讨论】:

            【解决方案12】:

            这是我阅读了 Apple 提供的文档和之前的帖子后的版本。我注意到的一件事是 textView 在被键盘覆盖时没有被处理。不幸的是,Apple 的文档不起作用,因为无论出于何种原因,在调用 textViewDidBeginEditing 之后都会调用键盘。我通过调用一个中心方法来处理这个问题,该方法检查键盘是否显示以及是否正在编辑 textView 或 textField。这样,只有在两种条件都存在时才会触发该过程。

            textViews 的另一点是,它们的高度可能会导致键盘夹住 textView 的底部,并且如果左上角的点在视图中,则不会调整。因此,我编写的代码实际上获取了任何 textView 或 textField 的屏幕引用的左下角,并查看它是否落在所显示键盘的屏幕引用坐标中,这意味着键盘覆盖了它的某些部分。

            let aRect : CGRect = scrollView.convertRect(activeFieldRect!, toView: nil)
                if (CGRectContainsPoint(keyboardRect!, CGPointMake(aRect.origin.x, aRect.maxY))) {
                    // scroll textView/textField into view
                }
            

            如果您使用的是导航控制器,子类还会将滚动视图自动调整插入设置为 false。

            self.automaticallyAdjustsScrollViewInsets = false
            

            遍历每个 textView 和 textField 来设置委托处理

                for view in self.view.subviews {
                    if view is UITextView {
                        let tv = view as! UITextView
                        tv.delegate = self
                    } else if view is UITextField {
                        let tf = view as! UITextField
                        tf.delegate = self
                    }
                }
            

            只需将您的基类设置为此处创建的子类即可获得结果。

            import UIKit
            
            class ScrollingFormViewController: UIViewController, UITextViewDelegate, UITextFieldDelegate {
            
            var activeFieldRect: CGRect?
            var keyboardRect: CGRect?
            var scrollView: UIScrollView!
            
            override func viewDidLoad() {
            
                self.automaticallyAdjustsScrollViewInsets = false
            
                super.viewDidLoad()
            
                // Do any additional setup after loading the view.
                self.registerForKeyboardNotifications()
                for view in self.view.subviews {
                    if view is UITextView {
                        let tv = view as! UITextView
                        tv.delegate = self
                    } else if view is UITextField {
                        let tf = view as! UITextField
                        tf.delegate = self
                    }
                }
                scrollView = UIScrollView(frame: self.view.frame)
                scrollView.scrollEnabled = false
                scrollView.showsVerticalScrollIndicator = false
                scrollView.showsHorizontalScrollIndicator = false
                scrollView.addSubview(self.view)
                self.view = scrollView
            }
            
            override func viewDidLayoutSubviews() {
                scrollView.sizeToFit()
                scrollView.contentSize = scrollView.frame.size
                super.viewDidLayoutSubviews()
            }
            
            deinit {
                self.deregisterFromKeyboardNotifications()
            }
            
            override func didReceiveMemoryWarning() {
                super.didReceiveMemoryWarning()
                // Dispose of any resources that can be recreated.
            }
            
            
            func registerForKeyboardNotifications()
            {
                //Adding notifies on keyboard appearing
                NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ScrollingFormViewController.keyboardWasShown), name: UIKeyboardWillShowNotification, object: nil)
                NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ScrollingFormViewController.keyboardWillBeHidden), name: UIKeyboardWillHideNotification, object: nil)
            }
            
            
            func deregisterFromKeyboardNotifications()
            {
                //Removing notifies on keyboard appearing
                NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
                NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
            }
            
            func keyboardWasShown(notification: NSNotification)
            {
                let info : NSDictionary = notification.userInfo!
                keyboardRect = (info[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
                adjustForKeyboard()
            }
            
            
            func keyboardWillBeHidden(notification: NSNotification)
            {
                keyboardRect = nil
                adjustForKeyboard()
            }
            
            func adjustForKeyboard() {
                if keyboardRect != nil && activeFieldRect != nil {
                    let aRect : CGRect = scrollView.convertRect(activeFieldRect!, toView: nil)
                    if (CGRectContainsPoint(keyboardRect!, CGPointMake(aRect.origin.x, aRect.maxY)))
                    {
                        scrollView.scrollEnabled = true
                        let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardRect!.size.height, 0.0)
                        scrollView.contentInset = contentInsets
                        scrollView.scrollIndicatorInsets = contentInsets
                        scrollView.scrollRectToVisible(activeFieldRect!, animated: true)
                    }
                } else {
                    let contentInsets : UIEdgeInsets = UIEdgeInsetsZero
                    scrollView.contentInset = contentInsets
                    scrollView.scrollIndicatorInsets = contentInsets
                    scrollView.scrollEnabled = false
                }
            }
            
            func textViewDidBeginEditing(textView: UITextView) {
                activeFieldRect = textView.frame
                adjustForKeyboard()
            }
            
            func textViewDidEndEditing(textView: UITextView) {
                activeFieldRect = nil
                adjustForKeyboard()
            }
            
            func textFieldDidBeginEditing(textField: UITextField)
            {
                activeFieldRect = textField.frame
                adjustForKeyboard()
            }
            
            func textFieldDidEndEditing(textField: UITextField)
            {
                activeFieldRect = nil
                adjustForKeyboard()
            }
            
            }
            

            【讨论】:

              【解决方案13】:

              已经给出了很棒的答案,但这是处理这种情况的另一种方法(使用 Swift 3x):

              首先在viewWillAppear()中调用如下方法

              func registerForKeyboardNotifications() {
              
              NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWasShown), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
              NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillBeHidden), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
              
              }
              

              现在在UIViewUIViewcontroller 的顶级约束中取一个IBOutlet,如下所示:(这里的UIViewUIScrollView 的子视图,这意味着你应该有一个UIScrollView对于你所有的subViews)

              @IBOutlet weak var loginViewTopConstraint: NSLayoutConstraint!
              

              还有一个像下面这样的变量并添加一个委托,即UITextFieldDelegate

              var activeTextField = UITextField() //This is to keep the reference of UITextField currently active
              

              接下来是神奇的部分,只需将其粘贴在下面sn-p

              func keyboardWasShown(_ notification: Notification) {
              
              let keyboardInfo  = notification.userInfo as NSDictionary?
              
              //print(keyboardInfo!)
              
              let keyboardFrameEnd: NSValue? = (keyboardInfo?.value(forKey: UIKeyboardFrameEndUserInfoKey) as? NSValue)
              
              let keyboardFrameEndRect: CGRect? = keyboardFrameEnd?.cgRectValue
              
              
              if activeTextField.frame.origin.y + activeTextField.frame.size.height + 10 > (keyboardFrameEndRect?.origin.y)! {
              
                  UIView.animate(withDuration: 0.3, delay: 0, options: .transitionFlipFromTop, animations: {() -> Void in
              
                      //code with animation
              
                      //Print some stuff to know what is actually happening
                      //print(self.activeTextField.frame.origin.y)
                      //print(self.activeTextField.frame.size.height)
                      //print(self.activeTextField.frame.size.height)
              
                      self.loginViewTopConstraint.constant = -(self.activeTextField.frame.origin.y + self.activeTextField.frame.size.height - (keyboardFrameEndRect?.origin.y)!) - 30.0
              
                      self.view.layoutIfNeeded()
              
                  }, completion: {(_ finished: Bool) -> Void in
                      //code for completion
              
                  })
              }
              }
              
              func keyboardWillBeHidden(_ notification: Notification) {
              
              UIView.animate(withDuration: 0.3, animations: {() -> Void in
              
                  self.loginViewTopConstraint.constant = self.view.frame.origin.y
                  self.view.layoutIfNeeded()
              
              })
              }
              
              //MARK: textfield delegates
              func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
                  activeTextField = textField
                  return true
              }
              
              func textFieldShouldReturn(_ textField: UITextField) -> Bool {
              
                         switch textField {
                  case YOUR_TEXTFIELD_ONE:
                      YOUR_TEXTFIELD_TWO.becomeFirstResponder()
                      break
                  case YOUR_TEXTFIELD_TWO:
                      YOUR_TEXTFIELD_THREE.becomeFirstResponder()
                      break
                  default:
                      textField.resignFirstResponder()
                      break
                  }
                  return true
              }
              

              现在是最后一个sn-p:

              //Remove Keyboard Observers
              override func viewWillDisappear(_ animated: Bool) {
              
              NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)
              
              NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
              }
              

              不要忘记在UIStoryboard 中为您的所有UITextFields 分配代表

              祝你好运!

              【讨论】:

                【解决方案14】:

                Swift 3 语法:

                func textFieldDidBeginEditing(_ textField: UITextField) {
                    // add if for some desired textfields
                        animateViewMoving(up: true, moveValue: 100)
                }
                
                func textFieldDidEndEditing(_ textField: UITextField) {
                    // add if for some desired textfields
                        animateViewMoving(up: false, moveValue: 100)
                }
                
                func animateViewMoving (up:Bool, moveValue :CGFloat){
                     textFieldDidEndEditing(_ textField: UITextField) {
                
                    let movementDuration:TimeInterval = 0.5
                
                    let movement:CGFloat = ( up ? -moveValue : moveValue)
                
                    UIView.beginAnimations("animateView", context: nil)
                
                    UIView.setAnimationBeginsFromCurrentState(true)
                
                    UIView.setAnimationDuration(movementDuration)
                
                    self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
                
                    UIView.commitAnimations()
                }
                

                这是获得您想要的东西的好方法 您可以为某些文本字段添加“if”条件 但是这种类型适用于所有人...希望它对每个人都有用

                【讨论】:

                  【解决方案15】:

                  首先声明一个变量来标识你的活动 UITextField。

                  第 1 步:-

                  喜欢var activeTextField: UITextField?

                  第 2 步:- 之后在 viewDidLoad 中添加这两行。

                  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)
                  

                  第 3 步:-

                  现在在你的控制器类中定义这两个方法。

                  func keyboardWillShow(_ notification: NSNotification) {
                  
                      self.scrollView.isScrollEnabled = true
                      var info = notification.userInfo!
                      let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
                      let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0)
                  
                      self.scrollView.contentInset = contentInsets
                      self.scrollView.scrollIndicatorInsets = contentInsets
                  
                      var aRect : CGRect = self.view.frame
                      aRect.size.height -= keyboardSize!.height
                      if let activeField = self.activeField {
                          if (!aRect.contains(activeField.frame.origin)){
                              self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
                          }
                      }
                  }
                  
                  
                  func keyboardWillHide(_ notification: NSNotification) {
                  
                      let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0)
                      self.scrollView.contentInset = contentInsets
                      self.scrollView.scrollIndicatorInsets = contentInsets
                      self.view.endEditing(true)
                      self.scrollView.isScrollEnabled = true
                  }
                  
                  
                  func textFieldDidBeginEditing(_ textField: UITextField){
                  
                      activeField = textField
                  }
                  
                  func textFieldDidEndEditing(_ textField: UITextField){
                  
                      activeField = nil
                  }
                  

                  【讨论】:

                    【解决方案16】:

                    对于 Swift 4.2。

                    这将适用于任何形式。不需要滚动视图。 不要忘记设置委托。

                    制作一个uitextfield的var

                    var clickedTextField = UITextField()
                    

                    在您看来已加载

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

                    知道点击的文本字段。可能您在整个屏幕上都有文本字段。

                    func textFieldDidBeginEditing(_ textField: UITextField) {
                        clickedTextField = textField
                    }
                    

                    检查键盘是否覆盖了文本框。

                    @objc func keyboardWillShow(sender: NSNotification,_ textField : UITextField) {
                        if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
                    
                            if clickedTextField.frame.origin.y > keyboardSize.origin.y {
                                self.view.frame.origin.y = keyboardSize.origin.y - clickedTextField.center.y - 20
                            }
                        }
                    }
                    
                    @objc func keyboardWillHide(sender: NSNotification) {
                        self.view.frame.origin.y = 0
                    }
                    

                    返回关闭键盘

                    func textFieldShouldReturn(_ textField: UITextField) -> Bool {   //delegate method
                        textField.resignFirstResponder()
                        return true
                    }
                    

                    更新: NSNotification.Name.UIKeyboardWillShow & NSNotification.Name.UIKeyboardWillHide 分别重命名为 UIResponder.keyboardWillShowNotification & UIResponder.keyboardWillHideNotification。

                    【讨论】:

                    • 可以说你在 viewController 中使用了 usernameTextfield 的出口。在 viewDidLoad 中只写: usernameTextField.delegate = self
                    • 感谢您的信息。我已经按照这封信进行了操作,但它并没有抬起键盘。我已经玩过代码,但无法让它工作。我正在使用 iOS 14 和 Xcode 12。谢谢。
                    • 你确认 UITextViewDelegate 协议到 uiviewcontroller 了吗?如果这不起作用,那么您可以使用“IQKeyboardManager”库。
                    【解决方案17】:

                    斯威夫特 3

                    @IBOutlet var scrollView: UIScrollView!
                    @IBOutlet var edtEmail: UITextField!
                    @IBOutlet var bottomTextfieldConstrain: NSLayoutConstraint! // <- this guy is the constrain that connect the bottom of textField to lower object or bottom of page!
                    
                     @IBAction func edtEmailEditingDidBegin(_ sender: Any) { 
                            self.bottomTextfieldConstrain.constant = 200
                            let point = CGPoint(x: 0, y: 200)
                            scrollView.contentOffset = point
                        }
                    
                    @IBAction func edtEmailEditingDidEnd(_ sender: Any) { 
                        self.bottomTextfieldConstrain.constant = 50
                    }
                    

                    【讨论】:

                      【解决方案18】:

                      接受的答案几乎是完美的。但我需要使用UIKeyboardFrameEndUserInfoKey 而不是UIKeyboardFrameBeginUserInfoKey,,因为后者返回键盘高度0。并将命中点更改为底部而不是原点。

                          var aRect : CGRect = self.view.frame
                          aRect.size.height -= keyboardSize!.height
                          if let activeField = self.activeField {
                              var point = activeField.frame.origin
                              point.y += activeField.frame.size.height
                              if (!aRect.contains(point)){
                                  self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
                              }
                          }
                      

                      【讨论】:

                        【解决方案19】:

                        Swift 4 更新了我的解决方案

                        在键盘显示/隐藏时带有约束动画, 享受。

                        import Foundation
                        import UIKit
                        
                        class PhoneController: UIViewController, UITextFieldDelegate{
                        
                            var phoneLayoutYConstraint: NSLayoutConstraint?
                        
                            override func viewDidLoad() {
                        
                                super.viewDidLoad()
                        
                                view.backgroundColor = .white
                        
                                NotificationCenter.default.addObserver(self, selector: #selector(handleKeyBoardNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
                                NotificationCenter.default.addObserver(self, selector: #selector(handleKeyBoardNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
                                phoneField.delegate = self
                        
                                view.addSubview(phoneField)
                        
                                NSLayoutConstraint.activate([phoneField.heightAnchor.constraint(equalToConstant: 50),
                                                             phoneField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                                                             phoneField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
                                                             phoneField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)])
                        
                                phoneLayoutYConstraint = NSLayoutConstraint(item: phoneField, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
                                phoneLayoutYConstraint?.isActive = true
                        
                            }
                        
                            let phoneField: UITextField = {
                                let text = UITextField()
                                text.translatesAutoresizingMaskIntoConstraints = false
                                text.keyboardType = .numberPad
                                text.font = UIFont.systemFont(ofSize: 30)
                                text.layer.cornerRadius = 5.0
                                text.layer.masksToBounds = true
                                text.layer.borderColor = UIColor.darkGray.cgColor
                                text.layer.borderWidth = 2.0
                        
                                return text
                            }()
                        
                        
                            override func viewDidDisappear(_ animated: Bool) {
                                super.viewWillDisappear(animated)
                                NotificationCenter.default.removeObserver(self)
                            }
                        
                            func textFieldDidBeginEditing(_ textField: UITextField) {
                        
                            }
                        
                        
                            func textFieldDidEndEditing(_ textField: UITextField) {
                        
                            }
                        
                            func textFieldShouldReturn(_ textField: UITextField) -> Bool {
                                textField.resignFirstResponder()
                                return true
                            }
                        
                        
                           @objc func handleKeyBoardNotification(_ notification: NSNotification) {
                        
                                if let info = notification.userInfo {
                        
                                    let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
                                    let isKeyBoardShowing = notification.name == NSNotification.Name.UIKeyboardWillShow
                        
                                    var aRect : CGRect = self.phoneField.frame
                                    aRect.size.height -= keyboardSize!.height
                        
                        
                                    phoneLayoutYConstraint?.constant = isKeyBoardShowing ? -keyboardSize!.height : 0
                        
                                    UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
                                        self.view.layoutIfNeeded()
                                    }, completion: { (boo) in
                        
                                    })
                        
                                }
                            }
                        
                        }
                        

                        【讨论】:

                          【解决方案20】:

                          斯威夫特 4

                          您可以使用带动画的键盘轻松上下移动UITextField

                          import UIKit
                          
                          class ViewController: UIViewController {
                          
                              @IBOutlet var textField: UITextField!
                          
                              override func viewDidLoad() {
                                  super.viewDidLoad()
                                  NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)
                              }
                          
                              override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
                                  textField.resignFirstResponder()
                              }
                          
                              @objc func keyboardWillChange(notification: NSNotification) {
                          
                                  let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
                                  let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
                                  let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
                                  let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
                                  let deltaY = targetFrame.origin.y - curFrame.origin.y
                          
                                  UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
                                      self.textField.frame.origin.y+=deltaY
                          
                                  },completion: nil)
                              }
                          

                          【讨论】:

                          • 又是一个解决方案,即使在不需要时也会不必要地向上推视图。请改进您的答案,这是误导
                          【解决方案21】:

                          斯威夫特 4.2

                          如果UITextField 的位置在键盘下方,我的解决方案将(垂直)将视图居中。

                          第 1 步:创建新的 swift 文件并复制粘贴 UIViewWithKeyboard 类。
                          第 2 步:在 Interface Builder 中将其设置为您最顶级的 UIView 的自定义类。

                          import UIKit
                          
                          class UIViewWithKeyboard: UIView {
                              @IBInspectable var offsetMultiplier: CGFloat = 0.75
                              private var keyboardHeight = 0 as CGFloat
                              private weak var activeTextField: UITextField?
                              override func awakeFromNib() {
                                  super.awakeFromNib()
                                  NotificationCenter.default.addObserver(self, selector: #selector(UIViewWithKeyboard.textDidBeginEditing),
                                                                         name: UITextField.textDidBeginEditingNotification, object: nil)
                                  NotificationCenter.default.addObserver(self, selector: #selector(UIViewWithKeyboard.keyboardWillShow),
                                                                         name: UIResponder.keyboardWillShowNotification, object: nil)
                                  NotificationCenter.default.addObserver(self, selector: #selector(UIViewWithKeyboard.keyboardWillHide),
                                                                         name: UIResponder.keyboardWillHideNotification, object: nil)
                              }
                          
                              @objc func textDidBeginEditing(_ notification: NSNotification) {
                                  self.activeTextField = notification.object as? UITextField
                              }
                          
                              @objc func keyboardWillShow(_ notification: Notification) {
                                  if let frameValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
                                      keyboardHeight = frameValue.cgRectValue.size.height
                                      if let textField = self.activeTextField {
                                          let offset = textField.frame.maxY < frame.maxY - keyboardHeight ? 0
                                                     : textField.frame.maxY - (frame.maxY - keyboardHeight) * offsetMultiplier
                                          self.setView(offset: offset)
                                      }
                                  }
                              }
                          
                              @objc func keyboardWillHide(_ notification: NSNotification) {
                                  self.setView(offset: 0)
                              }
                          
                              func setView(offset: CGFloat) {
                                  UIView.animate(withDuration: 0.25) {
                                      self.bounds.origin.y = offset
                                  }
                              }
                          }
                          

                          【讨论】:

                            【解决方案22】:

                            为 swift 4.2 重写

                            在 ViewDidLoad..

                             NotificationCenter.default.addObserver(self, selector: #selector(trailViewController.keyboardWasShown), name: UIResponder.keyboardWillShowNotification, object: nil)
                             NotificationCenter.default.addObserver(self, selector: #selector(trailViewController.keyboardWillBeHidden), name: UIResponder.keyboardWillHideNotification, object: nil)
                            

                            其他功能

                            func registerForKeyboardNotifications(){
                                //Adding notifies on keyboard appearing
                                NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
                                NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
                            }
                            
                            func deregisterFromKeyboardNotifications(){
                                //Removing notifies on keyboard appearing
                                NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
                                NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
                            }
                            
                            @objc func keyboardWasShown(notification: NSNotification){
                                //Need to calculate keyboard exact size due to Apple suggestions
                                self.scrollView.isScrollEnabled = true
                                var info = notification.userInfo!
                                let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
                                let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize!.height, right: 0.0)
                            
                                self.scrollView.contentInset = contentInsets
                                self.scrollView.scrollIndicatorInsets = contentInsets
                            
                                var aRect : CGRect = self.view.frame
                                aRect.size.height -= keyboardSize!.height
                                if let activeField = self.activeField {
                                    if (!aRect.contains(activeField.frame.origin)){
                                        self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
                                    }
                                }
                            }
                            
                            @objc func keyboardWillBeHidden(notification: NSNotification){
                                //Once keyboard disappears, restore original positions
                                var info = notification.userInfo!
                                let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
                                let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -keyboardSize!.height, right: 0.0)
                                self.scrollView.contentInset = contentInsets
                                self.scrollView.scrollIndicatorInsets = contentInsets
                                self.view.endEditing(true)
                                self.scrollView.isScrollEnabled = false
                            }
                            
                            func textFieldDidBeginEditing(_ textField: UITextField){
                                activeField = textField
                            }
                            
                            func textFieldDidEndEditing(_ textField: UITextField){
                                activeField = nil
                            }
                            

                            【讨论】:

                              【解决方案23】:

                              “我忘了说我是 Swift 新手 :( 检查这个的正确语法是什么?(我如何在这个函数中获取字段名称?)”

                              好的。首先确认到 UITextFieldDelegate 协议

                              class YourClass:UITextFieldDelegate
                              

                              然后实现函数

                              func textFieldDidBeginEditing(textField: UITextField!) {
                              
                                  if textField == txtOne
                                  {
                                      println("TextOne")
                                  }
                                  if textField == txtTwo
                                  {
                                      println("TextTwo")
                                  }
                              }
                              

                              您应该注意,正确的方法是使用滚动视图并将应该向上/向下移动的视图放置在滚动视图中并相应地处理键盘事件

                              【讨论】:

                                【解决方案24】:

                                此代码将您正在编辑的文本字段向上移动,以便您可以在 Swift 3 中查看此答案,您还必须将您的视图设为 UITextFieldDelegate:

                                var moveValue: CGFloat!
                                var moved: Bool = false
                                var activeTextField = UITextField()
                                
                                func textFieldDidBeginEditing(_ textField: UITextField) {
                                    self.activeTextField = textField
                                }
                                func textFieldDidEndEditing(_ textField: UITextField) {
                                    if moved == true{
                                    self.animateViewMoving(up: false, moveValue: moveValue )
                                        moved = false
                                    }
                                }
                                func animateViewMoving (up:Bool, moveValue :CGFloat){
                                    let movementDuration:TimeInterval = 0.3
                                    let movement:CGFloat = ( up ? -moveValue : moveValue)
                                
                                    UIView.beginAnimations("animateView", context: nil)
                                    UIView.setAnimationBeginsFromCurrentState(true)
                                    UIView.setAnimationDuration(movementDuration)
                                
                                    self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
                                    UIView.commitAnimations()
                                }
                                

                                然后在viewDidLoad中:

                                NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
                                

                                哪些调用(在 viewDidLoad 之外):

                                func keyboardWillShow(notification: Notification) {
                                    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
                                        let keyboardHeight = keyboardSize.height
                                        if (view.frame.size.height-self.activeTextField.frame.origin.y) - self.activeTextField.frame.size.height < keyboardHeight{
                                            moveValue = keyboardHeight - ((view.frame.size.height-self.activeTextField.frame.origin.y) - self.activeTextField.frame.size.height)
                                            self.animateViewMoving(up: true, moveValue: moveValue )
                                            moved = true
                                        }
                                    }
                                }
                                

                                【讨论】:

                                  【解决方案25】:

                                  对于 Swift 4.2

                                  此代码将允许您控制特定设备屏幕尺寸的框架的 Y 轴力矩。

                                  PS:这段代码不会根据TextField的位置智能移动框架。

                                  为 UIDevice 创建一个扩展

                                  extension UIDevice {
                                      enum ScreenType: String {
                                          case iPhone4_4S = "iPhone 4 or iPhone 4s"
                                          case iPhones_5_5s_5c_SE = "iPhone 5, iPhone 5s, iPhone 5c or iPhone SE"
                                          case iPhones_6_6s_7_8 = "iPhone 6, iPhone 6s, iPhone 7 or iPhone 8"
                                          case iPhones_6Plus_6sPlus_7Plus_8Plus = "iPhone 6 Plus, iPhone 6s Plus, iPhone 7 Plus or iPhone 8 Plus"
                                          case iPhoneX_Xs = "iPhone X, iPhone Xs"
                                          case iPhoneXR = "iPhone XR"
                                          case iPhoneXSMax = "iPhone Xs Max"
                                          case unknown
                                      }
                                      var screenType: ScreenType {
                                          switch UIScreen.main.nativeBounds.height {
                                          case 960:
                                              return .iPhone4_4S
                                          case 1136:
                                              return .iPhones_5_5s_5c_SE
                                          case 1334:
                                              return .iPhones_6_6s_7_8
                                          case 1920, 2208:
                                              return .iPhones_6Plus_6sPlus_7Plus_8Plus
                                          case 1792:
                                              return .iPhoneXR
                                          case 2436:
                                              return .iPhoneX_Xs
                                          case 2688:
                                              return .iPhoneXSMax
                                          default:
                                              return .unknown
                                          }
                                      }
                                  }
                                  

                                  在 viewDidLoad 上添加 NotificationObserver

                                  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 ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
                                          if self.view.frame.origin.y == 0 {
                                              switch (UIDevice.current.screenType.rawValue) {
                                              case (UIDevice.ScreenType.iPhones_5_5s_5c_SE.rawValue):
                                                  self.view.frame.origin.y -= 210
                                              case (UIDevice.ScreenType.iPhones_6_6s_7_8.rawValue):
                                                  self.view.frame.origin.y -= 110
                                              case (UIDevice.ScreenType.iPhones_6Plus_6sPlus_7Plus_8Plus.rawValue):
                                                  self.view.frame.origin.y -= 80
                                              case (UIDevice.ScreenType.iPhoneX_Xs.rawValue):
                                                  self.view.frame.origin.y -= 70
                                              case (UIDevice.ScreenType.iPhoneXR.rawValue):
                                                  self.view.frame.origin.y -= 70
                                              case (UIDevice.ScreenType.iPhoneXSMax.rawValue):
                                                  self.view.frame.origin.y -= 70
                                              default:
                                                  self.view.frame.origin.y -= 150
                                              }
                                          }
                                      }
                                  }
                                  
                                  @objc func keyboardWillHide(notification: NSNotification) {
                                      if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
                                          if self.view.frame.origin.y != 0 {
                                              switch (UIDevice.current.screenType.rawValue) {
                                              case (UIDevice.ScreenType.iPhones_5_5s_5c_SE.rawValue):
                                                  self.view.frame.origin.y += 210
                                              case (UIDevice.ScreenType.iPhones_6_6s_7_8.rawValue):
                                                  self.view.frame.origin.y += 110
                                              case (UIDevice.ScreenType.iPhones_6Plus_6sPlus_7Plus_8Plus.rawValue):
                                                  self.view.frame.origin.y += 80
                                              case (UIDevice.ScreenType.iPhoneX_Xs.rawValue):
                                                  self.view.frame.origin.y += 70
                                              case (UIDevice.ScreenType.iPhoneXR.rawValue):
                                                  self.view.frame.origin.y += 70
                                              case (UIDevice.ScreenType.iPhoneXSMax.rawValue):
                                                  self.view.frame.origin.y += 70
                                              default:
                                                  self.view.frame.origin.y += 150
                                              }
                                          }
                                      }
                                  }
                                  

                                  【讨论】:

                                  • 一般来说,我会说使用设备特定类型和硬编码布局相关尺寸不断变化是一种糟糕且相当昂贵的方法。
                                  猜你喜欢
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 2021-11-30
                                  • 1970-01-01
                                  • 2018-12-14
                                  • 1970-01-01
                                  • 2017-10-20
                                  相关资源
                                  最近更新 更多