视图向上移动特定的文本字段委托

时间:2017-08-09 15:41:46

标签: swift uitextfield

我必须使用标记

在Swift 3.0中的UIView仅移动到下面提到的委托方法中的UITextField
func textFieldDidBeginEditing(_ textField: UITextField) {
    if (textField.tag == 4){
        //UIView Up
    }
}

func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
    if (textField.tag == 4){
        //UIView Down 
    }
    return true
}

我尝试了很多代码,但没有一个像通知那样工作,等等。

2 个答案:

答案 0 :(得分:0)

您需要将Observers添加到NotificationCenter,以便在键盘向上向下时听取两者(我假设您的< em> textfield outlet是lastTextField,这个例子可以工作,但这显然必须适应你为它提供的任何名称)

IBOutlet weak var passwordTextField: UITextField!

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

(上面的代码可以添加到viewDidLoad()

然后添加要在这些通知到达时执行的方法,如下所示:

func keyboardWillShow(_ notification:Notification) {
    if view.frame.origin.y >= 0 && lastTextField.isFirstResponder {
        view.frame.origin.y -= getKeyboardHeight(notification)
    }
}

func keyboardWillHide(_ notification:Notification) {
    if view.frame.origin.y < 0 {
        view.frame.origin.y += getKeyboardHeight(notification)
    }
}

这些方法中的验证可防止双重执行,例如在 textfields 之间移动时向上/向下移动两次而不会重新启动第一响应者,这在您的情况下很常见(我假设您为表单执行此操作因此澄清你只需要第四个文本字段)。请注意,我只是在lastTextField方法中对指定的文本字段(带有其出口keyboardWillShow)进行验证,这样如果您在键盘显示时移动另一个文本字段并在其中重新响应响应者在哪种情况下,即使它不是您开始的原始位置,当隐藏键盘时,视图将返回其原始位置。

你还需要一种方法来获得键盘的高度,这可以帮助你:

func getKeyboardHeight(_ notification:Notification) -> CGFloat {
    let userInfo = notification.userInfo
    let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue // of CGRect
    return keyboardSize.cgRectValue.height
}

让我知道它是怎么回事,但我只是在我的应用程序上测试了相同的代码,它可以正常工作,所以你应该没问题。

PS:密切关注故事板(如果您正在使用它),并且 textfields delegate已正确设置。

答案 1 :(得分:0)

您要解决的问题相当复杂,因为它要求您:

  1. 找到textField,它是firstResponder
  2. 计算TextField相对于它的superViews
  3. 的位置
  4. 确定动画的距离,以便包含 superview不会跳出窗外,也不会跳 多/反复
  5. 为正确的superView设置动画。
  6. 正如你所看到的那样......它非常适合算法。但幸运的是,我可以提供帮助。但是,这仅适用于具有以下布局的层次结构:

    superView(view的情况下为UIViewController)&gt; (N)containerSubviews&gt;文本框

    其中N是整数

    或以下:

    superView(view的情况下为UIViewController)&gt;文本框

    想法是根据textField的firstResponser为superView设置动画,并计算它在屏幕内部的位置是否意味着它被键盘部分/完全阻挡,或者它没有被定位你想要编辑。当键盘以任意方式显示时,简单地向上移动superView的优点是,textField可能无法正确定位(即;被状态栏阻挡),以及文本字段位于ScrollView中的情况/ TableView或CollectionView,您只需将texfield滚动到您想要的位置即可。这允许您计算所需的位置。

    首先,你需要一个解析给定superView的方法,并查找它的哪个子视图isFirstResponder:

    func findActiveTextField(subviews : [UIView], textField : inout UITextField?) {
    
            for view in subviews {
                if let tf = view as? UITextField {
                    guard !tf.isFirstResponder else {
                        textField = tf; break
                        return
                    }
                } else if !subviews.isEmpty {
                    findActiveTextField(subviews: view.subviews, textField: &textField)
                }
            }
        }
    

    其次,要提升通知方法,还要制作管理实际动画的方法:

    func moveFromDisplace(view: UIView, keyboardheight: CGFloat, comp: @escaping (()->())) {
    
            //You check to see if the view passed is a textField.
            if let texty = view as? UITextField {
    
                //Ideally, you set some variables to animate with.
    
                //Next step, you determine which textField you're using.
    
                if texty == YourTextFieldA {
                    UIView.animate(withDuration: 0.5, animations: {
                        self./*the proper superView*/.center.y = //The value needed
                    })
                    comp()
                    return
                }
                if texty == YourTextFieldB {
                   // Now, since you know which textField is FirstResponder, you can calculate for each textField, if they will be cropped out by the keyboard or not, and to animate the main view up accordingly, or not if the textField is visible at the time the keyboard is called.
    
                    UIView.animate(withDuration: 0.5, animations: {
                        self./*the proper superView*/.center.y = //The Value needed
                    })
                    comp()
                    return
                }
    
    
            }
        }
    

    最后,该方法与keyboardWillShow key的通知相关联;在这种情况下,我有一个UIViewController,带有一个名为profileFlow的可选视图,其中包含一堆UITextFields

    func searchDisplace(notification: NSNotification) {
            guard let userInfo:NSDictionary = notification.userInfo as NSDictionary else { return }
            guard let keyboardFrame:NSValue = userInfo.value(forKey: UIKeyboardFrameEndUserInfoKey) as? NSValue else { return }
            let keyboardRectangle = keyboardFrame.cgRectValue
            let keyboardHeight = keyboardRectangle.height
            let keybheight = keyboardHeight
            var texty : UITextField? //Here is the potential textfield
            var search : UISearchBar? //In my case, i also look out for searchBars.. So ignore this.
    
            guard let logProfile = profileFlow else { return }
            findActiveTextField(subviews: [logProfile], textField: &texty)
            //Check if the parsing method found anything...
            guard let text = texty else {
                //Found something.. so determine if it should be animated..
                moveFromDisplace(view: searchy, keybheight: keybheight, comp: {
                    value in
                    search = nil
                })
    
                return
            }
            //Didn't find anything..
        }
    

    最后,你将这整个逻辑与通知联系起来:

    NotificationCenter.default.addObserver(self, selector: #selector(searchDisplace(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    

    我无法为代码提供更多内容,因为这完全取决于您的视图层次结构以及您希望动画制作的方式。所以你可以自己解决这个问题。

    侧面说明,通常情况下,如果您有足够多的文本字段可以正确布局,则意味着它们会超出屏幕的长度。您可能会简化布局。使这种算法更好的一种方法是确保将所有文本字段放在一个包含视图的位置,这在使用AutoLayout约束时会再次变得很重。可能的情况是,如果你处于这种情况,你可以负担得起添加几个视图的流量等。 还有一个事实是,我从来没有真正需要将它用于iPhone视图,更多用于iPad视图,甚至仅用于大型表格(电子商务)。因此,如果您不在该类别中,则可能值得检查您的布局。

    另一种解决方法是使用我的方法,但是如果您只有少量文本字段,则可以在findActiveTextField()方法中检查特定的textField,并在findActiveTextField()内为动画设置动画为好吧,如果你知道他们可能在的所有可能的位置。

    无论哪种方式,我都会在这种情况下使用inout parameters,如果你问我,还有值得关注的事情。