我已经开始使用 UIViewControllerAnimatedTransitioning
协议(protocol)学习自定义过渡动画。我在 youtube 上找到的大部分视频都是基于当我们有新的 ViewController 呈现圆形动画或类似动画时的流程。
我在实现过渡方式时遇到问题。大多数情况下,我需要的是类似于 facebook 应用程序 以及它们如何打开全屏图像查看器。
那么,假设我们有 VC1
和VC2
。在 VC1
上,我们调用操作来呈现 VC2
。在两个 VC
上,我们都有相同的 UI 元素。在我的例子中是 UIImageView
。就像您在 VC1
上单击 imageView
一样,它会打开某个对象的详细信息页面,其图像位于顶部。我想要动画,看起来应该像来自 VC1
的图像正在将帧更改为来自 VC2
的图像的最终帧,然后是其他内容(如标签、按钮、等)应该出现在详细信息页面上。
但我在训练过程中遇到了一些问题。
1、首先,我不理解transitionContext
的containerView
的思想。但正如我所见,它有点像转换之间的中间状态 View 。那是对的吗?但这很奇怪
对我来说,因为即使 backgroundColor
属性也不适用于 containerView
。
2. 我不明白在转换过程中我到底需要什么动画,containerView
subview 的结构应该是什么。在我的示例中,当呈现 VC2
时,据我所知,我需要隐藏它的所有 subview 。然后将 VC1
的 imageView 动画到 VC2
的 imageView
的框架,然后再次使所有 subview 可见。那么,在这种情况下,应该将 imageView
添加到 containerView 中吗?如果是这样,那么它应该是 VC1
中的实际 imageView
,还是 imageView 的全新副本,具有相同的帧/图像,只是在过渡期间临时使用...
将我链接到具有类似动画的示例/教程/代码会很有帮助
最佳答案
了解自定义过渡动画
如果你从 VCA
导航到 VCB
然后
- 首先,您需要使用
UIViewControllerTransitioningDelegate
。
transitioning delegate 负责提供用于自定义过渡的动画 Controller 。您指定的委托(delegate)对象必须符合 UIViewControllerTransitioningDelegate
协议(protocol)。
- 现在你必须使用
UIViewControllerAnimatedTransitioning
它负责根据动画 View 的持续时间 和实际逻辑 进行转换。
这些代表的工作方式就像您在两个 VC
之间并与他们一起玩一样。
要成功完成转换,您必须执行以下步骤:
所以首先你需要使用它
- 设置
modalPresentationStyle = .custom
- 分配
transitonDelegate
属性。
- 设置
在
func animateTransition(_ : )
中你必须使用上下文containerView
因为你在两个VC 之间
所以你需要可以制作任何动画的任何容器,因此上下文为您提供了可以制作动画的容器。现在您需要
fromView
和toView
即VCA.view
和VCB.view
响应。现在将这两个 View 添加到containerView
中,编写动画核心逻辑。最后要注意的是在转换上下文对象上调用的 completeTransition(_:) 方法。动画完成后必须调用此方法,让系统知道您的 View Controller 已完成转换。
这是过渡动画的核心基础。
我不知道 FB 动画,所以我只是解释了你剩下的问题。
引用
- https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/CustomizingtheTransitionAnimations.html
- https://code.tutsplus.com/tutorials/how-to-create-custom-view-controller-transitions-and-animations--cms-25716
您可以询问任何进一步的信息。
Code Addition
关于图片选择
加入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
)
}
//position all images inside the list
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)
}
// On image selection
VC_B.transitioningDelegate = self
present(VC_B, animated: true, completion: nil)
// add extension
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)
}
)
}
}
输出:
Git-hub repo : https://github.com/thedahiyaboy/TDCustomTransitions
xcode:9.2
swift :4
关于iOS自定义转场动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44134648/