UIViewControllerAnimatedTransitioning:旋转改变后的黑色屏幕碎片

我创build了一个Viewcontrollertransition,只要不改变设备的方向,一切都在工作。

图1显示了它应该的屏幕。 然后我切换到下一个viewcontroller我改变方向。 现在我回到第一个viewcontroller并再次切换方向。 然后在图像2中看到结果。黑色边框出现。 请不要介意在屏幕中心的白色方块。

下面你find我的animation代码。 你能看到什么是错的?

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提出的解决scheme,但没有奏效。 对我来说这个工作:

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

并在完成animation块:

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

希望有所帮助!