以交互方式解除KeyBoard Bug

时间:2017-03-09 08:27:19

标签: ios swift

我的键盘被解雇有问题。每次我在键盘上向下滑动,我都有这个空白的黑色背景,我想摆脱它。我不明白为什么它在那里。这与我的tableView连接。

My keyBoard

What it looks like when I swipe Down

我将tableView上的keyBoard设置为Dismiss Interactively

//                      KeyBoard (move text box above keyboard)




    //KeyBoard - exit when the view is touched
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }



    // Start Editing The Text Field
    func textFieldDidBeginEditing(_ messageTextField: UITextField) {
        moveTextField(messageTextField, moveDistance: -215, up: true)
    }

    // Finish Editing The Text Field
    func textFieldDidEndEditing(_ messageTextField: UITextField) {
        moveTextField(messageTextField, moveDistance: -215, up: false)
    }

    // Hide the keyboard when the return key pressed
    func textFieldShouldReturn(_ messageTextField: UITextField) -> Bool {
        messageTextField.resignFirstResponder()
        return true
    }

    // Move the text field in a pretty animation!
    func moveTextField(_ messageTextField: UITextField, moveDistance: Int, up: Bool) {
        let moveDuration = 0.3
        let movement: CGFloat = CGFloat(up ? moveDistance : -moveDistance)

        UIView.beginAnimations("animateTextField", context: nil)
        UIView.setAnimationBeginsFromCurrentState(true)
        UIView.setAnimationDuration(moveDuration)
        self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
        UIView.commitAnimations()
    }

5 个答案:

答案 0 :(得分:0)

inputAccessoryView的{​​{1}}中添加您的观点

UITextField

然后像这样设置yourtextField.inputAccessoryView = yourView

tableview

enter image description here

答案 1 :(得分:0)

黑色视图是ViewController后面的视图。在moveTextField动画完成之前,由于隐藏了键盘,因此可以看到该视图,从而使黑色视图可见。

关闭动画块本身中的键盘,以使键盘与屏幕一起关闭。然后从moveTextField调用touchesBegan。您需要在以下代码中获得UITextFieldtf)的引用。另外,不要忘记处理Return键。

//KeyBoard - exit when the view is touched
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if tf.isEditing {
    moveTextField(tf, moveDistance: -215, up: false)
    }

    //        self.view.endEditing(true)
}



// Start Editing The Text Field
func textFieldDidBeginEditing(_ messageTextField: UITextField) {
    moveTextField(messageTextField, moveDistance: -215, up: true)
}

// Finish Editing The Text Field
func textFieldDidEndEditing(_ messageTextField: UITextField) {
    //        moveTextField(tf, moveDistance: -215, up: false)
}

// Hide the keyboard when the return key pressed
func textFieldShouldReturn(_ messageTextField: UITextField) -> Bool {
    //        messageTextField.resignFirstResponder()
    if tf.isEditing {
        moveTextField(tf, moveDistance: -215, up: false)
    }
    return true
}

// Move the text field in a pretty animation!
func moveTextField(_ messageTextField: UITextField, moveDistance: Int, up: Bool) {
    let moveDuration = 0.3
    let movement: CGFloat = CGFloat(up ? moveDistance : -moveDistance)

    UIView.beginAnimations("animateTextField", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(moveDuration)
    if !up {
        self.view.endEditing(true)
    }
    self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
    UIView.commitAnimations()
}

答案 2 :(得分:0)

我前段时间也遇到过类似的问题,并发现了以下方法。

首先为您的视图添加一个底部约束,并将其与VC类中的IBOutlet连接:

@IBOutlet weak var bottomConstraint: NSLayoutConstraint!

然后将通知添加到您的viewWillAppear重写函数。我相信您已经添加了手势识别器。无论如何,我在此答案的底部共享了手势识别器功能。

override func viewWillAppear(_ animated: Bool) {
    //self.addGestureRecognizer()
    // To move view when keyboard appears/hides
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillChangeFrame(notification:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}

最主要的是下面的函数。我将其添加为扩展。这个想法是当键盘向下移动时用动画来改变约束。您会看到我为iPhone 4s使用了硬编码的值(我在iPhone 4s和iOS 9上使用此解决方案时遇到了问题)。因此,如果您不支持4s模型,则可以将其删除。

extension CheckoutViewController {
    // Function to scroll view when keyboard appears/disappears
    @objc func keyboardWillChangeFrame (notification: NSNotification) {
        if let userInfo = notification.userInfo {
            let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
            let duration:TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 1
            let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
            let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue
            let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
            if (endFrame?.origin.y)! >= UIScreen.main.bounds.size.height {
                self.bottomConstraint?.constant = 0.0
            } else {
                // Keyboard is opened
                var constraintValue = endFrame?.size.height ?? 0
                if UIDevice.current.modelName != "iPhone 4s" {
                    constraintValue = constraintValue - 35
                }
                self.bottomConstraint?.constant = constraintValue
            }
            UIView.animate(withDuration: duration,
                           delay: TimeInterval(0),
                           options: animationCurve,
                           animations: { self.view.layoutIfNeeded() },
                           completion: nil)
        }
    }
}

不幸的是,目前我无法访问XCode,因此以代码为例。希望它能帮助您解决问题。

我使用的UIViewController的手势识别器扩展:

extension UIViewController {
    func addGestureRecognizer() {
        // Gesture recognizer To dismiss keyboard
        let singleTap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
        singleTap.cancelsTouchesInView = false
        singleTap.numberOfTapsRequired = 1
        self.view.addGestureRecognizer(singleTap)
    }

    @objc func handleTap(_ recognizer: UITapGestureRecognizer) {
        self.view.endEditing(false)
    }
}

答案 3 :(得分:0)

更好的解决方案

如果您已经看到ios的本机 Messaging应用,则可以通过交互手势关闭键盘。 这样,您的问题也将得到解决,因为我们没有将UIView的textview / textfield和按钮(发送)添加到subview,而是作为视图控制器的辅助视图添加

第1步:

转到Storybaord选择集合视图,然后在属性列表上将“键盘关闭”模式更改为“交互式关闭”

enter image description here

并使集合视图充满整个屏幕(不要为textField和send按钮添加空间)

第2步:

在视图控制器中,在顶部添加以下属性

var viewAcc: UIView?
var sendButton: UIButton!
var inputTextField: UITextField!

override var inputAccessoryView: UIView? {
    return viewAcc
}

override var canBecomeFirstResponder: Bool {
    return true
}

在ViewDidLoad方法中,为初始化视图添加以下代码,并添加textField和发送按钮

    viewAcc = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 44))
    viewAcc?.backgroundColor = UIColor.white
    inputTextField = UITextField (frame: CGRect(x:8, y:0, width:UIScreen.main.bounds.width, height: 44 ))
    inputTextField.inputAccessoryView = nil
    inputTextField.delegate = self as? UITextFieldDelegate
    inputTextField.placeholder = "Enter message..."
    viewAcc?.backgroundColor = .white
    viewAcc?.addSubview(inputTextField);

    let topBorderView = UIView()
    topBorderView.backgroundColor = UIColor(white: 0.5, alpha: 0.5)
    viewAcc?.addSubview(topBorderView)
    viewAcc?.addConstraintsWithFormat(format: "H:|[v0]|", views: topBorderView)
    viewAcc?.addConstraintsWithFormat(format: "V:|[v0(0.5)]", views: topBorderView)

    sendButton = UIButton(type: .system)
    sendButton.isEnabled = true
    sendButton.titleLabel?.font = UIFont.systemFont(ofSize: 16)
    sendButton.setTitle("Send", for: .normal)
    sendButton.contentEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
    sendButton.addTarget(self, action: #selector(handleSend), for: .touchUpInside)
    viewAcc?.addSubview(sendButton)

    inputTextField.translatesAutoresizingMaskIntoConstraints = false
    sendButton.translatesAutoresizingMaskIntoConstraints = false
    viewAcc?.addConstraint(NSLayoutConstraint(item: inputTextField, attribute: .left, relatedBy: .equal, toItem: viewAcc, attribute: .left, multiplier: 1, constant: 8))
    viewAcc?.addConstraint(NSLayoutConstraint(item: inputTextField, attribute: .top, relatedBy: .equal, toItem: viewAcc, attribute: .top, multiplier: 1, constant: 7.5))
    viewAcc?.addConstraint(NSLayoutConstraint(item: inputTextField, attribute: .right, relatedBy: .equal, toItem: sendButton, attribute: .left, multiplier: 1, constant: -2))
    viewAcc?.addConstraint(NSLayoutConstraint(item: inputTextField, attribute: .bottom, relatedBy: .equal, toItem: viewAcc, attribute: .bottom, multiplier: 1, constant: -8))
    viewAcc?.addConstraint(NSLayoutConstraint(item: sendButton, attribute: .right, relatedBy: .equal, toItem: viewAcc, attribute: .right, multiplier: 1, constant: 0))
    viewAcc?.addConstraint(NSLayoutConstraint(item: sendButton, attribute: .bottom, relatedBy: .equal, toItem: viewAcc, attribute: .bottom, multiplier: 1, constant: -4.5))

现在运行该应用程序,您可以在底部看到textField和按钮,还可以看到完整的集合视图。您只需按住并向下滑动即可关闭键盘

希望对您有帮助

答案 4 :(得分:0)

从视图中创建一个底部约束,您希望根据键盘向上和向下推动该约束。让我们称之为viewBottomConstraint。接下来,复制粘贴下面的代码,这是自解释的。

完成此操作后,在您的KeyboardViewPusher中创建对UIViewController实例的引用。并使用正确的值对其进行初始化。之后,您唯一要做的就是在KeyboardViewPusher出现和消失时通知ViewController实例。

仅此而已!

import UIKit

/// Be SURE to call didAppear() and disDisappear() at the right time in your viewcontroller.
open class KeyboardViewPusher {

    /// Because of 2 things we need the actual viewControllersView:
    ///     1. Because we need to call layoutIfNeeded() on this particular view to actually animate it
    ///        If we do this directly on property 'view', it doesn't animate (nice job Apple).
    ///     2. To determine the safe area bottom constant (although we can get it also through the keyWindow).
    ///        But then we need to force unwrap stuff.
    public unowned let viewControllerView: UIView

    /// This is the view to push upwards.
    public unowned let view: UIView

    /// The bottom constant.
    /// Make sure this is equal to view.bottomAnchor == viewControllerView.bottomAnchor
    public unowned let viewBottomConstraint: NSLayoutConstraint

    /// Start constant of viewBottomConstraint
    /// We need this to properly animate it back when the keyboard will hide.
    public let viewBottomConstraintConstant: CGFloat

    private let defaultAnimationDuration: TimeInterval = 0.25

    public init(viewControllerView: UIView, view: UIView, viewBottomConstraint: NSLayoutConstraint) {
        self.viewControllerView = viewControllerView
        self.view = view
        self.viewBottomConstraint = viewBottomConstraint
        viewBottomConstraintConstant = viewBottomConstraint.constant
    }

    /// Call this in the viewDidAppear() method in the viewController.
    open func didAppear() {
        addObserver()
    }

    /// Call this in the viewDidDisappear() method in the viewController.
    open func didDisappear() {
        removeObserver()
    }

    open func removeObserver() {
        NotificationCenter.default.removeObserver(self)
    }

    open func addObserver() {
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(self.keyboardWillShow(_:)),
                                               name: UIResponder.keyboardWillShowNotification,
                                               object: nil)
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(self.keyboardWillHide(_:)),
                                               name: UIResponder.keyboardWillHideNotification,
                                               object: nil)
    }

    @objc open func keyboardWillShow(_ notification: NSNotification) {
        guard let keyboardHeight = notification.determineKeyboardHeight() else { return }

        let maximumPushValue = -(keyboardHeight - viewControllerView.safeAreaInsets.bottom)

        viewBottomConstraint.constant = maximumPushValue

        UIView.animate(withDuration: notification.determineKeyboardAnimationDuration() ?? defaultAnimationDuration) {
            self.viewControllerView.layoutIfNeeded()
        }
    }

    @objc open func keyboardWillHide(_ notification: NSNotification) {
        hide(animationDuration: notification.determineKeyboardAnimationDuration() ?? defaultAnimationDuration)
    }

    // When animation with a value of 0, it doesn't actually animates it but directly layouts the view.
    // This doesn't negatively affect the performance.
    open func hide(animationDuration: TimeInterval = 0) {
        guard viewBottomConstraint.constant != viewBottomConstraintConstant else { return }

        viewBottomConstraint.constant = viewBottomConstraintConstant

        UIView.animate(withDuration: animationDuration) {
            self.viewControllerView.layoutIfNeeded()
        }
    }

    deinit {
        removeObserver()
    }
}

/// Helper extensions for the KeyboardViewPusher
public extension NSNotification {
    public func determineKeyboardHeight() -> CGFloat? {
        return (userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height
    }

    public func determineKeyboardAnimationDuration() -> TimeInterval? {
        return userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval
    }
}

我前一段时间编写了这段代码,并将其放在github:https://github.com/Jasperav/JVKeyboardViewPusher上。我认为您不能立即克隆该项目。复制粘贴上面的代码虽然具有相同的效果。