在iOS中出现键盘时滑动UIView

时间:2016-01-05 20:23:34

标签: ios swift uiview

我知道当键盘出现在iOS上时,有很多关于滑动UIView的类似问题。但是,我似乎遇到了我未提及的实施问题。当我的幻灯片动画发生时,它不会像我期望的那样从屏幕顶部开始,而是从较低的原点开始并向后移动到屏幕的顶部。

UIView Sliding Incorrectly

这是我为实现这种上滑行为而创建的类扩展。

public extension UIViewController {

    private dynamic func keyboardWillShow(sender: NSNotification) {
        if view.frame.origin.y == 0 {
            slideViewVerticallyForKeyboardHeight(sender, directionUp: true)
        }
    }

    private dynamic func keyboardWillHide(sender: NSNotification) {
        if view.frame.origin.y < 0 {
            slideViewVerticallyForKeyboardHeight(sender, directionUp: false)
        }
    }

    private func slideViewVerticallyForKeyboardHeight(notification: NSNotification, directionUp: Bool) {
        UIView.beginAnimations(nil, context: nil)
        let keyboardHeight: CGFloat = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().height ?? 0.0
        let animationDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey]?.doubleValue ?? 0.0
        let animationCurve: Int = notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey]?.integerValue ?? 0
        UIView.setAnimationDuration(animationDuration)
        UIView.setAnimationCurve(UIViewAnimationCurve(rawValue: animationCurve)!)
        UIView.setAnimationBeginsFromCurrentState(true)

        var newFrameRect = view.frame
        if directionUp {
            newFrameRect.origin.y -= keyboardHeight
            newFrameRect.size.height += keyboardHeight
        } else {
            newFrameRect.origin.y += keyboardHeight
            newFrameRect.size.height -= keyboardHeight
        }
        view.frame = newFrameRect
        UIView.commitAnimations()
    }

    public func registerViewSlideOnKeyobard() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
    }

    public func unregisterViewSlideOnKeyboard() {
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
    }
}

我不确定我错过了什么。看着我的view.frame值,我有一个负面的起源。正如我所料。有谁看到我错过了什么?

编辑:用户aimak提出了一个非常明智的建议,即我更改为动画的(不推荐的)块调用版本。有趣的是,动画仍然被打破,但以不同的方式。以下是修改后的代码和最新动画调用所发生情况的屏幕截图。

enter image description here

private func slideViewVerticallyForKeyboardHeight(notification: NSNotification, directionUp: Bool) {
    UIView.beginAnimations(nil, context: nil)
    let keyboardHeight: CGFloat = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().height ?? 0.0
    let animationDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey]?.doubleValue ?? 0.0
    let animationCurve: UIViewAnimationCurve = UIViewAnimationCurve(rawValue: notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey]?.integerValue ?? 0)!
    var newFrameRect = view.frame
    if directionUp {
        newFrameRect.origin.y -= keyboardHeight
        newFrameRect.size.height += keyboardHeight
    } else {
        newFrameRect.origin.y += keyboardHeight
        newFrameRect.size.height -= keyboardHeight
    }

    UIView.animateWithDuration(animationDuration, delay: 0, options: animationCurve.toOptions(), animations: {
            self.view.frame = newFrameRect
        }, completion: nil)
}

2 个答案:

答案 0 :(得分:1)

这可能没有完全帮助,但是自iOS 4+以来不鼓励那些动画方法:

  

在iOS 4.0及更高版本中不鼓励使用此方法。您应该使用基于块的动画方法来指定动画。

参考:https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/clm/UIView/commitAnimations

您是否尝试过使用基于块的API?

编辑:这是自动布局问题!

好的,我想我拥有它:你使用autolayout吗?如果是这样,UIViewController.view的子视图可能具有view.top = 0的约束,并且该约束永远不会被破坏。如果您想要实现您想要的动画,请考虑:1。将每个子视图嵌入scrollView(然后为contentOffet.y更改设置动画)或2.删除/编辑您的view.top约束

答案 1 :(得分:0)

正如aimak指出的那样,问题在于我使用的是AutoLayout,而且约束覆盖了我对框架的修改。为了解决这个问题,我将所有内容都移到了scrollview中。我现在利用滚动滚动视图在键盘显示时偏移。

enter image description here

这是我必须提供滚动行为的助手类。请注意,我现在传递滚动视图。

public class KeyboardScrollViewHelper {

    private var scrollView: UIScrollView?
    private var isScrolled = false

    private dynamic func keyboardWillShow(sender: NSNotification) {
        guard !isScrolled else {
            return
        }

        slideViewVerticallyForKeyboardHeight(sender, directionUp: true)
    }

    private dynamic func keyboardWillHide(sender: NSNotification) {
        guard isScrolled else {
            return
        }

        slideViewVerticallyForKeyboardHeight(sender, directionUp: false)
    }

    private func slideViewVerticallyForKeyboardHeight(notification: NSNotification, directionUp: Bool) {

        guard let scrollView = self.scrollView else {
            return
        }

        let keyboardHeight: CGFloat = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().height ?? 0.0
        let animationDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey]?.doubleValue ?? 0.0
        let animationCurve: UIViewAnimationCurve = UIViewAnimationCurve(rawValue: notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey]?.integerValue ?? 0)!
        var scrollViewOffset: CGFloat = 0
        if directionUp {
            scrollViewOffset = scrollView.contentOffset.y + keyboardHeight
            isScrolled = true
        } else {
            scrollViewOffset =  scrollView.contentOffset.y - keyboardHeight
            isScrolled = false
        }

        scrollViewOffset = max(0, scrollViewOffset)

        UIView.animateWithDuration(animationDuration, delay: 0, options: animationCurve.toOptions(), animations: {
            scrollView.contentOffset.y = scrollViewOffset
            }, completion: nil)
    }

    public func registerViewSlideOnKeyobard(scrollView: UIScrollView) {
        self.scrollView = scrollView
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
    }

    public func unregisterViewSlideOnKeyboard() {
        scrollView?.contentOffset = CGPointZero

        scrollView = nil
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
    }
}
相关问题