【问题标题】:Move view with keyboard using Swift使用 Swift 使用键盘移动视图
【发布时间】:2014-11-22 02:17:22
【问题描述】:

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

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

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

任何帮助将不胜感激。

【问题讨论】:

  • 最好的方法是把你的内容放在一个UIScrollView中,然后通过键盘的高度来调整滚动视图的contentInset属性当它显示时。绝对不要假设键盘高度——使用“键盘将显示”通知中的值。
  • 事实上,Apple 文档在“管理键盘”下告诉您如何执行此操作:developer.apple.com/library/ios/documentation/StringsTextFonts/…
  • 我认为下面的所有答案都没有考虑一种情况:如果您有多个文本字段并且其中一些位于屏幕顶部怎么办?每当用户点击该文本字段时,它就会超出屏幕,我很确定正确答案应该检测是否it is actually needed to scroll view up when keyboard appears
  • 这个答案能够通过检查当前正在编辑的文本字段是否与键盘占用相同的空间来检测是否真的需要在键盘出现时向上滚动视图:stackoverflow.com/a/28813720/6749410

标签: ios swift uikit nsnotificationcenter uikeyboard


【解决方案1】:

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

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
}

要解决这个问题,请将两个函数 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
    }
}

斯威夫特 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
    }
}
    

斯威夫特 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
    }
}

斯威夫特 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
    }
}

【讨论】:

  • 如果用户在键盘存在时触摸另一个文本字段,视图将被进一步向上推,这会导致黑色区域(键盘的大小) - 我们需要通过一个变量来解决这个问题跟踪键盘是否存在。例如,如果 keyboardPresent == true 则不要移动视图原点等
  • @Matthew Lin 使用布尔值,因此函数 keyboardWillShow 和 hide 只能工作一次
  • 只有一个建议,这样您就不必像我一样进行大量调试。如果您在同一屏幕上有多个 uitextfields,则键盘大小可能会有所不同(它不会根据您的设置显示对某些输入的建议),因此建议每次设置 self.view.frame.origin.y = 0你关闭键盘。例如,它会为您的电子邮件文本字段显示 sugeestions,因此键盘大小会增加,它不会显示密码字段的建议,因此键盘大小会减小。
  • 获取键盘大小时需要使用UIKeyboardFrameEndUserInfoKey而不是UIKeyboardFrameBeginUserInfoKey。目前我不确定为什么,但前者会产生更一致的结果。
  • 请将UIKeyboardFrameBeginUserInfoKey 替换为UIKeyboardFrameEndUserInfoKey。第一个给出键盘的起始帧,有时为零,而第二个给出键盘的结束帧。
【解决方案2】:

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

  1. 如果您尚未使用 Spring 动画框架,请下载 KeyboardLayoutConstraint.swift 并将文件添加(拖放)到您的项目中。
  2. 在情节提要中,为 View 或 Textfield 创建底部约束,选择约束(双击它)并在 Identity Inspector 中,将其类从 NSLayoutConstraint 更改为 KeyboardLayoutConstraint。
  3. 完成!

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

【讨论】:

  • 要选择底部约束,您也可以转到 Size Inspector,然后双击列表中的约束 - raywenderlich.com/wp-content/uploads/2015/09/…
  • 这对我来说很完美。这实际上是一个两步的过程。 1. 添加 KeyboardLayoutConstraint.swift, 2. 在故事板中,为视图或文本字段创建底部约束。注意:我删除了我的约束,只在视图或文本字段的底部添加了 1 个约束,并将其类从 NSLayoutConstraint 更改为 KeyboardLayoutConstraint。然后上面的任何视图/文本字段等我只是使用单个 KeyboardLayoutConstraint 将该项目的约束连接到该项目,结果是当键盘出现/消失时视图中的所有项目都向上/向下移动
  • 这是最好的解决方案,提供的代码不会硬编码任何值,例如动画的长度或曲线,或键盘的大小。也很容易理解。
  • 这对我有用,但我在键盘顶部和滚动视图底部之间获得了 50 像素的额外空间。我想知道这是否是由于我正在使用的安全区域底部约束。有人遇到这个吗?
  • 这是一个很棒的答案。设计也很酷。一个建议:如果您的文本视图/文本字段位于表格视图单元格上,您可能会注意到每次用户单击输入并转到下一个文本字段时,具有此约束的视图会笨拙地跳转。您可以将动画包装在 DispatchQueue.main.async {} 中以修复它。干得好!竖起大拇指!
【解决方案3】:

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

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

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

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

解决方案

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

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

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

移除观察者

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

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

根据来自 cmets 的问题更新:

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

【讨论】:

  • 在处理多个文本字段时,视图一直向上移动并且不会向下移动
  • 您将不得不更改条件以考虑文本字段
  • 感谢您的回复,我在堆栈溢出时找到了我正在寻找的答案stackoverflow.com/questions/1126726/…
  • @MugunthanBalakrishnan 感谢您提出这个问题,我已经添加了一个解决方案。
  • 大家好,有一个错误。在 viewWillDisappear 中调用后,观察者不会从视图中移除。将这一行“NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: self.view.window)”替换为“NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)”然后是观察者被移除
【解决方案4】:

不是广告、促销或垃圾邮件,只是一个很好的解决方案。我知道这个问题有近 30 个答案,我很震惊,甚至没有人提到过一次关于 this beautiful GitHub project 的事情,这一切都对你有用,甚至更好。所有的答案只是向上移动视图。我刚刚用这个 IQKeyboardManager 解决了我所有的问题。它有13000+颗星。
如果您使用 swift,只需将其添加到您的 podfile 中

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

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

【讨论】:

  • 这个确实不错,但是最新版本对我不起作用,我用的是6.2.1,在AppDelegate中导入为import IQKeyboardManager并使用IQKeyboardManager.shared().isEnabled = true
  • 这在使用多个编辑文本时非常有效,这节省了我的时间
  • 非常感谢您指出这个美妙的图书馆。这个库最终是苹果从未提供过解决方案的所有与键盘相关的废话的最终答案。现在我将把它用于我所有的项目,新的和旧的,并且节省时间和头痛,这个键盘出现,消失或不消失,或者如何隐藏它,为什么它重叠,问题一直在引起我我正在为 iPhone 编程。
  • @DhanuK,刚刚找到了这个库,并且运行良好,而且毫不费力。应用委托代码已更新为 IQKeyboardManager.shared.enable = true
  • 这个答案需要更高,更高。
【解决方案5】:

我对其中一个答案进行了一些改进,使其可以在一个页面上使用不同的键盘和不同的文本视图/字段:

添加观察者:

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

移除观察者:

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

【讨论】:

  • 此解决方案比公认的答案效果更好。接受的答案只显示键盘一次,这对我来说是一个错误:)
  • 这适用于 Xcode 10.1 和 iOS 12。接受的答案不再有效。
  • 这是一个很好的答案,我唯一要添加的是跟踪新设备(X、XS 等)中的底部安全区域,以便解决这个问题。
  • @Munib 请参阅stackoverflow.com/a/54993623/1485230 其他问题包括视图没有动画,以及没有跟随键盘高度变化。
  • 如果我的 textField 在视图顶部怎么办..?我的意思是如果有原点 Y = 0 的文本字段 ..??然后 textField 正在上升,我看不到它
【解决方案6】:

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

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
}

【讨论】:

  • 这对我有用。然而它有点生涩。我怎样才能让它顺利向上移动?还有一种方法可以仅将其应用于其中一个文本字段,因为它目前对所有人都执行此操作。 :(
  • 它可能无法与“自动布局”一起使用,因此请考虑停用它。
  • 自动布局会导致一些奇怪的行为@Josh,你错了
  • 不要这样做!你不能假设键盘有一定的尺寸。
  • 应该使用keyboardSize。当您在设备上有附件视图和不同的键盘高度时会发生什么?分离键盘?
【解决方案7】:

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

添加 UIResponder 的这个 Extension 以获取选中的 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
    }
}

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

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

    override func viewWillDisappear(_ animated: Bool) {
        self.removeKeyboardObserver()
    }

  • func viewWillAppear(_ animated: Bool)注册此通知

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

    Download Demo Here

【讨论】:

  • 这看起来是最好的解决方案,但是有几个错误。 1,文本字段向上移动,但是当我开始输入它时,它会向上跳跃一点。 2、横屏输入时textField有时会跳到左边。
  • @Darren 我正在尝试找出这些错误,但我没有找到,你能告诉我这些错误是从哪里得到的吗?我指的是哪个版本/设备......??
  • 它就像一个魅力......非常感谢朋友
  • 效果很好,但是当我在 UIView 中使用它时,它包含在 UIViewController 中嵌套在 UITabBarController 中,UIView 向上移动并且永远不会向下返回。也许我错过了一些东西。欢迎任何意见或帮助。
  • @Yisus 你能分享一个演示,以便我可以轻松检查吗?
【解决方案8】:

我看到所有答案都是通过键盘高度的值移动视图本身。好吧,我有一个详尽的答案,如果您使用约束,即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()
    }
}

【讨论】:

  • 您好,先生,您能告诉我为什么当放置在还包含 TableView 的视图中时这不起作用吗?当它包含一个 CollectionView 时,它在相同的场景中工作正常。
【解决方案9】:

对于黑屏错误 (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
    }
}

【讨论】:

  • 如果有标签栏就不行。必须计算tabbar的高度,否则键盘和view之间会出现黑屏。
  • 这不会修复键盘在 iPhone X 和更新版本上的黑色区域。每次键盘出现和消失时,主视图都会向下滑动。
【解决方案10】:

我们定义 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
    }
}

【讨论】:

  • 如果我的 textField 在视图顶部怎么办..?我的意思是如果有原点 Y = 0 的文本字段 ..??然后 textField 正在上升,我看不到它
【解决方案11】:

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

【讨论】:

  • 受 Pavle 解决方案的启发,我对其进行了升级,以自动将键盘提升一定比例的剩余可用空间,并递归地找到焦点区域以进行正确的布局。在这里抓住它:gist.github.com/noordawod/24d32b2ce8363627ea73d7e5991009a0
  • 我的标签栏也随着窗口向上移动! :(
【解决方案12】:

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

想法是:

  • 获取焦点TextField的绝对Y位置
  • 获取键盘高度
  • 获取 ScreenHeight
  • 然后计算键盘位置和文本域之间的距离(如果 向上移动视图)
  • 使用 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
}

}

【讨论】:

  • 非常好! (在 viewDidLoad 中,您有“VehiculeViewController”,而不仅仅是“ViewController”)。
  • 一个更完整和有用的答案。谢谢!我建议按如下方式调用键盘检查,因为它会给出一致的键盘大小…………if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as?NSValue)?.cgRectValue .size
【解决方案13】:

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

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

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

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

@IBOutlet private var bottomLayoutConstraint: NSLayoutConstraint!

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

代码如下:

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

【讨论】:

    【解决方案14】:

    我注意到其他答案涉及从视图中切割一些顶部。如果你想简单地调整视图大小而不剪切任何内容,试试这个方法:)

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

    【讨论】:

      【解决方案15】:

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

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

      【讨论】:

        【解决方案16】:

        类似于@Boris 的回答,但在 Swift 5 中:

        override func 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)
        }
        
        @IBAction 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
                }
            }
        }
        
        @IBAction func keyboardWillHide(notification: NSNotification) {
            if self.view.frame.origin.y != 0 {
                self.view.frame.origin.y = 0
            }
        }
        

        【讨论】:

          【解决方案17】:

          对于 Swift 3

          func textFieldDidBeginEditing(_ textField: UITextField) { // became first responder
          
              //move textfields up
              let myScreenRect: CGRect = UIScreen.main.bounds
              let keyboardHeight : CGFloat = 216
          
              UIView.beginAnimations( "animateView", context: nil)
              var movementDuration:TimeInterval = 0.35
              var needToMove: CGFloat = 0
          
              var frame : CGRect = self.view.frame
              if (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height > (myScreenRect.size.height - keyboardHeight - 30)) {
                  needToMove = (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height) - (myScreenRect.size.height - keyboardHeight - 30);
              }
          
              frame.origin.y = -needToMove
              self.view.frame = frame
              UIView.commitAnimations()
          }
          
          func textFieldDidEndEditing(_ textField: UITextField) {
              //move textfields back down
              UIView.beginAnimations( "animateView", context: nil)
              var movementDuration:TimeInterval = 0.35
              var frame : CGRect = self.view.frame
              frame.origin.y = 0
              self.view.frame = frame
              UIView.commitAnimations()
          }
          

          【讨论】:

            【解决方案18】:

            当打开键盘时,它对所有 Guy 的更新 Tableview 高度的 100% 完美答案

            对于 Swift4.2

               override func viewDidLoad() {
                  super.viewDidLoad()
                  NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
            
                  NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
               }
            
               @objc func keyboardWillShow(notification: NSNotification) {
                if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
            
                    var userInfo = notification.userInfo!
                    var keyboardFrame:CGRect = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
                    keyboardFrame = self.view.convert(keyboardFrame, from: nil)
            
                    var contentInset:UIEdgeInsets = self.tbl.contentInset
                      contentInset.bottom = keyboardFrame.size.height
                      self.tbl.contentInset = contentInset
                }
            }
            
               @objc func keyboardWillHide(notification: NSNotification) {
                if ((notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
                    let contentInset:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
                    self.tbl.contentInset = contentInset
                }
            }
            

            Swift3.2

                override func viewDidLoad() {
                      super.viewDidLoad()
            
                       NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
            
                       NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
                }
                func keyboardWillShow(notification: NSNotification) {
                     if ((notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
                     //self.view.frame.origin.y -= keyboardSize.height
                     var userInfo = notification.userInfo!
                     var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
                      keyboardFrame = self.view.convert(keyboardFrame, from: nil)
            
                      var contentInset:UIEdgeInsets = self.tbl.contentInset
                      contentInset.bottom = keyboardFrame.size.height
                      self.tbl.contentInset = contentInset
            
                   }
                }
            
                func keyboardWillHide(notification: NSNotification) {
                     if ((notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
                     let contentInset:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
                     self.tbl.contentInset = contentInset
                     }
                }
            

            【讨论】:

            • 这是最好的答案。 tbl 应该是 tableView 并且我添加了一些填充: contentInset.bottom = keyboardFrame.size.height + 10
            【解决方案19】:

            斯威夫特 4:

            我在接受最多的答案时遇到了问题,其中隐藏键盘并没有将视图一直返回到页面底部(仅部分)。这对我有用(+为 Swift 4 更新)。

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

            【讨论】:

            • 如果我的 textField 在视图顶部怎么办..?我的意思是如果有原点 Y = 0 的文本字段 ..??然后 textField 正在上升,我看不到它
            【解决方案20】:

            这是我的解决方案(实际上,此代码适用于视图中文本字段较少的情况,也适用于只有一个文本字段的情况)

            class MyViewController: UIViewController, UITextFieldDelegate {
            
            @IBOutlet weak var firstTextField: UITextField!
            @IBOutlet weak var secondTextField: UITextField!
            
            var activeTextField: UITextField!
            var viewWasMoved: Bool = false
            
            
            override func viewDidLoad() {
                super.viewDidLoad()
                NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PrintViewController.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
                NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PrintViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
            }
            
            override func viewDidDisappear(animated: Bool) {
                super.viewWillDisappear(animated)
                NSNotificationCenter.defaultCenter().removeObserver(self)
            }
            
            func textFieldDidBeginEditing(textField: UITextField) {
                self.activeTextField = textField
            }
            
            func textFieldDidEndEditing(textField: UITextField) {
                self.activeTextField = nil
            }
            
            func textFieldShouldReturn(textField: UITextField) -> Bool {
                textField.resignFirstResponder()
                return true
            }
            
            
            func keyboardWillShow(notification: NSNotification) {
            
                let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
            
                var aRect: CGRect = self.view.frame
                aRect.size.height -= keyboardSize!.height
            
                let activeTextFieldRect: CGRect? = activeTextField?.frame
                let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.origin
            
                if (!CGRectContainsPoint(aRect, activeTextFieldOrigin!)) {
                    self.viewWasMoved = true
                    self.view.frame.origin.y -= keyboardSize!.height
                } else {
                    self.viewWasMoved = false
                }
            }
            
            func keyboardWillHide(notification: NSNotification) {
                if (self.viewWasMoved) {
                    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
                        self.view.frame.origin.y += keyboardSize.height
                    }
                }
            }
            

            【讨论】:

            • 不要忘记将 Delegate 设置为 textFields
            • 更改键盘中的条件将显示为 if (!CGRectContainsPoint(aRect, newOrgin!) && !self.viewWasMoved)
            • 重置框架时添加 self.viewWasMoved = false
            【解决方案21】:

            为 Swift 3 更新...

            正如其他人所说,您需要在控制器的 viewDidLoad() 方法中添加通知观察者,如下所示:

            NotificationCenter.default.addObserver(forName: .UIKeyboardWillShow, object: nil, queue: nil)
                { notification in
                self.keyboardWillShow(notification)
                }
            
            NotificationCenter.default.addObserver(forName: .UIKeyboardWillHide, object: nil, queue: nil)
                { notification in
                self.keyboardWillHide(notification)
                }
            
            NotificationCenter.default.addObserver(forName: .UIKeyboardDidShow, object: nil, queue: nil)
                { _ in
                self.enableUserInteraction()
                }
            
            NotificationCenter.default.addObserver(forName: .UIKeyboardDidHide, object: nil, queue: nil)
                { _ in
                self.enableUserInteraction()
                }
            

            记得在适当的地方删除你的观察者(我在 viewWillDisappear() 方法中这样做)

            NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
            NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
            NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidShow, object: nil)
            NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidHide, object: nil)
            

            然后,实现您的显示和隐藏方法 - 注意告诉应用忽略交互事件的行 (beginIgnoringInteractionEvents)。这很重要,因为没有它,用户可能会点击字段甚至滚动视图并导致第二次发生转变,从而导致可怕的 UI 故障。在键盘显示和隐藏之前忽略交互事件将防止这种情况发生:

            func keyboardWillShow(notification: Notification)
                {
                if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
                    {
                    UIApplication.shared.beginIgnoringInteractionEvents()
                    self.view.frame.origin.y -= keyboardSize.height
                    // add this line if you are shifting a scrollView, as in a chat application
                    self.timelineCollectionView.contentInset.top += keyboardSize.height
                    }
                }
            
            func keyboardWillHide(notification: Notification)
                {
                if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
                    {
                    UIApplication.shared.beginIgnoringInteractionEvents()
                    self.view.frame.origin.y += keyboardSize.height
                    // add this line if you are shifting a scrollView, as in a chat application
                    self.timelineCollectionView.contentInset.top -= keyboardSize.height
                    }
                }
            

            最后,重新启用用户交互(请记住,此方法在键盘 didShow 或 didHide 之后触发):

            func enableUserInteraction()
                {
                UIApplication.shared.endIgnoringInteractionEvents()
                }
            

            【讨论】:

              【解决方案22】:

              Swift 3 代码

              var activeField: UITextField?
              
              override func viewDidLoad() {
                  super.viewDidLoad()
              
                  NotificationCenter.default.addObserver(self, selector: #selector(ProfileViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
                  NotificationCenter.default.addObserver(self, selector: #selector(ProfileViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
              }
              
              func textFieldDidBeginEditing(_ textField: UITextField){
                  activeField = textField
              }
              
              func textFieldDidEndEditing(_ textField: UITextField){
                  activeField = nil
              }
              
              func keyboardWillShow(notification: NSNotification) {
                  if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
                      if (self.activeField?.frame.origin.y)! >= keyboardSize.height {
                          self.view.frame.origin.y = keyboardSize.height - (self.activeField?.frame.origin.y)!
                      } else {
                          self.view.frame.origin.y = 0
                      }
                  }
              }
              
              func keyboardWillHide(notification: NSNotification) {
                  self.view.frame.origin.y = 0
              }
              

              【讨论】:

                【解决方案23】:

                如果您在同一个 VC 上有 2 个或更多文本字段,并且用户点击其中一个,然后点击另一个,而不调用函数 keyboardWillHide,则视图会再向上一次,这不是必要的,因为您将拥有键盘、具有键盘高度的空白空间,然后是视图,使用我编辑的答案中的代码:

                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) {
                    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
                        self.view.frame.origin.y += keyboardSize.height
                    }
                }
                

                要解决这个问题,请将“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 let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
                        if view.frame.origin.y != 0 {
                            self.view.frame.origin.y += keyboardSize.height
                        }
                    }
                }
                

                【讨论】:

                • 如果我的 textField 在视图顶部怎么办..?我的意思是如果有原点 Y = 0 的文本字段 ..??然后 textField 正在上升,我看不到它
                【解决方案24】:

                @Boris 的解决方案非常好,但视图有时会损坏。

                为了完美对齐,请使用以下代码

                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 let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
                    if self.view.frame.origin.y != 0{
                        self.view.frame.origin.y = 0 
                    }
                } }
                

                【讨论】:

                  【解决方案25】:

                  这个视频教程是最好的。 7分钟长,它会很有意义。当您有多个文本字段并希望滚动视图在点击该特定文本字段时移动“x”个像素时,这样一个简单的解决方案。

                  https://youtu.be/VuiPGJOEBH4

                  只需以下步骤:

                  - 将所有文本字段放在限制在视图边缘的滚动视图中。

                  -将所有文本字段和滚动视图作为代表连接到视图控制器。

                  -使用 IBOutlet 连接所有文本字段和滚动视图。

                  class ViewController: UIViewController, UITextFieldDelegate {
                  

                  -将 UITextFieldDelegate 协议添加到您的类中

                  @IBOutlet var stateAddress: UITextField!
                  @IBOutlet var zipAddress: UITextField!
                  @IBOutlet var phoneNumber: UITextField!
                  @IBOutlet var vetEmailAddress: UITextField!    
                  @IBOutlet weak var scrollView: UIScrollView!
                  

                  -将 UITextFieldDelegate 方法添加到您的 swift 文件中:

                  func textFieldShouldReturn(textField: UITextField) -> Bool {
                  
                      textField.resignFirstResponder()
                      return true
                  }
                  
                  
                  func textFieldDidBeginEditing(textField: UITextField) {
                  
                      if (textField == self.stateAddress) {
                          scrollView.setContentOffset(CGPointMake(0, 25), animated: true)
                      }
                      else if (textField == self.zipAddress) {
                          scrollView.setContentOffset(CGPointMake(0, 57), animated: true)
                      }
                      else if (textField == self.phoneNumber) {
                          scrollView.setContentOffset(CGPointMake(0, 112), animated: true)
                      }
                      else if (textField == self.vetEmailAddress) {
                          scrollView.setContentOffset(CGPointMake(0, 142), animated: true)
                      }
                  }
                  
                  func textFieldDidEndEditing(textField: UITextField) {
                  
                      scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
                  }
                  

                  第一种方法只是激活键盘上的返回按钮以关闭键盘。第二个是当您点击任何特定的文本字段然后设置滚动视图滚动距离的 y 偏移量(我的基于我的视图控制器 25,57,112,142 上的 y 位置)。最后一个说当你离开键盘时,滚动视图会回到原来的位置。

                  我通过这种方式使我的视图像素完美!

                  【讨论】:

                    【解决方案26】:

                    这个功能已经内置在 Ios 中,但是我们需要在外部完成。
                    插入以下代码
                    * 当 textField 在键盘下时移动视图,
                    * textField 在键盘上方时不移动视图
                    * 需要时根据键盘高度移动视图。
                    这在所有情况下都有效并经过测试。

                    import UIKit
                    
                    class NamVcc: UIViewController, UITextFieldDelegate
                    {
                        @IBOutlet weak var NamTxtBoxVid: UITextField!
                    
                        var VydTxtBoxVar: UITextField!
                        var ChkKeyPadDspVar: Bool = false
                        var KeyPadHytVal: CGFloat!
                    
                        override func viewDidLoad()
                        {
                            super.viewDidLoad()
                    
                            NamTxtBoxVid.delegate = self
                        }
                    
                        override func viewWillAppear(animated: Bool)
                        {
                            NSNotificationCenter.defaultCenter().addObserver(self,
                                selector: #selector(TdoWenKeyPadVyd(_:)),
                                name:UIKeyboardWillShowNotification,
                                object: nil);
                            NSNotificationCenter.defaultCenter().addObserver(self,
                                selector: #selector(TdoWenKeyPadHyd(_:)),
                                name:UIKeyboardWillHideNotification,
                                object: nil);
                        }
                    
                        func textFieldDidBeginEditing(TxtBoxPsgVar: UITextField)
                        {
                            self.VydTxtBoxVar = TxtBoxPsgVar
                        }
                    
                        func textFieldDidEndEditing(TxtBoxPsgVar: UITextField)
                        {
                            self.VydTxtBoxVar = nil
                        }
                    
                        func textFieldShouldReturn(TxtBoxPsgVar: UITextField) -> Bool
                        {
                            self.VydTxtBoxVar.resignFirstResponder()
                            return true
                        }
                    
                        override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
                        {
                            view.endEditing(true)
                            super.touchesBegan(touches, withEvent: event)
                        }
                    
                        func TdoWenKeyPadVyd(NfnPsgVar: NSNotification)
                        {
                            if(!self.ChkKeyPadDspVar)
                            {
                                self.KeyPadHytVal = (NfnPsgVar.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().height
                    
                                var NonKeyPadAraVar: CGRect = self.view.frame
                                NonKeyPadAraVar.size.height -= self.KeyPadHytVal
                    
                                let VydTxtBoxCenVal: CGPoint? = VydTxtBoxVar?.frame.origin
                    
                                if (!CGRectContainsPoint(NonKeyPadAraVar, VydTxtBoxCenVal!))
                                {
                                    self.ChkKeyPadDspVar = true
                                    UIView.animateWithDuration(1.0,
                                        animations:
                                        { self.view.frame.origin.y -= (self.KeyPadHytVal)},
                                        completion: nil)
                                }
                                else
                                {
                                    self.ChkKeyPadDspVar = false
                                }
                            }
                    
                        }
                    
                        func TdoWenKeyPadHyd(NfnPsgVar: NSNotification)
                        {
                            if (self.ChkKeyPadDspVar)
                            {
                                self.ChkKeyPadDspVar = false
                                UIView.animateWithDuration(1.0,
                                    animations:
                                    { self.view.frame.origin.y += (self.KeyPadHytVal)},
                                    completion: nil)
                            }
                        }
                    
                        override func viewDidDisappear(animated: Bool)
                        {
                            super.viewWillDisappear(animated)
                            NSNotificationCenter.defaultCenter().removeObserver(self)
                            view.endEditing(true)
                            ChkKeyPadDspVar = false
                        }
                    }
                    

                    |::|有时视图会下降,在这种情况下使用高度 +/- 150 :

                        NonKeyPadAraVar.size.height -= self.KeyPadHytVal + 150
                    
                        { self.view.frame.origin.y -= self.KeyPadHytVal  - 150},
                                        completion: nil)
                    
                        { self.view.frame.origin.y += self.KeyPadHytVal  - 150},
                                    completion: nil)
                    

                    【讨论】:

                      【解决方案27】:
                      func keyboardWillShow(notification: NSNotification) {
                      
                          if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
                              self.view.frame.origin.y = self.view.frame.height - (self.view.frame.height + keyboardSize.height)
                          }
                      
                      }
                      
                      func keyboardWillHide(notification: NSNotification) {
                              self.view.frame.origin.y = 0
                      }
                      

                      它必须更稳定

                      【讨论】:

                        【解决方案28】:
                         override func viewWillAppear(animated: Bool)
                         {
                         super.viewWillAppear(animated)
                        
                         NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
                         NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
                        
                         }
                        
                         // MARK: - keyboard
                         func keyboardWillShow(notification: NSNotification) 
                        {
                        
                        if let userInfo = notification.userInfo {
                        if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
                        let contentInsets = self.tblView.contentInset as UIEdgeInsets
                        self.tblView.contentInset = UIEdgeInsets(top: contentInsets.top, left: contentInsets.left, bottom: keyboardSize.height, right:contentInsets.right)
                                            // ...
                                        } else {
                                            // no UIKeyboardFrameBeginUserInfoKey entry in userInfo
                                        }
                                    } else {
                                        // no userInfo dictionary in notification
                                    }
                                }
                        
                        func keyboardWillHide(notification: NSNotification) 
                        {
                        let contentInsets = self.tblView.contentInset as UIEdgeInsets
                        self.tblView.contentInset = UIEdgeInsets(top: contentInsets.top, left: contentInsets.left, bottom: 0, right:contentInsets.right)
                         }
                        

                        【讨论】:

                          【解决方案29】:

                          使用以下代码在 UITextField Clicked 上查看 Up

                          func textFieldDidBeginEditing(textField: UITextField) {
                              ViewUpanimateMoving(true, upValue: 100)
                          }
                          func textFieldDidEndEditing(textField: UITextField) {
                              ViewUpanimateMoving(false, upValue: 100)
                          }
                          func ViewUpanimateMoving (up:Bool, upValue :CGFloat){
                              var durationMovement:NSTimeInterval = 0.3
                              var movement:CGFloat = ( up ? -upValue : upValue)
                              UIView.beginAnimations( "animateView", context: nil)
                              UIView.setAnimationBeginsFromCurrentState(true)
                              UIView.setAnimationDuration(durationMovement)
                              self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
                              UIView.commitAnimations()
                          }
                          

                          【讨论】:

                            【解决方案30】:

                            我做了一个cocoapod来简化事情:

                            https://github.com/xtrinch/KeyboardLayoutHelper

                            使用方法:

                            创建一个自动布局底部约束,在模块 KeyboardLayoutHelper 中给它一个 KeyboardLayoutConstraint 类,Pod 会做必要的工作来增加它以适应出现和消失的键盘。有关如何使用它的示例,请参见示例项目(我制作了两个:scrollView 中的 textFields,以及带有两个基本视图的垂直居中的 textFields - 登录和注册)。

                            底部布局约束可以是容器视图,textField 本身,任何东西,你可以命名它。

                            【讨论】:

                              猜你喜欢
                              • 2015-12-14
                              • 2018-07-19
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2012-02-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2023-03-08
                              相关资源
                              最近更新 更多