【问题标题】:Issue moving view when keyboard appears Swift当键盘出现Swift时发出移动视图
【发布时间】:2023-03-08 17:28:01
【问题描述】:

我正在使用滚动视图和自动布局来在键盘出现时移动视图并隐藏我的一个文本输入元素。为此,我使用以下功能。

问题是我无法让它同时适用于文本字段和文本视图。我进行了很多研究并尝试实现我在 SO 和其他资源上找到的所有答案,但大多数答案只处理单个文本字段而不是多个文本字段,我还没有找到一个文本字段和文本视图的单一解决方案。

我知道下面的代码是为文本字段设计的,但我正在尝试修改它以使其也适用于文本视图,因为在我见过的所有不同方式中,当键盘出现时移动视图,这是最好的对我来说。

我想知道是否有一种方法可以使用我当前的代码来移动我的文本字段和文本视图的视图。我也想知道这是否是移动视图的最佳方式。

键盘出现时移动视图的功能:

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
} 

我已经尝试实现textViewDidBeginEditingtextViewDidEndEditing,然后在这一行中指定它来代替myTextViewlet activeTextFieldRect: CGRect? = myTextField?.frame,但这似乎是一种草率的方法,并且无论如何都不起作用。非常感谢任何帮助。

【问题讨论】:

    标签: ios swift user-interface textview uitextfield


    【解决方案1】:

    第一步是确定作为当前第一响应者的文本字段或文本视图。要么同时使用 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
        }
    

    第二步是确定当前项目是否在视图的可见部分。这是通过检查所选项目的原点是否在视图的可见矩形内来完成的。您应该检查所选项目的中心或底部而不是其原点,因为有时原点将在可见视图矩形内,但被显示在键盘顶部的 iOS 文本输入建议面板隐藏。

    在我用来测试您的场景的整个代码下方发布:

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

    首先,我为所有文本字段创建了一个 IBOutletCollection。 然后我为所有文本视图创建了一个 IBoutletCollection。 然后创建的方法将遍历所有 textFields 和 textViews 并返回活动项的框架。

    其余代码 90% 与您正在执行的操作相似。 唯一的区别不是检查所选项目的原点是否位于视图的可见部分内,而是检查所选项目的中心是否位于视图的可见部分内。

    【讨论】:

    • 谢谢,这听起来像是我需要的。我对在哪里实现上述功能有点困惑。另外,我是否将myTextField?.frame 行中的let activeTextFieldRect: CGRect? = myTextField?.frame 替换为包含函数返回的活动元素的变量?
    • 请参考我修改后的答案
    • 谢谢。我尝试实现这一点,但没有任何反应。您的代码看起来不错,所以一定有我遗漏的东西。你能告诉我是否应该将代码中的任何text viewstext fields 重命名为我为我设置的名称吗?除此之外,我想不出这对我不起作用的原因。
    • 在发布的示例代码中,我使用的是 IBOutletCollections。所以我没有为每个提交文本视图的文本使用变量名。您不必使用相同的方法。您还可以使用 textView 和 textField 委托来确定活动项目。问题中发布的原始代码不起作用的唯一两个原因是您已删除 textView 委托,并且您正在使用活动项目框架的原点或其中心。
    • 它不起作用,因为我最初在 viewDidLoad 中注释掉了注册键盘通知,但我忘了取消注释它们。效果很好!
    猜你喜欢
    • 2019-03-30
    • 2010-12-19
    • 2018-05-21
    • 2016-05-07
    • 1970-01-01
    • 1970-01-01
    • 2012-07-25
    • 2014-02-07
    相关资源
    最近更新 更多