簡體   English   中英

UIViewControllerAnimatedTransitioning:旋轉更改后的黑屏片段

[英]UIViewControllerAnimatedTransitioning: Black screen fragments after rotation change

我創建了一個Viewcontrollertransition,只要不更改設備方向,一切都可以正常工作。

圖1顯示了應該顯示的屏幕。 然后,我切換到下一個更改方向的ViewController。 現在,我回到第一個viewcontroller並再次切換方向。 然后,結果在圖像2中可見。出現黑色邊框。 請不要介意屏幕中央的白色框。

在下面,您可以找到我的動畫代碼。 你看錯了嗎?

import Foundation

import UIKit

class ZoomOutCircleViewTransition: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {

    var hideDelayed = false
    var transitionContext: UIViewControllerContextTransitioning?

    init(hideDelayed : Bool = true) {
        self.hideDelayed = hideDelayed
        super.init()
    }


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

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        self.transitionContext = transitionContext

        guard let toViewController: UIViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) else {
            return
        }

        guard let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) else {
            return
        }

        guard let toViewTransitionFromView = toViewController as? TransitionFromViewProtocol else {
            return
        }

        let containerView = transitionContext.containerView()

        let imageViewSnapshot = toViewTransitionFromView.getViewForTransition()
        imageViewSnapshot.alpha = 0.0
        let imageViewSnapshotOriginalFrame = imageViewSnapshot.frame

        let startFrame = CGRectMake(-CGRectGetWidth(toViewController.view.frame)/2, -CGRectGetHeight(toViewController.view.frame)/2, CGRectGetWidth(toViewController.view.frame)*2, CGRectGetHeight(toViewController.view.frame)*2)

        let quadraticStartFrame = CGRect(x: startFrame.origin.x - (startFrame.height - startFrame.width)/2, y: startFrame.origin.y, width: startFrame.height, height: startFrame.height)

        containerView!.insertSubview(toViewController.view, atIndex: 0)
        containerView!.addSubview(imageViewSnapshot)


        // UIViewController circle shrink animation
        let bigCirclePath = UIBezierPath(ovalInRect: quadraticStartFrame)

        let smallCirclePath = UIBezierPath(ovalInRect: imageViewSnapshot.frame)
        let maskLayer = CAShapeLayer()
        maskLayer.frame = toViewController.view.frame
        maskLayer.path = bigCirclePath.CGPath//maskPath.CGPath
        fromViewController.view.layer.mask = maskLayer

        let pathAnimation = CABasicAnimation(keyPath: "path")
        pathAnimation.delegate = self
        pathAnimation.fromValue = bigCirclePath.CGPath
        pathAnimation.toValue = smallCirclePath.CGPath
        pathAnimation.duration = transitionDuration(transitionContext)
        maskLayer.path = smallCirclePath.CGPath
        maskLayer.addAnimation(pathAnimation, forKey: "pathAnimation")

        //        pathAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)

        imageViewSnapshot.frame = quadraticStartFrame

        // Make imageView visible with animation
        let showImageViewAnimation =  {
            imageViewSnapshot.alpha = 1.0
        }
        let showImageViewDelay = 0.3
        UIView.animateWithDuration(transitionDuration(transitionContext) - showImageViewDelay , delay: showImageViewDelay, options: UIViewAnimationOptions.CurveLinear, animations: showImageViewAnimation) { (completed) -> Void in
        }

        // Shrink the imageView to the original size
        let scaleImageViewAnimation = {
            imageViewSnapshot.frame = imageViewSnapshotOriginalFrame
        }
        UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: scaleImageViewAnimation) { (completed) -> Void in
            // After the complete animations have endet

            // Hide ImageView after it is completely resized. Added some animation delay to not abruptly change the contactImage
            if self.hideDelayed {
                let hideImageViewAnimation =  {
                    imageViewSnapshot.alpha = 0.0
                }
                UIView.animateWithDuration(0.2 , delay: 0.2, options: UIViewAnimationOptions.CurveLinear, animations: hideImageViewAnimation) { (completed) -> Void in
                    imageViewSnapshot.removeFromSuperview()
                }
            }
            else {
                imageViewSnapshot.removeFromSuperview()
            }
        }
    }

    override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
        if let transitionContext = self.transitionContext {
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
        }
    }

    // MARK: UIViewControllerTransitioningDelegate protocol methods

    // return the animataor when presenting a viewcontroller
    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self
    }

    // return the animator used when dismissing from a viewcontroller
    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self
    }

}

您需要將新框架設置為toViewController.view。 這會將視圖更新為當前方向。

toViewController.view.frame = fromViewController.view.frame

使用我的更新代碼:

class ZoomOutCircleViewTransition: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {

    var hideDelayed = false
    var transitionContext: UIViewControllerContextTransitioning?

    init(hideDelayed : Bool = true) {
        self.hideDelayed = hideDelayed
        super.init()
    }


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

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        self.transitionContext = transitionContext

        guard let toViewController: UIViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) else {
            return
        }

        guard let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) else {
            return
        }

        guard let toViewTransitionFromView = toViewController as? TransitionFromViewProtocol else {
            return
        }

        toViewController.view.frame = fromViewController.view.frame

        let containerView = transitionContext.containerView()

        let imageViewSnapshot = toViewTransitionFromView.getViewForTransition()
        imageViewSnapshot.alpha = 0.0
        let imageViewSnapshotOriginalFrame = imageViewSnapshot.frame

        let startFrame = CGRectMake(-CGRectGetWidth(fromViewController.view.frame)/2, -CGRectGetHeight(fromViewController.view.frame)/2, CGRectGetWidth(toViewController.view.frame)*2, CGRectGetHeight(toViewController.view.frame)*2)

        let quadraticStartFrame = CGRect(x: startFrame.origin.x - (startFrame.height - startFrame.width)/2, y: startFrame.origin.y, width: startFrame.height, height: startFrame.height)

        containerView!.insertSubview(toViewController.view, atIndex: 0)
        containerView!.addSubview(imageViewSnapshot)


        // UIViewController circle shrink animation
        let bigCirclePath = UIBezierPath(ovalInRect: quadraticStartFrame)

        let smallCirclePath = UIBezierPath(ovalInRect: imageViewSnapshot.frame)
        let maskLayer = CAShapeLayer()
        maskLayer.frame = toViewController.view.frame
        maskLayer.path = bigCirclePath.CGPath//maskPath.CGPath
        fromViewController.view.layer.mask = maskLayer

        let pathAnimation = CABasicAnimation(keyPath: "path")
        pathAnimation.delegate = self
        pathAnimation.fromValue = bigCirclePath.CGPath
        pathAnimation.toValue = smallCirclePath.CGPath
        pathAnimation.duration = transitionDuration(transitionContext)
        maskLayer.path = smallCirclePath.CGPath
        maskLayer.addAnimation(pathAnimation, forKey: "pathAnimation")

        //        pathAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)

        imageViewSnapshot.frame = quadraticStartFrame

        // Make imageView visible with animation
        let showImageViewAnimation =  {
            imageViewSnapshot.alpha = 1.0
        }
        let showImageViewDelay = 0.3
        UIView.animateWithDuration(transitionDuration(transitionContext) - showImageViewDelay , delay: showImageViewDelay, options: UIViewAnimationOptions.CurveLinear, animations: showImageViewAnimation) { (completed) -> Void in
        }

        // Shrink the imageView to the original size
        let scaleImageViewAnimation = {
            imageViewSnapshot.frame = imageViewSnapshotOriginalFrame
        }
        UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: scaleImageViewAnimation) { (completed) -> Void in
            // After the complete animations have endet

            // Hide ImageView after it is completely resized. Added some animation delay to not abruptly change the contactImage
            if self.hideDelayed {
                let hideImageViewAnimation =  {
                    imageViewSnapshot.alpha = 0.0
                }
                UIView.animateWithDuration(0.2 , delay: 0.2, options: UIViewAnimationOptions.CurveLinear, animations: hideImageViewAnimation) { (completed) -> Void in
                    imageViewSnapshot.removeFromSuperview()
                }
            }
            else {
                imageViewSnapshot.removeFromSuperview()
            }
            toViewController.view.layer.mask = nil
        }
    }

    override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
        if let transitionContext = self.transitionContext {
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
        }
    }

    // MARK: UIViewControllerTransitioningDelegate protocol methods

    // return the animataor when presenting a viewcontroller
    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self
    }

    // return the animator used when dismissing from a viewcontroller
    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self
    }

}

class ZoomOutCircleViewTransition: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {

    var hideDelayed = false
    var transitionContext: UIViewControllerContextTransitioning?

    init(hideDelayed : Bool = true) {
        self.hideDelayed = hideDelayed
        super.init()
    }


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

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        self.transitionContext = transitionContext

        guard let toViewController: UIViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) else {
            return
        }

        guard let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) else {
            return
        }

        guard let toViewTransitionFromView = toViewController as? TransitionFromViewProtocol else {
            return
        }

        toViewController.view.frame = fromViewController.view.frame

        let containerView = transitionContext.containerView()

        let imageViewSnapshot = toViewTransitionFromView.getViewForTransition()
        imageViewSnapshot.alpha = 0.0
        let imageViewSnapshotOriginalFrame = imageViewSnapshot.frame

        let startFrame = CGRectMake(-CGRectGetWidth(fromViewController.view.frame)/2, -CGRectGetHeight(fromViewController.view.frame)/2, CGRectGetWidth(toViewController.view.frame)*2, CGRectGetHeight(toViewController.view.frame)*2)

        let quadraticStartFrame = CGRect(x: startFrame.origin.x - (startFrame.height - startFrame.width)/2, y: startFrame.origin.y, width: startFrame.height, height: startFrame.height)

        containerView!.insertSubview(toViewController.view, atIndex: 0)
        containerView!.addSubview(imageViewSnapshot)


        // UIViewController circle shrink animation
        let bigCirclePath = UIBezierPath(ovalInRect: quadraticStartFrame)

        let smallCirclePath = UIBezierPath(ovalInRect: imageViewSnapshot.frame)
        let maskLayer = CAShapeLayer()
        maskLayer.frame = toViewController.view.frame
        maskLayer.path = bigCirclePath.CGPath//maskPath.CGPath
        fromViewController.view.layer.mask = maskLayer

        let pathAnimation = CABasicAnimation(keyPath: "path")
        pathAnimation.delegate = self
        pathAnimation.fromValue = bigCirclePath.CGPath
        pathAnimation.toValue = smallCirclePath.CGPath
        pathAnimation.duration = transitionDuration(transitionContext)
        maskLayer.path = smallCirclePath.CGPath
        maskLayer.addAnimation(pathAnimation, forKey: "pathAnimation")

        //        pathAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)

        imageViewSnapshot.frame = quadraticStartFrame

        // Make imageView visible with animation
        let showImageViewAnimation =  {
            imageViewSnapshot.alpha = 1.0
        }
        let showImageViewDelay = 0.3
        UIView.animateWithDuration(transitionDuration(transitionContext) - showImageViewDelay , delay: showImageViewDelay, options: UIViewAnimationOptions.CurveLinear, animations: showImageViewAnimation) { (completed) -> Void in
        }

        // Shrink the imageView to the original size
        let scaleImageViewAnimation = {
            imageViewSnapshot.frame = imageViewSnapshotOriginalFrame
        }
        UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: scaleImageViewAnimation) { (completed) -> Void in
            // After the complete animations have endet

            // Hide ImageView after it is completely resized. Added some animation delay to not abruptly change the contactImage
            if self.hideDelayed {
                let hideImageViewAnimation =  {
                    imageViewSnapshot.alpha = 0.0
                }
                UIView.animateWithDuration(0.2 , delay: 0.2, options: UIViewAnimationOptions.CurveLinear, animations: hideImageViewAnimation) { (completed) -> Void in
                    imageViewSnapshot.removeFromSuperview()
                }
            }
            else {
                imageViewSnapshot.removeFromSuperview()
            }
            toViewController.view.layer.mask = nil
        }
    }

    override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
        if let transitionContext = self.transitionContext {
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
        }
    }

    // MARK: UIViewControllerTransitioningDelegate protocol methods

    // return the animataor when presenting a viewcontroller
    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self
    }

    // return the animator used when dismissing from a viewcontroller
    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self
    }
}

我遇到了同樣的問題,並嘗試了@Arun提出的解決方案,但沒有成功。 對我來說,這是:

    guard let toViewController: UIViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) else { return }
    let toFrame = transitionContext.finalFrameForViewController(toViewController)

在動畫的完成塊中:

    }) { finished in
        toViewController.view.frame = toFrame
        transitionContext.completeTransition(finished)
    }

希望有幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM