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控制器的代理,提供了转场动画自定义方法
网友评论