简体   繁体   English

我的子视图没有使用视图控制器制作动画

[英]My subviews doesn't animate with the view controller

I've a simple sample project in which I'm playing around some view controller custom animations, to integrate in a bigger project, but I've found some issues with them.我有一个简单的示例项目,其中我正在播放一些视图控制器自定义动画,以集成到更大的项目中,但我发现它们存在一些问题。

I have 2 simple view controllers, the first one with a button to present the second one, with custom animation;我有 2 个简单的视图控制器,第一个带有按钮来呈现第二个,带有自定义动画; and the second one has some labels and a dismiss button which animates the view controller out 'of the scene'第二个有一些标签和一个关闭按钮,可以将视图控制器设置为“脱离场景”

When I'm presenting the view controller, after I click the present button, the subviews of the presented view controller, appear on the screen before the view controller animates in, but when I'm dismissing the VC, all the subviews go with the dismissed view controller.当我呈现视图控制器时,在单击呈现按钮后,呈现的视图控制器的子视图在视图控制器动画之前出现在屏幕上,但是当我关闭 VC 时,所有子视图都与解除视图控制器。

On my view controller 2 (presented) I've the views with default auto-layout (reset to suggested constraints)在我的视图控制器 2(呈现)上,我有默认自动布局的视图(重置为建议的约束)

I can't find a justification why the subviews doesn't animate in, inside the view controller as I expected to.我找不到为什么子视图没有按预期在视图控制器内部设置动画的理由。

Below goes a gif showing what's happening, and the source-code:下面是一个 gif 显示正在发生的事情,以及源代码:

动图

CODE: view controller 1 (presenting VC)代码:视图控制器 1(呈现 VC)

import UIKit

class 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)
    }

    // REMARK: UIViewControllerTransitioningDelegate
    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: view controller 2 (presented VC)代码:视图控制器 2(呈现 VC)

import UIKit

class ViewController2: UIViewController {

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

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

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

}

CODE: CustomPresentationController代码:CustomPresentationController

import UIKit
import Foundation

class CustomPresentationController: 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 class CODE:动画师类

import Foundation
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
        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)
        }
    }

}

Alright I am going to take a stab at helping you.好的,我会尽力帮助你。 First the reason why it is not working is autolayout has position your views but you have a frame of size zero basically.首先,它不起作用的原因是自动布局已定位您的视图,但基本上您的框架大小为零。 To show you this go to the controller in question and have it clip its subviews and they will not show up during the transition.为了向您展示这一点,请转到有问题的控制器并让它剪辑其子视图,并且它们不会在过渡期间出现。 Now I probably would not change the frame to move it in since you just want to slide it in and you can probably get rid of some code.现在我可能不会更改框架以将其移入,因为您只想将其滑入并且您可能可以摆脱一些代码。 Here is what it looks like for me.这就是我的样子。

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
    }

}

Delete the Custom Presentation Controller.删除自定义展示控制器。 I honestly don't see a need for it.老实说,我认为没有必要。

Now the 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)

        }

    }

}

That's all you need.这就是你所需要的。 Cheers.干杯。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM