【问题标题】:iOS custom transitions and rotationiOS 自定义过渡和旋转
【发布时间】:2015-08-12 15:27:23
【问题描述】:

我正在使用自定义转换来显示全屏模式游戏视图。当用户开始游戏时,根视图控制器缩小“进入”屏幕,而全屏游戏视图控制器从较大的比例缩小到显示器,同时从 0% 不透明度过渡到 100% 不透明度。简单!

过渡看起来很棒并且工作正常,在关闭游戏视图控制器时也正确地反转动画。

我遇到的问题是,如果在显示全屏游戏视图控制器的同时旋转设备,在返回到根视图控制器时,布局会变得很糟糕。进一步的旋转并不能解决问题,布局很乱,而且一直很乱。

如果我禁用自定义过渡,这个问题就消失了。此外,如果我保留自定义过渡,但在过渡动画的源视图和目标视图上禁用调用设置 CATransform3D,问题就会再次消失。

这是我的过渡代表:

class FullscreenModalTransitionManager: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate  {

    private var presenting:Bool = true

    // MARK: UIViewControllerAnimatedTransitioning protocol methods

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {

        // get reference to our fromView, toView and the container view that we should perform the transition in
        let container = transitionContext.containerView()
        let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
        let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!

        let scale:CGFloat = 1.075
        //let bigScale = CGAffineTransformMakeScale(scale, scale)
        //let smallScale = CGAffineTransformMakeScale(1/scale,1/scale)
        let bigScale = CATransform3DMakeScale(scale, scale, 1)
        let smallScale = CATransform3DMakeScale(1/scale, 1/scale, 1)
        let smallOpacity:CGFloat = 0.5
        let presenting = self.presenting

        if presenting {

            // when presenting, incoming view must be on top
            container.addSubview(fromView)
            container.addSubview(toView)

            toView.layer.transform = bigScale
            toView.opaque = false
            toView.alpha = 0

            fromView.layer.transform = CATransform3DIdentity
            fromView.opaque = false
            fromView.alpha = 1
        } else {

            // when !presenting, outgoing view must be on top
            container.addSubview(toView)
            container.addSubview(fromView)

            toView.layer.transform = smallScale
            toView.opaque = false
            toView.alpha = smallOpacity

            fromView.layer.transform = CATransform3DIdentity
            fromView.opaque = false
            fromView.alpha = 1
        }


        let duration = self.transitionDuration(transitionContext)

        UIView.animateWithDuration(duration,
            delay: 0.0,
            usingSpringWithDamping: 0.7,
            initialSpringVelocity: 0,
            options: nil,
            animations: {

                if presenting {
                    fromView.layer.transform = smallScale
                    fromView.alpha = smallOpacity
                } else {
                    fromView.layer.transform = bigScale
                    fromView.alpha = 0
                }

            },
            completion: nil )

        UIView.animateWithDuration(duration,
            delay: duration/6,
            usingSpringWithDamping: 0.7,
            initialSpringVelocity: 0.5,
            options: nil,
            animations: {
                toView.layer.transform = CATransform3DIdentity
                toView.alpha = 1
            },
            completion: { finished in
                transitionContext.completeTransition(true)
            })
    }

    func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
        return 0.5
    }

    // MARK: UIViewControllerTransitioningDelegate protocol methods

    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        self.presenting = true
        return self
    }

    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        self.presenting = false
        return self
    }
}

并且,作为视觉参考,这是我的根视图控制器通常的样子:

并且,作为视觉参考,如果我在游戏视图中旋转我的设备(至少一次)并返回到根视图控制器,这就是我的根视图控制器的样子。

最后一点 - 以防它响起任何铃声 - 我正在使用自动布局和大小类来布局我的根视图控制器。

谢谢,

【问题讨论】:

    标签: ios swift uiviewcontroller transitions


    【解决方案1】:

    我遇到了类似的问题,我为导航控制器上的推送和弹出编写了自定义转换。如果您在推送后旋转设备,当您弹回根视图控制器时,它的框架将保持不变。


    问题


    解决方案

    目标 C

    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
    
        // ViewController Reference
        UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
        // Fix layout bug in iOS 9+
        toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];
    
        // The rest of your code ...
    } 
    

    Swift 3.0

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    
        // ViewController reference
        let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
    
        // Fix layout bug in iOS 9+
        toViewController.view.frame = transitionContext.finalFrame(for: toViewController)
    
        // The rest of your code ...
    }
    

    【讨论】:

    • 我在 iOS 10.0 上遇到了同样的问题,这解决了它。谢谢。
    • 也在 iOS 11 中工作。
    【解决方案2】:

    我在对具有非身份转换的视图执行一些手动布局代码时无意中发现了这一点。 事实证明,如果您的视图具有非标识转换,则正常布局代码会失败。

    解决方法是,在我的过渡委托中采用过渡后的视图,并在动画完成回调中将其变换设置为身份(因为该视图在动画结束时是不可见的,并且在新视图的后面,这有不影响外观)

    UIView.animateWithDuration(duration,
        delay: 0.0,
        usingSpringWithDamping: 0.7,
        initialSpringVelocity: 0,
        options: nil,
        animations: {
    
            if presenting {
                fromView.transform = smallScale
                fromView.alpha = smallOpacity
            } else {
                fromView.transform = bigScale
                fromView.alpha = 0
            }
    
        },
        completion: { completed in
            // set transform of now hidden view to identity to prevent breakage during rotation
            fromView.transform = CGAffineTransformIdentity
        })
    

    【讨论】:

    • 只有在转换后 fromVC 不可见时才有效。看我的回答
    • 同时使用这个和@agilityvision 的答案对我有用!当transition完成后,你需要将transform重置为identity,然后当transition开始时,你需要将frame设置为finalFrame,然后应用transform。
    【解决方案3】:

    我终于找到了解决这个问题的方法。您需要改进@agilityvision 代码。您需要添加 BOOL 值,例如 closeVCNow 表示您要关闭 VC,并在 animateTransition: 中,在动画块中执行此操作:

    if (self.closeVCNow) {
          toVC.view.transform = CGAffineTransformIdentity; 
          toVC.view.frame = [transitionContext finalFrameForViewController:toVC];
          self.closeVCNow = NO;
      }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-08
      • 2013-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多