首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >当键盘向上移动时,如何使textFields保持在位置上?斯威夫特

当键盘向上移动时,如何使textFields保持在位置上?斯威夫特
EN

Stack Overflow用户
提问于 2017-03-01 22:47:54
回答 2查看 2.4K关注 0票数 1

我已经创建了一个有4个字段和一个按钮的表单。视图层次结构如下所示: Main UIVIew,view (改名为contentView),在contentView之上,我有4个字段和一个以编程方式创建的按钮。

  1. 当触发viewDidLoad时,按钮不会向上滚动,因此可以在contentView中看到。
  2. 当开始键入textFields时,textFields会在可视区域外向上滚动。
  3. 当firstResponder辞职(隐藏键盘)时,我无法滚动contentView。我会按照上面指定的顺序列出图片截图。

在此尝试之前,我将按钮放在ViewController视图上,将按钮的底部约束分配给一个变量,而当keyboardDidShow将键盘大小添加到底部约束时,就会将按钮放在键盘上方。然而,一个堆栈花说这种方法很容易出错:Move button when keyboard appears swift

我遵守了本教程,但我没有得到相同的结果。https://spin.atomicobject.com/2014/03/05/uiscrollview-autolayout-ios/

考虑到Iphone的屏幕大小不同,请给出最佳的解决方案。

代码语言:javascript
运行
复制
class EleventhViewController: UIViewController, UITextFieldDelegate {

 @IBOutlet weak var fullName: UITextField!
 @IBOutlet weak var flatNumber: UITextField!
 @IBOutlet weak var streetAddress: UITextField!
 @IBOutlet weak var phoneNumber: UITextField!
 @IBOutlet weak var contentView: UIView!
 @IBOutlet weak var scrollView: UIScrollView!
 var nextButtonOutlet:UIButton!

override func viewDidLoad() {
      super.viewDidLoad()
    //called whenever keyboard is shown/hidden
 registerForKeyboardNotifications()   

     //when identifies single or multiple taps, call DismissKeyboard
 var tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "DismissKeyboard")
    contentView.addGestureRecognizer(tap)

//create button programmatically
    var button = UIButton(type: UIButtonType.custom) as UIButton
      button = UIButton(frame: CGRect(x: 0, y: 637, width: 375, height: 50))
      button.titleLabel?.textColor = UIColor.white
      button.backgroundColor = UIColor(colorLiteralRed: 117/255, green: 232/255, blue: 0, alpha: 1)
      button.setTitle("Next", for: .normal)
      button.addTarget(self, action: #selector(EleventhViewController.nextButton), for: .touchUpInside)
       self.contentView.addSubview(button)
         self.nextButtonOutlet = button

//disable scroll bouncing
   scrollView.bounces = false

    self.fullName.delegate = self
     self.flatNumber.delegate = self
      self.streetAddress.delegate = self
         self.phoneNumber.delegate = self
 }


   //Call this function when the tap is recognized.
     func DismissKeyboard(){
       contentView.endEditing(true)
  }



     // Stop Editing on Return Key Tap. 
     func textFieldShouldReturn(_ textField: UITextField) -> Bool {
       textField.resignFirstResponder()
        return true
  }


 weak var activeField: UITextField?
 func keyboardDidShow(_ notification: Notification) {

       //when a textfield is edited lift the button above the keyboard
      if let activeField = self.activeField,let keyboardSize =      
       (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as?  
            NSValue)?.cgRectValue {
        let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 
             keyboardSize.height, right: 0.0)
               self.scrollView.contentInset = contentInsets

  var aRect = self.view.frame
     aRect.size.height -= keyboardSize.size.height

      if !aRect.contains(nextButtonOutlet.frame.origin) {
          self.scrollView.scrollRectToVisible(nextButtonOutlet.frame, animated: true)
    }
 }


  func keyboardWillHide(_ notification: Notification) {

     let contentInsets = UIEdgeInsets.zero
      self.scrollView.contentInset = contentInsets
          self.scrollView.scrollIndicatorInsets = contentInsets
}

    //Keep track of which textfield is being edited to make sure the field is visible when keyboard pops up
 func textFieldDidBeginEditing(_ textField: UITextField) {
        self.activeField = textField
 }

  func textFieldDidEndEditing(_ textField: UITextField, reason: UITextFieldDidEndEditingReason) {  
    self.activeField = nil
}

    //register for keyboard notifications
      func registerForKeyboardNotifications() {

       NotificationCenter.default.addObserver(self, selector: 
      #selector(keyboardDidShow), 
        name: NSNotification.Name.UIKeyboardDidShow, object: nil)

       NotificationCenter.default.addObserver(self, selector:    
        #selector(keyboardWillHide), name: 
         NSNotification.Name.UIKeyboardWillHide, object: nil)
  }

 //remove keyBoard observers
  func deregisterFromKeyboardNotifications() {
    NotificationCenter.default.removeObserver(self, name: 
           NSNotification.Name.UIKeyboardDidShow, object: nil)

    NotificationCenter.default.removeObserver(self, name: 
         NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(true)
    //deregister keyboard notifications
         deregisterFromKeyboardNotifications()
     }
 } //end of class

   view Hierachy

代码语言:javascript
运行
复制
   When viewDidLoad is triggered,button does not show 

开始键入textFields时

代码语言:javascript
运行
复制
When keyboard is hidden

代码语言:javascript
运行
复制
 Desired result

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-03-03 13:32:32

因此,我认为您已经接近了,我不确定这是代码问题还是自动收费问题。我猜你正在收到关于你的滚动视图的抱怨,不知道内容大小,所以我将涵盖这两个方面。

编辑:另外,您的按钮必须位于我首先添加的视图容器下面,并且需要与滚动视图分开处理。不要把它放在滚动视图中。

这些方法在下面工作,除了将50或任何东西添加到包含滚动视图的视图的布局底部。另外,下面的方法将有助于编辑

Autolayout:首先,对于只在页面上使用的表单,我喜欢从添加一个视图开始,并在顶部布局指南(按钮所需的任何空间)中添加一个视图,左和右。然后,我将我的scrollview (将滚动视图引脚到该视图)添加到视图( added.Then )中,接下来,我将内容视图添加到滚动视图中。现在,我将其固定在滚动视图上。你会发现自动收费表仍然不快乐。那么为什么第一个视图和如何解决这个问题。我从contentView拖到保持滚动视图的视图,并选择等高和等宽。现在你不会有自动布局对你尖叫。注意:这适用于您想要填充第一个视图大小的内容,但允许它滚动以避免使用键盘。见图

在添加这个等高后,我可以继续使用故事板。我设置了文本框。底部的textfield,您可能想要也可能不想将它钉在底部,但是如果您确实这样做了,>= yourNumber。

编辑:现在将您的下一个按钮添加到包含所有内容的视图下面的情节提要中。必须将按钮固定在主视图的底部,然后用0来坚持键盘。现在看起来会是这样。

显然,这与初始图像略有冲突,但您所要做的只是增加底部布局指南的空间,只需确保将按钮添加到主视图,而不是保留滚动视图的视图。现在,将您的按钮连接到iboutlet中的控制器。我们需要它。

接下来,请确保模拟器中有正确的键盘。**不使用硬件键盘

最后是密码。其中有些您需要替换textfield变量,因为我在子视图中循环以设置委托。我还在卷轴上添加了填充。应该将deRegister移动到deint()。查看我的代码,最后您可能想滚动键盘上的滚动视图,而不是原来的显示,但是我没有改变这一点。

代码语言:javascript
运行
复制
import UIKit

class ViewController: UIViewController,UITextFieldDelegate {

//added in storyboard. removed the code
@IBOutlet weak var nextButton: UIButton!

@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var contentView: UIView!
    override func viewDidLoad() {
        super.viewDidLoad()
        //called whenever keyboard is shown/hidden

        registerForKeyboardNotifications()

        //when identifies single or multiple taps, call DismissKeyboard
        var tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "DismissKeyboard")
        contentView.addGestureRecognizer(tap)

        //disable scroll bouncing
        scrollView.bounces = false

        //replace with your textfields
        for subs in self.contentView.subviews{
            if subs is UITextField{
                print("setting")
                (subs as! UITextField).delegate = self
            }
        }
    }


    //Call this function when the tap is recognized.
    func DismissKeyboard(){
        contentView.endEditing(true)
    }



    // Stop Editing on Return Key Tap.
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }

    //edited for next button
    weak var activeField: UITextField?
    func keyboardDidShow(_ notification: Notification) {

        //when a textfield is edited lift the button above the keyboard
        if let activeField = self.activeField,let keyboardSize =
            (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as?
                NSValue)?.cgRectValue {

            //20 in insets and offset is just padding
            let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom:
                keyboardSize.height + 20 + nextButton.bounds.height, right: 0.0)
            self.scrollView.contentInset = contentInsets

            var aRect = self.view.frame
            aRect.size.height -= keyboardSize.height


            let bottomPoint = CGPoint(x: activeField.frame.origin.x, y:activeField.frame.origin.y)

            if aRect.contains(bottomPoint){
                let scrollPoint = CGPoint(x: 0.0, y: bottomPoint.y - keyboardSize.height - 20 - nextButton.bounds.height)
                scrollView.setContentOffset(scrollPoint, animated: true)
            }

        }

    }
        func keyboardWillHide(_ notification: Notification) {

            let contentInsets = UIEdgeInsets.zero
            self.scrollView.contentInset = contentInsets
            self.scrollView.scrollIndicatorInsets = contentInsets
        }

        //Keep track of which textfield is being edited to make sure the field is visible when keyboard pops up
        func textFieldDidBeginEditing(_ textField: UITextField) {
            self.activeField = textField
        }


        func textFieldDidEndEditing(_ textField: UITextField, reason: UITextFieldDidEndEditingReason) {
            self.activeField = nil
        }

        //register for keyboard notifications
        func registerForKeyboardNotifications() {

            NotificationCenter.default.addObserver(self, selector:
                #selector(keyboardDidShow),
                                                   name: NSNotification.Name.UIKeyboardDidShow, object: nil)

            NotificationCenter.default.addObserver(self, selector:
                #selector(keyboardWillHide), name:
                NSNotification.Name.UIKeyboardWillHide, object: nil)
        }

        //remove keyBoard observers
        func deregisterFromKeyboardNotifications() {
            NotificationCenter.default.removeObserver(self, name: 
                NSNotification.Name.UIKeyboardDidShow, object: nil)

            NotificationCenter.default.removeObserver(self, name: 
                NSNotification.Name.UIKeyboardWillHide, object: nil)
        }



        deinit {
            //deregister keyboard notifications
            deregisterFromKeyboardNotifications()
        }
} //end of class

现在再走一步。我们得处理按钮上移的问题。不只是杀死这个控制器并在其中放置更多的处理,您可以子类底部约束来处理它。(只需确保不向底部添加顶约束。)下面是一个在项目中删除的约束。

代码语言:javascript
运行
复制
import UIKit

class AvoidingConstraint: NSLayoutConstraint {

    private var offset : CGFloat = 0
    private var keyboardVisibleHeight : CGFloat = 0

    override public func awakeFromNib() {
        super.awakeFromNib()

        offset = constant

        NotificationCenter.default.addObserver(self, selector: #selector(AvoidingConstraint.keyboardWillShowNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(AvoidingConstraint.keyboardWillHideNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    // MARK: Notification

    func keyboardWillShowNotification(_ notification: Notification) {
        if let userInfo = notification.userInfo {
            if let frameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue {
                let frame = frameValue.cgRectValue
                keyboardVisibleHeight = frame.size.height
            }

            self.updateConstant()
            switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) {
            case let (.some(duration), .some(curve)):

                let options = UIViewAnimationOptions(rawValue: curve.uintValue)

                UIView.animate(
                    withDuration: TimeInterval(duration.doubleValue),
                    delay: 0,
                    options: options,
                    animations: {
                        UIApplication.shared.keyWindow?.layoutIfNeeded()
                        return
                }, completion: { finished in
                })
            default:

                break
            }

        }

    }

    func keyboardWillHideNotification(_ notification: NSNotification) {
        keyboardVisibleHeight = 0
        self.updateConstant()

        if let userInfo = notification.userInfo {

            switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) {
            case let (.some(duration), .some(curve)):

                let options = UIViewAnimationOptions(rawValue: curve.uintValue)

                UIView.animate(
                    withDuration: TimeInterval(duration.doubleValue),
                    delay: 0,
                    options: options,
                    animations: {
                        UIApplication.shared.keyWindow?.layoutIfNeeded()
                        return
                }, completion: { finished in
                })
            default:
                break
            }
        }
    }

    func updateConstant() {
        self.constant = offset + keyboardVisibleHeight
    }

}

将其添加到项目中的文件中。然后,您所要做的就是为您在故事板中的按钮设置底部约束,将其更改为这个子类。只需确保没有顶约束。持有滚动视图的视图需要对主视图具有底部约束,而不需要为按钮留出足够的空间。运行这个项目并享受。如果这个解释还不够,请参阅测试项目链接。https://www.dropbox.com/s/ir5x324mvhhne64/ScrollView.zip?dl=0

票数 3
EN

Stack Overflow用户

发布于 2017-03-03 09:51:13

我认为只有当字段被键盘覆盖时,你才应该向上移动,就像我几天前做的那样:

代码语言:javascript
运行
复制
let keyboardScreenEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue ?? NSValue()).cgRectValue
let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window)
UIView.animate(withDuration: 0.2) {
    if notification.name == Notification.Name.UIKeyboardWillHide {
        self.view.frame = CGRect(x: 0, y: 0, width: self.view.width, height: self.view.height)
    } else {
        let offset = (self.view.frame.size.height - self.activeField.frame.maxY) - keyboardViewEndFrame.height
        if offset < 0 {
            self.view.frame = CGRect(x: 0, y:  offset, width: self.view.width, height: self.view.height)
        } else {
            self.view.frame = CGRect(x: 0, y: 0, width: self.view.width, height: self.view.height)
        }
    }
}

基本上,您只需要为键盘处理计时添加逻辑,如果键盘帧超过textfield帧,则应该处理它。希望能帮上忙。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42543593

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档