简体   繁体   English

当键盘出现Swift时发出移动视图

[英]Issue moving view when keyboard appears Swift

I am using a scroll view and auto layout to move the view when the keyboard appears and hides one of my text input elements. 我使用滚动视图和自动布局在键盘出现并隐藏我的文本输入元素之一时移动视图。 To do so I am using the below functions. 为此,我正在使用以下功能。

The issue is that I can't get it to work for both the text field and text view. 问题是我无法同时在文本字段和文本视图中使用它。 I have researched a lot and tried implementing all answers I have found on SO and other resources but most answers only deal with single text fields not multiple and I have not found a single solution for a text field and a text view. 我进行了很多研究,并尝试实现在SO和其他资源上找到的所有答案,但是大多数答案只处理单个文本字段而不是多个文本字段,并且我还没有找到针对文本字段和文本视图的单一解决方案。

I know that the below code is designed for text fields but I am trying to modify it to work with text views as well because out of all the different ways I haver seen to move the view when the keyboard appears this works the best for me. 我知道下面的代码是为文本字段设计的,但是我也试图对其进行修改以使其与文本视图一起使用,因为在键盘出现时,我已经看到了各种不同的移动视图的方式,这对我来说是最好的。

I am wondering if there is a way to get the view to move for both my text field and text view using my current code. 我想知道是否有一种方法可以使用当前代码为我的文本字段和文本视图移动视图。 Also Im wondering if this is the best way to be moving the view. 我也想知道这是否是移动视图的最佳方法。

Functions to move the view when keyboard appears: 出现键盘时移动视图的功能:

func keyboardWillShow(sender: NSNotification) {
    let info: NSDictionary = sender.userInfo!
    let value: NSValue = info.valueForKey(UIKeyboardFrameBeginUserInfoKey) as! NSValue
    let keyboardSize: CGSize = value.CGRectValue().size
    let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height + 20, 0.0)
    scrollView.contentInset = contentInsets

    var aRect: CGRect = self.view.frame
    aRect.size.height -= keyboardSize.height
    let activeTextFieldRect: CGRect? = myTextField?.frame
    let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.origin
    if (!CGRectContainsPoint(aRect, activeTextFieldOrigin!)) {
        scrollView.scrollRectToVisible(activeTextFieldRect!, animated:true)
    }
}

func keyboardWillHide(sender: NSNotification) {
    let contentInsets: UIEdgeInsets = UIEdgeInsetsZero
    scrollView.contentInset = contentInsets
}

func textFieldDidBeginEditing(textField: UITextField) {
    myTextField = textField
    scrollView.scrollEnabled = true
}

func textFieldDidEndEditing(textField: UITextField) {
    myTextField = nil
    scrollView.scrollEnabled = true
} 

I have tried implementing textViewDidBeginEditing and textViewDidEndEditing and then assigning that in place of myTextView in this line: let activeTextFieldRect: CGRect? = myTextField?.frame 我曾尝试推行textViewDidBeginEditingtextViewDidEndEditing ,然后分配到位的myTextView在这一行: let activeTextFieldRect: CGRect? = myTextField?.frame let activeTextFieldRect: CGRect? = myTextField?.frame but that seems like a sloppy way to do this and doesn't work anyway. let activeTextFieldRect: CGRect? = myTextField?.frame但这似乎是一种草率的方式,因此无法正常工作。 Any help is much appreciated. 任何帮助深表感谢。

Step one is to determine the textfield or textview which is the current first responder. 第一步是确定当前第一响应者的文本字段或文本视图。 Either use both textField and textView delegates to correctly determine the first responder or iterate through all the text fields and text views to see which is the first responder by doing something like: 可以使用textField和textView委托正确地确定第一响应者,也可以遍历所有文本字段和文本视图以执行以下操作以查看哪个是第一响应者:

func activeItemRect() -> CGRect? {
        for textField in textFields {
            if textField.isFirstResponder() { return textField.frame }
        }
        for textView in textViews{
            if textView.isFirstResponder() { return textView.frame }
        }
        return nil
    }

Step two is to determine if the current item is in the visible portion of the view or not. 第二步是确定当前项目是否在视图的可见部分中。 This you are doing by checking whether the origin of selected item is inside the visible rect of the view. 您可以通过检查所选项目的原点是否在视图的可见区域内来进行此操作。 You should be checking the centre or bottom of the selected item instead of its origin because sometimes the origin will be within the visible view rect but hidden by the iOS text input suggestions panel which appears right on top of the keyboard. 您应该检查所选项目的中心或底部,而不是其原点,因为有时原点会在可见视图rect中,但被显示在键盘顶部的iOS文本输入建议面板隐藏。

Posting below the entire code I used to test your scenario: 在用于测试您的方案的完整代码下面发布:

class ViewController: UIViewController {

    @IBOutlet var textFields: [UITextField]!
    @IBOutlet var textViews: [UITextView]!
    @IBOutlet weak var scrollView: UIScrollView!

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

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }


    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        for textField in textFields { textField.resignFirstResponder() }
        for textView in textViews{ textView.resignFirstResponder() }
    }

    func activeItemRect() -> CGRect? {
        for textField in textFields {
            if textField.isFirstResponder() { return textField.frame }
        }
        for textView in textViews{
            if textView.isFirstResponder() { return textView.frame }
        }
        return nil
    }

    func keyboardWillShow(sender: NSNotification) {
        let info: NSDictionary = sender.userInfo!
        let value: NSValue = info.valueForKey(UIKeyboardFrameBeginUserInfoKey) as! NSValue
        let keyboardSize: CGSize = value.CGRectValue().size
        let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height + 20, 0.0)
        scrollView.contentInset = contentInsets

        var aRect: CGRect = self.view.frame
        aRect.size.height -= keyboardSize.height
        let activeTextFieldRect: CGRect? = activeItemRect()
        let activeTextFieldCentre: CGPoint? = CGPointMake(CGRectGetMidX(activeTextFieldRect!), CGRectGetMidY(activeTextFieldRect!))
        if (!CGRectContainsPoint(aRect, activeTextFieldCentre!)) {
            scrollView.scrollRectToVisible(activeTextFieldRect!, animated:true)
        }
    }

    func keyboardWillHide(sender: NSNotification) {
        let contentInsets: UIEdgeInsets = UIEdgeInsetsZero
        scrollView.contentInset = contentInsets
    }

}

First I created an IBOutletCollection for all text fields. 首先,我为所有文本字段创建了一个IBOutletCollection。 Then I created an IBoutletCollection for all text views. 然后,我为所有文本视图创建了一个IBoutletCollection。 Then created method that will loop through all textFields and textViews and returns the frame of the active item. 然后创建的方法将遍历所有textFields和textViews并返回活动项目的框架。

Rest of the code is 90% similar to what you are doing. 其余代码与您正在执行的操作相似90%。 Only difference is instead of checking if the origin of selected item lies within visible portion of the view I am checking if the centre of selected item lies within the visible portion of the view. 唯一的区别是,不是检查所选项目的原点是否位于视图的可见部分内,而是检查所选项目的中心是否位于视图的可见部分内。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM