首页 文章

仅在键盘覆盖输入字段时才向上移动视图

提问于
浏览
122

我正在尝试为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
}

23 回答

  • 0

    您的问题在this document by Apple中得到了很好的解释 . 此页面上的示例代码(位于 Listing 4-1 )完全符合您的需要,只有在当前编辑应位于键盘下方时才会滚动视图 . 您只需要将所需的控件放在scrollViiew中 . 唯一的问题是这是Objective-C,我认为你需要它在Swift中...所以它是:它是:

    声明一个变量

    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 并在初始化方法中设置正确的委托:ex:

    self.you_text_field.delegate = self
    

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

    编辑/更新:Swift 3.0语法

    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
        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 keyboardWillBeHidden(notification: NSNotification){
        //Once keyboard disappears, restore original positions
        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
        self.view.endEditing(true)
        self.scrollView.isScrollEnabled = false
    }
    
    func textFieldDidBeginEditing(_ textField: UITextField){
        activeField = textField
    }
    
    func textFieldDidEndEditing(_ textField: UITextField){
        activeField = nil
    }
    
  • 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
    
        return 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 .

  • 7

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

    我遇到了类似的问题,并使用scrollView找到了一个非常直接的解决方案 without ,而是在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)
        }
    }
    

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

    Shifts whole view up: 仅在编辑某些文本字段(bottomText)时

    Shifts whole view down: 仅当视图不在原始位置时

  • 18

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

  • 0

    Swift 4 (updated )延期

    • 在一个容器中添加按钮

    • 使用IBOutlet containerBtmConstrain连接容器的底部约束

    • inViewDidLoad

    self.containerDependOnKeyboardBottomConstrain = containerBtmConstrain
    self.watchForKeyboard()
    
    • 添加以下扩展名
    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!
      let keyboardFrame: CGRect = (info[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
    
      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()
      })
     }
    }
    
  • 1

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

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

    虽然activeField的起源可能在键盘上方,但maxY可能不会...

    我会为activeField创建一个'max'点并检查它是否在键盘Rect中 .

  • 1

    我使用SwiftLint,它对接受的答案的格式有一些问题 . 特别:

    冒号之前没有空格,没有强制转换,更喜欢UIEdgeInset(顶部:等等...而不是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
    }
    
  • 4

    只需使用此扩展名即可在键盘出现时移动任何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()
    
  • 0

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

    textViews的另一个要点是它们的高度可能会使键盘剪切textView的底部,如果在视图中的左上角点则不会调整 . 因此,我编写的代码实际上采用任何textView或textField的屏幕引用的Bottom-Left点,并查看它是否落在所呈现的键盘的屏幕引用坐标中,暗示键盘覆盖了它的一部分 .

    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()
    }
    
    }
    
  • 181

    在下面的示例中,我只是在开始编辑txtLastName或txtCity时向上移动视图 . 我创建了变量keyboardActive,因为如果我点击txtLastName并在txtCity之后,视图可以向上移动2倍 .

    看看它是否适合你 .

    class ViewController: UIViewController, UITextFieldDelegate {
    
       @IBOutlet weak var txtFirstName: UITextField!
       @IBOutlet weak var txtLastName: UITextField!
       @IBOutlet weak var txtCity: UITextField!
    
       var keyboardActive = false
    
       override func viewDidLoad() {
           super.viewDidLoad()
           self.txtFirstName.delegate = self
           self.txtLastName.delegate = self
           self.txtCity.delegate = self
       }
    
       func textFieldDidBeginEditing(textField: UITextField) {
          if textField != self.txtFirstName && keyboardActive == false {
              self.view.frame.origin.y -= 165
              self.keyboardActive = true
          }
       }
    
       func textFieldShouldEndEditing(textField: UITextField) -> Bool {
          if textField != self.txtFirstName && keyboardActive == true {
              self.view.frame.origin.y += 165
              self.keyboardActive = false
          }
          return true
       }
    
       func textFieldShouldReturn(textField: UITextField) -> Bool {
          self.view.endEditing(true)
          return false
       }
    
    }
    
  • 2

    在ReactNative android和IOS应用程序中这样的问题通过以下步骤解决 .

    像这样安装包 .

    $ npm install --save react-native-keyboard-spacer
    

    现在将键盘spacer插入到React Native项目中的js或jsx文件中 .

    import React, { Component } from 'react';
     import KeyboardSpacer from 'react-native-keyboard-spacer';
     import { View, Text, TextInput } from 'react-native';
    
     export default class Sample extends Component{
        render(){
           return(
               <View style={{flex: 1}}>
                  <TextInput 
                      placeholderTextColor="£000000"
                      underlineColorAndroid="transparent"
                      keyboardType="default"
                      maxLength={30}
                      placeholder={'Enter your text!'} />
    
                  <TextInput placeholder={"another text field"} />
    
                  <TextInput placeholder={"another text field"} />
    
                  {/* now place the below component after your input fields form block or view */}
    
                 <KeyboardSpacer/>
              </View>
           );
        }
     }
    

    然后解决在写入时隐藏文本字段的键盘问题 .

    Note: It will work both IOS and Android React Native apps.
    
       Hope It is helpful to others.
    
  • 2

    已经给出了很棒的答案,但这是处理这种情况的另一种方法(使用 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)
    
    }
    

    现在拿 UIViewUIViewUIView 的顶部约束如下:(这里 UIViewUIScrollView 的子视图,这意味着你的所有 subViews 应该有一个 UIScrollView

    @IBOutlet weak var loginViewTopConstraint: NSLayoutConstraint!
    

    另一个变量如跟随并添加一个委托,即 UITextFieldDelegate

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

    之后,这是神奇的部分,只需粘贴下面的代码段:

    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
    }
    

    现在最后一个片段:

    //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 中的所有 UITextField

    祝好运!

  • 111

    Swift 3 syntax:

    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”条件,但这种类型适用于所有...希望它对每个人都有用

  • 0

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

    好 . 首先确认UITextFieldDelegate协议

    class YourClass:UITextFieldDelegate
    

    然后实现该功能

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

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

  • 1

    此代码向上移动您正在编辑的文本字段,以便您可以在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
            }
        }
    }
    
  • 0

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

    被接受的anwser几乎是完美的 . 但我需要使用 UIKeyboardFrameEndUserInfoKey 而不是 UIKeyboardFrameBeginUserInfoKey, ,因为后者返回keyborad高度0.并将hittest点更改为底部而不是原点 .

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

    首先声明一个变量来标识您的活动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
    }
    
  • 0

    Swift 4 Updated my solution

    键盘上的约束动画显示/隐藏,享受 .

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

    Swift 4

    你可以轻松地上下移动 UITextField 与键盘与动画

    enter image description here

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

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

    对于swift 4.2 . 这适用于任何形式 . 不需要scrollview .

    //制作一个uitextfield变种

    var clickedTextField = UITextField()
    

    //在你的viewdid加载中

    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
    }
    

相关问题