如何复制iOS Notification Center窗口的弹跳效果,该窗口会掉到屏幕底部并在没有低于窗口高度的情况下弹跳?这似乎是使用阻尼和弹簧速度,但是如何防止物体(例如在这种情况下)超出其标记并向后退回?
答案 0 :(得分:1)
更新回答:您可以构建自己的自定义转换。
假设您有两个视图控制器,StartController
和EndController
。您希望从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
。这将允许您将物理和碰撞应用于您的视图。
您可能会有一个从屏幕顶部掉落的视图,并与屏幕底部的视图发生碰撞。您需要使用UIGravityBehavior
和UICollisionBehavior
,并且应该能够调整常量以获得所需的效果。