交互式解除过程中呈现视图控制器变化的动画效果

3
我正在开发一个类似于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 上的动画都是非交互式运行的。也就是说,缩放将在通常需要3%的时间内完成,而不是在3%解散时保持在3%处。
您可以在GitHub 上获取可用的示例项目。以及YouTube 上有关此问题的视频。 我尝试了以下方法,但它们都产生了相同的结果:
  • 像上面那样平行动画。
  • 在 UIViewControllerAnimatedTransitioning 中进行动画处理。
  • 使用 CABasicAnimation 并手动调整容器视图层的时间。
2个回答

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())
    })
}

该方法头部的注释比文档更直接地说明了这一点:
// 如果视图不是容器视图的子视图,并且您需要此动画由UIPercentDrivenInteractiveTransition交互控制器驱动,则需要此备用API。

-1

感谢您的回答,我在iOS 9.x和10.x设备上遇到了这个问题 - 使用animateAlongsideTransition(in:animation:completion:)解决了问题。

有趣的是,在iOS 11.x上,animate(alongsideTransition:completion:)也可以正确地为presentingViewController工作(不需要使用animateAlongsideTransition(in:animation:completion:)) - 看起来苹果在最新的iOS中做了一些改进。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接