动画在交互式解雇期间对presentViewController的更改

时间:2016-04-21 16:14:27

标签: ios custom-transition

我正在使用类似于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中看到这一点。

我尝试了以下方法,但它们都产生了相同的结果:

  • 如上所示的平行动画。
  • UIViewControllerAnimatedTransitioning中的动画。
  • 使用CABasicAnimation手动调整容器视图层的时间。

2 个答案:

答案 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中掀起了一些东西。