如何复制iOS通知中心窗口中显示的放置/反弹动画效果?

时间:2017-09-19 00:34:42

标签: ios uianimation

如何复制iOS Notification Center窗口的弹跳效果,该窗口会掉到屏幕底部并在没有低于窗口高度的情况下弹跳?这似乎是使用阻尼和弹簧速度,但是如何防止物体(例如在这种情况下)超出其标记并向后退回?

2 个答案:

答案 0 :(得分:1)

更新回答:您可以构建自己的自定义转换。

假设您有两个视图控制器,StartControllerEndController。您希望从StartController到EndController进行此自定义转换。

1)创建自定义过渡对象,如下所示:

class CustomSlideTransition: NSObject, UIViewControllerAnimatedTransitioning {

    var duration: Double = 1.0

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

        // Access EndController

        let toViewController = transitionContext.viewController(forKey: .to) as! EndController

        // Access the container view :

        let containerView = transitionContext.containerView

        // Move EndController's view frame:

        toViewController.view.frame.origin.y -= UIScreen.main.bounds.size.height

        containerView.addSubview(toViewController.view)

        // Adjust the properties of the spring to what fits your needs the most:

        UIView.animate(withDuration: duration, delay: 0.0, usingSpringWithDamping: 0.2, initialSpringVelocity: 7.0, options: [.curveEaseInOut], animations: {

            // Get your EndController's view frame moves back to its final position

            toViewController.view.frame.origin.y += UIScreen.main.bounds.size.height

        }, completion: { (finished) in

            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        })
    }   
}

2)在StartController的prepareForSegue方法中,将委托设置为self

class StartController: UIViewController {

    // ...

    // MARK: PrepareForSegue

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        if let destinationController = segue.destination as? EndController {

            destinationController.transitioningDelegate = self

        }

    }

    // ...

}

3)使StartController符合UIViewControllerTransitioningDelegate

extension StartController: UIViewControllerTransitioningDelegate {

    // MARK: UIViewControllerTransitioningDelegate

    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return CustomSlideTransition()
    }

}

4)根据需要设计您的EndController!

注意:您可能还想添加一个自定义转换来解除EndController。

更新:现在,如果您真的不希望视图控制器在窗口外反弹一点,那么在这里使用spring可能不是最好的方法。 因为在iPhone上弹跳效果“功率”是使用滑动(从顶部)偏移计算的,您可能希望使用关键帧动画自定义更多动画块,或者UIKIT Dynamics如果您感觉舒服。 / p>

UIView.animate(withDuration: duration, animations: {

    toViewController.view.frame.origin.y += UIScreen.main.bounds.size.height

}, completion: { (finished) in

    // Create a custom bounce effect that doesn't go beyond the window (ie. only negative values)

    let animation = CAKeyframeAnimation(keyPath: "transform.translation.y")
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
    animation.duration = 0.75
    animation.autoreverses = false

    // Depending on how you would like to present EndController, you may want to change the hardcoded values below.
    // For example you could make it so that if the user swipes really fast, it would bounce even more..

    animation.values = [0, -60, 0, -25, 0]

    // Add the key frame animation to the view's layer :

    toViewController.view.layer.add(animation, forKey: "bounce")

    transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})

答案 1 :(得分:1)

查看UIKitDynamics。这将允许您将物理和碰撞应用于您的视图。

您可能会有一个从屏幕顶部掉落的视图,并与屏幕底部的视图发生碰撞。您需要使用UIGravityBehaviorUICollisionBehavior,并且应该能够调整常量以获得所需的效果。