菜鸟教程小白 发表于 2022-12-12 10:58:15

ios - 在交互式解雇期间动画更改 presentingViewController


                                            <p><p>我正在开发类似于 Mail.app 的打开草稿行为的 UIPresentationController 子类。呈现 ViewController 时,它不会一直到顶部,呈现的 ViewController 会缩小,就好像它正在回落一样。</p>

<p>它的基本要点如下:</p>

<pre><code>class CustomPresentationController : UIPresentationController {

    // Create a 40pt space above the view.
    override func frameOfPresentedViewInContainerView() -&gt; 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&#39;s frame on orientation change.
    override func containerViewWillLayoutSubviews() {
      super.containerViewWillLayoutSubviews()
      guard let bounds = containerView?.bounds else { return }
      presentingViewController.view.bounds = bounds
    }
}
</code></pre>

<p>这适用于非交互式演示或解雇。然而,在执行交互式解除时,<code>presentingViewController.view</code> 上的所有动画都以非交互方式运行。也就是说,缩放将在通常需要关闭的大约 300 毫秒内发生,而不是在 3% 关闭时保持在 3% 完成。</p>

<p>您可以在 <a href="https://github.com/bnickel/interactive-parent-transform-bug" rel="noreferrer noopener nofollow">a sample project is available on GitHub.</a> 中看到这一点和 <a href="https://www.youtube.com/watch?v=BRbH0GauCt4" rel="noreferrer noopener nofollow">a video of the issue is on YouTube</a> .</p>

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

<ul>
<li>如上所示的并行动画。</li>
<li>在 UIViewControllerAnimatedTransitioning 中制作动画。</li>
<li>使用 CABasicAnimation 手动调整容器 View 层的时间。</li>
</ul></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>问题在于 <code>presentingViewController</code> 不是演示文稿的 <code>containerView</code> 的后代。 <code>UIPercentDrivenInteractiveTransition</code> 通过将 <code>containerView.layer.speed</code> 设置为零并设置 <code>containerView.layer.timeOffset</code> 来反射(reflect)完成百分比。由于有问题的 View 不是层次结构的一部分,因此它的速度保持在 1 并且正常完成。</p>

<p>这在 <code>animateAlongsideTransition(_:,completion:)</code> 的文档中有明确说明:</p>

<blockquote>
<p>Use this method to perform animations that are not handled by the animator objects themselves. <strong>All of the animations you specify must occur inside the animation context’s container view (or one of its descendants).</strong> Use the containerView property of the context object to get the container view. <strong>To perform animations in a view that does not descend from the container view, use the <code>animateAlongsideTransitionInView:animation:completion:</code> method instead.</strong></p>
</blockquote>

<p>如文档所示,切换到 <code>animateAlongsideTransitionInView(_:,animation:,completion:)</code> 可以解决问题:</p>

<pre><code>// 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())
    })
}
</code></pre>

<p>标题中对该方法的注释比文档更直接:</p>

<blockquote>
<p>// This alternative API is needed if the view is not a descendent of the container view AND you require this animation to be driven by a UIPercentDrivenInteractiveTransition interaction controller.</p>
</blockquote></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 在交互式解雇期间动画更改 presentingViewController,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/36775216/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/36775216/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 在交互式解雇期间动画更改 presentingViewController