我的子视图不与视图控制器一起动画

问题描述:

我有一个简单的示例项目,我正在玩一些视图控制器自定义动画,要集成到一个更大的项目中,但我发现它们有一些问题。我的子视图不与视图控制器一起动画

我有2个简单的视图控制器,第一个带有按钮以呈现第二个,带有自定义动画;第二个有一些标签和一个解雇按钮,动画视图控制器'场景'

当我提出视图控制器,当我点击当前按钮后,呈现的视图控制器的子视图,在视图控制器开始动画之前出现在屏幕上,但是当我解散VC时,所有子视图都与解散的视图控制器一起进行。

在我的视图控制器2(提交)我已经默认自动布局(重置建议限制)

我找不到理由,为什么子视图不动画中,里面的观点视图控制器,如我所料。

下面转到示出发生了什么的GIF,和源代码:

GIF

CODE:视图控制器1(呈递VC)

进口的UIKit

类的ViewController:UIViewController中,UIViewControllerTransitioningDelegate {

var animator = Animator() 


override func viewDidLoad() { 
    super.viewDidLoad() 
} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
} 


@IBAction func presentButton(_ sender: Any) { 
    let storyboard = UIStoryboard(name: "Main", bundle: nil); 
    let vc = storyboard.instantiateViewController(withIdentifier: "vc2") as! ViewController2 

    vc.transitioningDelegate = self 
    vc.modalPresentationStyle = .custom // chama as funções à parte 

    present(vc, animated: true, completion: nil) 
} 




func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { 
    animator.transitioningMode = .Present // sabe que está em presenting mode 
    return animator 
} 

func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 
    animator.transitioningMode = .Dismiss // Sabe que está em dismissing mode 
    return animator 
} 

func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { 
    return CustomPresentationController(presentedViewController: presented, presenting: presenting) 
} 




} 

CODE:视图控制器2(呈现VC)

进口的UIKit

类ViewController2:UIViewController的{

override func viewDidLoad() { 
    super.viewDidLoad() 
} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
} 



@IBAction func dismissButton(_ sender: Any) { 
    dismiss(animated: true, completion: nil) 
} 

} 

CODE:CustomPresentationController

import UIKit 

进口基金会

类CUS tomPresentationController:UIPresentationController {

override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController!) { 
    super.init(presentedViewController: presentedViewController, presenting: presentingViewController) 
} 


override var frameOfPresentedViewInContainerView: CGRect { 

    // arranca a 0 
    var presentedViewFrame = CGRect.zero 

    // Calcula os bounds do container 
    let containerBounds = self.containerView?.bounds 

    // Recalcula o size 
    presentedViewFrame.size = CGSize(width: (containerBounds?.size.width)! , height: ((containerBounds?.size.height)! * 0.90)) 

    presentedViewFrame.origin.x = 0 
    presentedViewFrame.origin.y = (containerBounds?.size.height)! * 0.1 

    return presentedViewFrame 
} 


} 

CODE:Animator类

进口基金会 进口的UIKit

类动画:NSObject的,UIViewControllerAnimatedTransitioning {

enum Status { 
    case Present 
    case Dismiss 
} 
var transitioningMode: Status = .Present 
var presentDuration = 1.0 
var dismissDuration = 0.3 


// Tempo da animação 
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 
    if (transitioningMode == .Present) { 
     return presentDuration 
    } else { 
     return dismissDuration 
    } 
} 



func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 

    // Get the set of relevant objects. 
    let containerView = transitionContext.containerView 

    guard 
     let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from), 
     let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) 
     else { 
      print("Returning animateTransition VC") 
      return 
    } 

    let toView = transitionContext.view(forKey: UITransitionContextViewKey.to) 
    let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from) 



    // Set up some variables for the animation. 
    let containerFrame:  CGRect = containerView.frame 
    var toViewStartFrame: CGRect = transitionContext.initialFrame(for: toVC) 
    let toViewFinalFrame: CGRect = transitionContext.finalFrame(for: toVC) 
    var fromViewFinalFrame: CGRect = transitionContext.finalFrame(for: fromVC) 

    // Set up animation parameters. 
    if (transitioningMode == .Present) { 
     // Modify the frame of the presented view so that it starts 
     // offscreen at the lower-right corner of the container. 
     toViewStartFrame.origin.x = 0//containerFrame.size.width 
     toViewStartFrame.origin.y = containerFrame.size.height * 0.1 


    } else { 
     // Modify the frame of the dismissed view so it ends in 
     // the lower-right corner of the container view. 
     fromViewFinalFrame = CGRect(x: containerFrame.size.width, 
            y: containerFrame.size.height, 
            width: (toVC.view.frame.size.width), 
            height: (toVC.view.frame.size.height)) 



    } 

    if (transitioningMode == .Present) { 
     // Always add the "to" view to the container. 
     // And it doesn't hurt to set its start frame. 
     containerView.addSubview(toView!) 
     toView?.frame = toViewStartFrame 
    } 

    // Animate using the animator's own duration value. 
    UIView.animate(withDuration: presentDuration, animations: { 

     if (self.transitioningMode == .Present) { 
      // Move the presented view into position. 
      toView?.frame = toViewFinalFrame 
     } 
     else { 
      // Move the dismissed view offscreen. 
      fromView?.frame = fromViewFinalFrame 
     } 
    }) { (finished) in 
     let success = !(transitionContext.transitionWasCancelled) 
     // After a failed presentation or successful dismissal, remove the view. 
     if ((self.transitioningMode == .Present && !success) || (self.transitioningMode == .Dismiss && success)) { 
      toView?.removeFromSuperview() 
     } 

     // Notify UIKit that the transition has finished 
     transitionContext.completeTransition(success) 

    } 

} 



} 
+0

蓝色视图应该低于呈现视图控制器的顶部。我知道这个问题,但是如果我要显示代码,我希望它符合你的用例。有没有一个导航栏或 – agibson007

+0

和这是在当前的上下文? – agibson007

+0

动画效果(它来自哪里,它结束的地方不是很重要,我稍后会改变它) –

好吧,我要带刺在帮助你。首先,它不工作的原因是自动布局具有定位视图,但基本上你有一个大小为零的框架。为了向你展示这一点,请去讨论有问题的控制器,让它剪辑它的子视图,并且在转换过程中它们不会显示出来。现在我可能不会更改框架来移动它,因为您只是想将其滑入,并且可能会删除一些代码。这是我看起来的样子。

import UIKit 

class ViewController: UIViewController,UIViewControllerTransitioningDelegate { 

    var animator = Animator() 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Do any additional setup after loading the view, typically from a nib. 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 

    @IBAction func presentModally(_ sender: Any) { 
     self.performSegue(withIdentifier: "modal", sender: nil) 
    } 

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 
     if segue.identifier == "modal"{ 
      let dvc = segue.destination 
      dvc.transitioningDelegate = self 
      dvc.modalPresentationStyle = .overCurrentContext 
     } 
    } 

    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { 
     animator.transitioningMode = .Present // sabe que está em presenting mode 
     return animator 
    } 

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 
     animator.transitioningMode = .Dismiss // Sabe que está em dismissing mode 
     return animator 
    } 

} 

删除自定义演示文稿控制器。我真的没有看到它的需要。

现在的动画师。

import UIKit 

class Animator: NSObject,UIViewControllerAnimatedTransitioning { 
    enum Status { 
     case Present 
     case Dismiss 
    } 
    var transitioningMode: Status = .Present 
    var presentDuration = 1.0 
    var dismissDuration = 0.3 


    // Tempo da animação 
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 
     if (transitioningMode == .Present) { 
      return presentDuration 
     } else { 
      return dismissDuration 
     } 
    } 


    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 

     // Get the set of relevant objects. 
     let containerView = transitionContext.containerView 

     guard 
      let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from), 
      let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) 
      else { 
       print("Returning animateTransition VC") 
       return 
     } 

     let toView = transitionContext.view(forKey: UITransitionContextViewKey.to) 
     let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from) 

     // Set up some variables for the animation. 
     let containerFrame:  CGRect = containerView.frame 
     let toViewFinalFrame: CGRect = transitionContext.finalFrame(for: toVC) 
     var fromViewFinalFrame: CGRect = transitionContext.finalFrame(for: fromVC) 

     // Set up animation parameters. 
     if (transitioningMode == .Present) { 
      let anchor = toViewFinalFrame.origin 
      toView?.layer.anchorPoint = anchor 
      toView?.layer.position = anchor 
      toView?.transform = CGAffineTransform(scaleX: 0, y: 1) 
      //another posibility 
      //toView?.transform = CGAffineTransform(translationX: -containerView.bounds.width, y: -containerView.bounds.height) 
     } else { 
      // Modify the frame of the dismissed view so it ends in 
      // the lower-right corner of the container view. 
      fromViewFinalFrame = CGRect(x: containerFrame.size.width, 
             y: containerFrame.size.height, 
             width: (toVC.view.frame.size.width), 
             height: (toVC.view.frame.size.height)) 
     } 

     if (transitioningMode == .Present) { 
      // Always add the "to" view to the container. 
      // And it doesn't hurt to set its start frame. 
      containerView.addSubview(toView!) 
      // toView?.frame = toViewStartFrame 
     } 

     // Animate using the animator's own duration value. 
     UIView.animate(withDuration: presentDuration, animations: { 

      if (self.transitioningMode == .Present) { 
       // Move the presented view into position. 
       toView?.transform = .identity 
      } 
      else { 
       // Move the dismissed view offscreen. 
       fromView?.frame = fromViewFinalFrame 
      } 
     }) { (finished) in 
      let success = !(transitionContext.transitionWasCancelled) 
      // After a failed presentation or successful dismissal, remove the view. 
      if ((self.transitioningMode == .Present && !success) || (self.transitioningMode == .Dismiss && success)) { 
       toView?.removeFromSuperview() 
      } 

      // Notify UIKit that the transition has finished 
      transitionContext.completeTransition(success) 

     } 

    } 

} 

这就是你所需要的。干杯。

+0

我认为这是必需的他定制的演示课,如果我是未来我想改变视图控制器的大小。我会尝试你写的内容,我会尽快给你回复。感谢您的帮助:) –

+0

您可以保留自定义的演示文稿控制器,但我会返回您想要的帧的确切大小,并使用翻译或缩放将其移入到位。只是我2美分。当我做动画时,我实际上要改变框架,我通常会拍摄快照并隐藏原始图像并取消隐藏,并在最后删除快照。但是,我只对视图或子视图的快照进行动画处理。这样我从不真正操纵真实视图的框架。希望这也有帮助。 – agibson007

+0

不错的提示。你有没有看过mail.app的iOS 10.3上的新动画?当你创建一个新的电子邮件时,视图控制器来自底部,但没有达到顶部,就像90%的大小,背景视图控制器扩展了一点,你可以看到他们两个。这就是我想在这里创建的;) –