了解自定义转场动画
如果您从 VCA
导航到 VCB
,则需要执行以下操作:
- 首先,您需要使用
UIViewControllerTransitioningDelegate
。
转场代理负责提供要用于自定义转换的动画控制器。指定的委托对象必须符合 UIViewControllerTransitioningDelegate
协议。
- 现在,您需要使用
UIViewControllerAnimatedTransitioning
它负责过渡,包括视图动画的持续时间和实际逻辑。
这些代理就像您处于两个 VC
之间并与它们交互一样。
为了使完整的转换成功,必须执行以下步骤:
首先,您需要使用以下方法:
- 设置
modalPresentationStyle = .custom
- 分配
transitionDelegate
属性。
在 func animateTransition(_ : )
中,您需要使用上下文 containerView
,因为您处于两个 VC
之间,所以您需要任何容器来进行任何动画,因此上下文为您提供了可以执行动画的容器。
现在,您需要 fromView
和 toView
,即 VCA.view
和 VCB.view
。现在将这两个视图添加到 containerView
中并编写动画的核心逻辑。
最后一个重要事项是在转场上下文对象上调用 completeTransition(_ :)
方法。一旦您的动画完成,必须调用此方法以让系统知道您的视图控制器已完成转换。
这是转换动画的核心基础。
我不知道 FB 动画,所以我只解释了您问题的其余部分。
参考资料
如果需要进一步的信息,请问。
代码添加
在图像选择中添加到 VC_A
var selectedImage: UIImageView?
let transition = PopAnimator()
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(
alongsideTransition: {context in
self.bgImage.alpha = (size.width>size.height) ? 0.25 : 0.55
self.positionListItems()
},
completion: nil
)
}
func positionListItems() {
let listHeight = listView.frame.height
let itemHeight: CGFloat = listHeight * 1.33
let aspectRatio = UIScreen.main.bounds.height / UIScreen.main.bounds.width
let itemWidth: CGFloat = itemHeight / aspectRatio
let horizontalPadding: CGFloat = 10.0
for i in herbs.indices {
let imageView = listView.viewWithTag(i) as! UIImageView
imageView.frame = CGRect(
x: CGFloat(i) * itemWidth + CGFloat(i+1) * horizontalPadding, y: 0.0,
width: itemWidth, height: itemHeight)
}
listView.contentSize = CGSize(
width: CGFloat(herbs.count) * (itemWidth + horizontalPadding) + horizontalPadding,
height: 0)
}
VC_B.transitioningDelegate = self
present(VC_B, animated: true, completion: nil)
extension VC_A: UIViewControllerTransitioningDelegate {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
transition.originFrame = selectedImage!.superview!.convert(selectedImage!.frame, to: nil)
transition.presenting = true
selectedImage!.isHidden = true
return transition
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
transition.presenting = false
return transition
}
}
动画类
class PopAnimator: NSObject, UIViewControllerAnimatedTransitioning {
let duration = 1.0
var presenting = true
var originFrame = CGRect.zero
var dismissCompletion: (()->Void)?
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return duration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
let toView = transitionContext.view(forKey: .to)!
let herbView = presenting ? toView : transitionContext.view(forKey: .from)!
let initialFrame = presenting ? originFrame : herbView.frame
let finalFrame = presenting ? herbView.frame : originFrame
let xScaleFactor = presenting ?
initialFrame.width / finalFrame.width :
finalFrame.width / initialFrame.width
let yScaleFactor = presenting ?
initialFrame.height / finalFrame.height :
finalFrame.height / initialFrame.height
let scaleTransform = CGAffineTransform(scaleX: xScaleFactor, y: yScaleFactor)
if presenting {
herbView.transform = scaleTransform
herbView.center = CGPoint(
x: initialFrame.midX,
y: initialFrame.midY)
herbView.clipsToBounds = true
}
containerView.addSubview(toView)
containerView.bringSubview(toFront: herbView)
UIView.animate(withDuration: duration, delay:0.0, usingSpringWithDamping: 0.4,
initialSpringVelocity: 0.0,
animations: {
herbView.transform = self.presenting ?
CGAffineTransform.identity : scaleTransform
herbView.center = CGPoint(x: finalFrame.midX,
y: finalFrame.midY)
},
completion:{_ in
if !self.presenting {
self.dismissCompletion?()
}
transitionContext.completeTransition(true)
}
)
}
}
输出:
![输入图像描述](https://istack.dev59.com/wa0AW.gif)
Github代码库:https://github.com/thedahiyaboy/TDCustomTransitions
VC_B
,它有许多字段/子视图,不仅仅是全屏imageView,但我想要一个动画,它将只显示图像(缩放)初始时,然后显示所有其他字段。这需要在实际动画之前隐藏所有对象,将图像动画到其最终框架,然后再次迭代所有对象以显示它们。对吗? - Stas IvanovVC_B
上显示图像。当图像显示后,您希望通过动画显示其他一些组件(如果我理解有误,请发送您的描述链接)。为此,首先使用 animateTransition 来动画化 VC。然后在VC_B
的ViewDidAppear
中根据您的逻辑动画化其他组件。注意: transitionAnimate 用于动画化 VC,而不是组件。 - dahiya_boy