美文网首页iOS面试知识
iOS开发 — 转场动画详解

iOS开发 — 转场动画详解

作者: buding_ | 来源:发表于2022-10-16 18:03 被阅读0次

    UIViewControllerAnimatedTransitioning:

    负责present/dismiss的自然过程的动画效果

    @protocol UIViewControllerAnimatedTransitioning <NSObject>
    // This is used for percent driven interactive transitions, as well as for
    // container controllers that have companion animations that might need to
    // synchronize with the main animation.
    - (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
    // This method can only be a no-op if the transition is interactive and not a percentDriven interactive transition.
    - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
    
    @optional
    
    /// A conforming object implements this method if the transition it creates can
    /// be interrupted. For example, it could return an instance of a
    /// UIViewPropertyAnimator. It is expected that this method will return the same
    /// instance for the life of a transition.
    - (id <UIViewImplicitlyAnimating>) interruptibleAnimatorForTransition:(id <UIViewControllerContextTransitioning>)transitionContext API_AVAILABLE(ios(10.0));
    
    // This is a convenience and if implemented will be invoked by the system when the transition context's completeTransition: method is invoked.
    - (void)animationEnded:(BOOL) transitionCompleted;
    

    Example

    - (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
        return 0.35;
    }
    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        
        UIView *containerView = transitionContext.containerView;
        
        // For a Presentation:
        //      fromView = The presenting view.
        //      toView   = The presented view.
        // For a Dismissal:
        //      fromView = The presented view.
        //      toView   = The presenting view.
        UIView *fromView;
        UIView *toView;
        
        // In iOS 8, the viewForKey: method was introduced to get views that the
        // animator manipulates.  This method should be preferred over accessing
        // the view of the fromViewController/toViewController directly.
        // It may return nil whenever the animator should not touch the view
        // (based on the presentation style of the incoming view controller).
        // It may also return a different view for the animator to animate.
        //
        // Imagine that you are implementing a presentation similar to form sheet.
        // In this case you would want to add some shadow or decoration around the
        // presented view controller's view. The animator will animate the
        // decoration view instead and the presented view controller's view will
        // be a child of the decoration view.
        if ([transitionContext respondsToSelector:@selector(viewForKey:)]) {
            fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
            toView = [transitionContext viewForKey:UITransitionContextToViewKey];
        } else {
            fromView = fromViewController.view;
            toView = toViewController.view;
        }
        
        fromView.frame = [transitionContext initialFrameForViewController:fromViewController];
        toView.frame = [transitionContext finalFrameForViewController:toViewController];
        
        fromView.alpha = 1.0f;
        toView.alpha = 0.0f;
        
        // We are responsible for adding the incoming view to the containerView
        // for the presentation/dismissal.
        [containerView addSubview:toView];
        
        NSTimeInterval transitionDuration = [self transitionDuration:transitionContext];
        
        [UIView animateWithDuration:transitionDuration animations:^{
            fromView.alpha = 0.0f;
            toView.alpha = 1.0;
        } completion:^(BOOL finished) {
            // When we complete, tell the transition context
            // passing along the BOOL that indicates whether the transition
            // finished or not.
            BOOL wasCancelled = [transitionContext transitionWasCancelled];
            [transitionContext completeTransition:!wasCancelled];
        }];
    }
    

    UIViewControllerInteractiveTransitioning

    负责present/dismiss 交互式过程中的效果,一般可通过继承 UIPercentDrivenInteractiveTransition 去自定义

    @interface UIPercentDrivenInteractiveTransition : NSObject <UIViewControllerInteractiveTransitioning>
    
    
    /// Use this method to pause a running interruptible animator. This will ensure that all blocks
    /// provided by a transition coordinator's notifyWhenInteractionChangesUsingBlock: method
    /// are executed when a transition moves in and out of an interactive mode.
    - (void)pauseInteractiveTransition API_AVAILABLE(ios(10.0));
    
    // These methods should be called by the gesture recognizer or some other logic
    // to drive the interaction. This style of interaction controller should only be
    // used with an animator that implements a CA style transition in the animator's
    // animateTransition: method. If this type of interaction controller is
    // specified, the animateTransition: method must ensure to call the
    // UIViewControllerTransitionParameters completeTransition: method. The other
    // interactive methods on UIViewControllerContextTransitioning should NOT be
    // called. If there is an interruptible animator, these methods will either scrub or continue 
    // the transition in the forward or reverse directions.
    - (void)updateInteractiveTransition:(CGFloat)percentComplete;
    - (void)cancelInteractiveTransition;
    - (void)finishInteractiveTransition;
    
    @end
    

    Example

    - (CGFloat)percentForGesture:(UIScreenEdgePanGestureRecognizer *)gesture
    {
        // Because view controllers will be sliding on and off screen as part
        // of the animation, we want to base our calculations in the coordinate
        // space of the view that will not be moving: the containerView of the
        // transition context.
        UIView *transitionContainerView = self.transitionContext.containerView;
        
        CGPoint locationInSourceView = [gesture locationInView:transitionContainerView];
        
        // Figure out what percentage we've gone.
    
        CGFloat width = CGRectGetWidth(transitionContainerView.bounds);
        CGFloat height = CGRectGetHeight(transitionContainerView.bounds);
        
        // Return an appropriate percentage based on which edge we're dragging
        // from.
        if (self.edge == UIRectEdgeRight)
            return (width - locationInSourceView.x) / width;
        else if (self.edge == UIRectEdgeLeft)
            return locationInSourceView.x / width;
        else if (self.edge == UIRectEdgeBottom)
            return (height - locationInSourceView.y) / height;
        else if (self.edge == UIRectEdgeTop)
            return locationInSourceView.y / height;
        else
            return 0.f;
    }
    
    
    //| ----------------------------------------------------------------------------
    //! Action method for the gestureRecognizer.
    //
    - (IBAction)gestureRecognizeDidUpdate:(UIScreenEdgePanGestureRecognizer *)gestureRecognizer
    {
        switch (gestureRecognizer.state)
        {
            case UIGestureRecognizerStateBegan:
                // The Began state is handled by the view controllers.  In response
                // to the gesture recognizer transitioning to this state, they
                // will trigger the presentation or dismissal.
                break;
            case UIGestureRecognizerStateChanged:
                // We have been dragging! Update the transition context accordingly.
                [self updateInteractiveTransition:[self percentForGesture:gestureRecognizer]];
                break;
            case UIGestureRecognizerStateEnded:
                // Dragging has finished.
                // Complete or cancel, depending on how far we've dragged.
                if ([self percentForGesture:gestureRecognizer] >= 0.5f)
                    [self finishInteractiveTransition];
                else
                    [self cancelInteractiveTransition];
                break;
            default:
                // Something happened. cancel the transition.
                [self cancelInteractiveTransition];
                break;
        }
    }
    

    UIViewControllerTransitioningDelegate

    负责指定UIViewController的present/dismiss时的动画对象 (包括自然过程动画与交互过程动画),默认声明了该代理

    @protocol UIViewControllerTransitioningDelegate <NSObject>
    
    @optional
    - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
    
    - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;
    
    - (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator;
    
    - (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator;
    
    - (nullable UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(nullable UIViewController *)presenting sourceViewController:(UIViewController *)source API_AVAILABLE(ios(8.0));
    
    @end
    

    UIPresentationController

    集成presentedViewController 和 presentingViewController,并提供很多转场相关的协议; 可继承后,用于自定义转场动画;

    UINavigationControllerDelegate

    导航控制器的代理,提供了转场动画自定义方法,类似UIViewControllerTransitioningDelegate

    UITabBarControllerDelegate

    Tab控制器的代理,提供了转场动画自定义方法

    相关文章

      网友评论

        本文标题:iOS开发 — 转场动画详解

        本文链接:https://www.haomeiwen.com/subject/haukortx.html