我正在使用类似于Mail.app的开放草案行为的UIPresentationController子类。当呈现视图控制器时,它不会一直到顶部,并且呈现视图控制器会向下缩小,就好像它正在回落一样。
它的基本要点如下:
class CustomPresentationController : UIPresentationController {
// Create a 40pt space above the view.
override func frameOfPresentedViewInContainerView() -> CGRect {
let frame = super.frameOfPresentedViewInContainerView()
let insets = UIEdgeInsets(top: 40, left: 0, bottom: 0, right: 0)
return UIEdgeInsetsInsetRect(frame, insets)
}
// Scale down when expanded is true, otherwise identity.
private func setScale(expanded expanded: Bool) {
if expanded {
let fromMeasurement = presentingViewController.view.bounds.width
let fromScale = (fromMeasurement - 30) / fromMeasurement
presentingViewController.view.transform = CGAffineTransformMakeScale(fromScale, fromScale)
} else {
presentingViewController.view.transform = CGAffineTransformIdentity
}
}
// Scale down alongside the presentation.
override func presentationTransitionWillBegin() {
presentingViewController.transitionCoordinator()?.animateAlongsideTransition({ context in
self.setScale(expanded: true)
}, completion: { context in
self.setScale(expanded: !context.isCancelled())
})
}
// Scale up alongside the dismissal.
override func dismissalTransitionWillBegin() {
presentingViewController.transitionCoordinator()?.animateAlongsideTransition({ context in
self.setScale(expanded: false)
}, completion: { context in
self.setScale(expanded: context.isCancelled())
})
}
// Fix the scaled view's frame on orientation change.
override func containerViewWillLayoutSubviews() {
super.containerViewWillLayoutSubviews()
guard let bounds = containerView?.bounds else { return }
presentingViewController.view.bounds = bounds
}
}
这适用于非交互式演示或解雇。但是,在执行交互式解雇时,presentingViewController.view
上的所有动画都以非交互方式运行。也就是说,缩放将发生在通常需要解雇的约300毫秒内,而不是在3%被解雇时保持3%完成。
您可以在a sample project is available on GitHub.和a video of the issue is on YouTube中看到这一点。
我尝试了以下方法,但它们都产生了相同的结果:
答案 0 :(得分:4)
问题是presentingViewController
不是演示文稿containerView
的后代。 UIPercentDrivenInteractiveTransition
的工作原理是将containerView.layer.speed
设置为零并设置containerView.layer.timeOffset
以反映完成百分比。由于有问题的视图不是层次结构的一部分,因此它的速度保持在1并且正常完成。
animateAlongsideTransition(_:,completion:)
的文档中明确说明了这一点:
使用此方法执行动画对象本身未处理的动画。 您指定的所有动画必须出现在动画上下文的容器视图(或其后代之一)中。使用上下文对象的containerView属性来获取容器视图。 要在不从容器视图下降的视图中执行动画,请改用
animateAlongsideTransitionInView:animation:completion:
方法。
如文档所示,切换到animateAlongsideTransitionInView(_:,animation:,completion:)
可解决问题:
// Scale up alongside the dismissal.
override func dismissalTransitionWillBegin() {
presentingViewController.transitionCoordinator()?.animateAlongsideTransitionInView(presentingViewController.view, animation: { context in
self.setScale(expanded: false)
}, completion: { context in
self.setScale(expanded: context.isCancelled())
})
}
标题中对该方法的评论比文档更直接:
//如果视图不是容器视图的后代,则需要此备用API,并且您需要此动画由UIPercentDrivenInteractiveTransition交互控制器驱动。
答案 1 :(得分:-1)
感谢您的回答,如果在iOS 9.x和10.x设备上出现此问题 - 使用 animateAlongsideTransition(in:animation:completion :) 完成了这项工作。
有趣的是,在iOS 11.x animate(withsideTransition:completion :)上也适用于 presentsViewController (不需要使用 animateAlongsideTransition(在:动画:完成:)) - 看起来苹果在最新的iOS中掀起了一些东西。