控制器的转场动画
众所周知,iOS中的页面跳转方式有两种,一种是navigationController push/pop新页面,另一种是当前页面present/dismiss新页面
1. push/pop 转场动画
系统默认的push动画是从右往左推出新视图,pop则是从左往右消失
自定义实现步骤
a.控制器实现nagationController delegate的方法animationControllerForOperation:fromController:toController,返回一个实现了UIViewControllerAnimatedTransitionning对象,如果返回为nil,则是系统的默认实现
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC {
if ([NSStringFromClass(fromVC.class) isEqualTo:]) {
return [CustomTransitioning new];
}
return nil;
}
b.自定义实现UIViewControllerAnimatedTransitioning协议的对象,实现自定义转场
@interface XWPageCoverTransition : NSObject<UIViewControllerAnimatedTransitioning>
@end
@implementation XWPageCoverTransition
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
return 0.3;
}
/**
* 如何执行过渡动画
*/
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
}
@end
必须实现该协议的两个方法
transitionDuration: 返回转场时间
animationTransition: 转场动画的具体操作,以一个简单的例子来说明如何实现
// 从下到上显示
- (void)showFromBottomToTop:(id<UIViewControllerContextTransitioning>)transitionContext {
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *containerView = [transitionContext containerView];
CGRect toVCFrame = [transitionContext finalFrameForViewController:toVC];
[containerView addSubview:toVC.view];
[containerView sendSubviewToBack:toVC.view];
//对tempView做动画,避免bug;
UIView *tempView = [toVC.view snapshotViewAfterScreenUpdates:YES];
tempView.frame = CGRectOffset(toVCFrame, 0, SCREEN_HEIGHT);
[containerView addSubview:tempView];
//增加阴影
tempView.layer.shadowOffset = CGSizeMake(0, 1);
tempView.layer.shadowColor = [UIColor lightGrayColor].CGColor;
tempView.layer.shadowOpacity = 0.8;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
tempView.frame = toVCFrame;
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
[tempView removeFromSuperview];
[containerView bringSubviewToFront:toVC.view];
}];
}
以上代码是自定义push从下到上显示,该方法包含一个transitionContext对象,我们来看看该对象的几个重要属性
-containerView 包含上下文的容器,动画在该容器中进行
-viewControllerForKey 获取fromVC/toVC
-finalFrameForViewController 获取fromVC/toVC的最终展示frame
一般的做法是根据转场类型push/pop做相应处理,通常是frame,alpha的的简单变化,也可以做复杂点的三维变化。
如果是push动画,A->B,fromVC是A,toVC是B;pop B,fromVC是B,toVC是A。每次变换container中必须添加toVC.view,截取该视图,对截取的视图做相应动画,动画结束后,恢复原始状态即可。
2.present/dismiss动画,默认的是从下到上呈现,以及从上到下消失
自定义实现步骤:
1.自定义的页面需要声明UIViewControllerTransitionningDelegate,并设置modelPresentationStyle为custom,同事还需实现相关的代理方法
@interface XWPresentedOneController ()<UIViewControllerTransitioningDelegate>
@property (nonatomic, strong) XWInteractiveTransition *interactiveDismiss;
@property (nonatomic, strong) XWInteractiveTransition *interactivePush;
@end
@implementation XWPresentedOneController
- (void)dealloc{
NSLog(@"销毁了!!!!!");
}
- (instancetype)init
{
self = [super init];
if (self) {
self.transitioningDelegate = self;
self.modalPresentationStyle = UIModalPresentationCustom;
}
return self;
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{
return [XWPresentOneTransition transitionWithTransitionType:XWPresentOneTransitionTypePresent];
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed{
return [XWPresentOneTransition transitionWithTransitionType:XWPresentOneTransitionTypeDismiss];
}
- (id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator{
return _interactiveDismiss.interation ? _interactiveDismiss : nil;
}
- (id<UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id<UIViewControllerAnimatedTransitioning>)animator{
XWInteractiveTransition *interactivePresent = [_delegate interactiveTransitionForPresent];
return interactivePresent.interation ? interactivePresent : nil;
}
@end
UIViewControllerTransitionDelegate重要方法介绍
- animationControllerForPresentedController: present返回实现<UIViewControllerTransitioning>对象
- animationControllerForDismissedController: 返回自定义的dimiss对象
- interactionControllerForPresentation: present返回百分比动画
- interactionControllerForDismissal: dismiss返回百分比动画
百分比(交互式)动画,需定义UIPercentDrivenInteractiveTransition子类,绑定pan手势,根据手势的相应状态传递事件,本质上还是调用自定义实现的transition方法,因此没个transition完成动画的闭包中会有相应代码来回应交互式状态
/开始动画吧,使用产生弹簧效果的动画API
[UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0 usingSpringWithDamping:0.55 initialSpringVelocity:1.0 / 0.55 options:0 animations:^{
//首先我们让vc2向上移动
toVC.view.transform = CGAffineTransformMakeTranslation(0, -400);
//然后让截图视图缩小一点即可
tempView.transform = CGAffineTransformMakeScale(0.85, 0.85);
} completion:^(BOOL finished) {
//使用如下代码标记整个转场过程是否正常完成[transitionContext transitionWasCancelled]代表手势是否取消了,如果取消了就传NO表示转场失败,反之亦然,如果不是用手势的话直接传YES也是可以的,我们必须标记转场的状态,系统才知道处理转场后的操作,否者认为你一直还在,会出现无法交互的情况,切记
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
//转场失败后的处理
if ([transitionContext transitionWasCancelled]) {
//失败后,我们要把vc1显示出来
fromVC.view.hidden = NO;
//然后移除截图视图,因为下次触发present会重新截图
[tempView removeFromSuperview];
}
}];
UIView的转场动画
1.直接调用系统api [UIView transitionWithView:duration:option:animation:^{}completion:^{}]
- transitionView 需要转场到的视图
- duration 动画时间
- option 转场类型
- aniamtion 动画块
- completion 动画结束回调
UIViewAnimationOptionTransitionNone // default
UIViewAnimationOptionTransitionFlipFromLeft // 从左翻转
UIViewAnimationOptionTransitionFlipFromRight // 从右翻转
UIViewAnimationOptionTransitionCurlUp // 向上翻页
UIViewAnimationOptionTransitionCurlDown // 向下翻页
UIViewAnimationOptionTransitionCrossDissolve // 溶解
UIViewAnimationOptionTransitionFlipFromTop // 从上翻转
UIViewAnimationOptionTransitionFlipFromBottom // 从下翻转
2.使用CATransition 创建相应的animation,view.layer添加后直接在layer上渲染
CATransition的基本属性,以下属性均可以使用kvc调用
- type 转场类型
- subtype 转场的子类型
- duration 动画时间
- timeFunction 动画加速度
// type
*1.kCATransitionMoveIn 新的视图把旧的视图掩盖
*2.kCATransitionPush 旧的视图移走,新的视图移进来
*3.kCATransitionFade 逐渐消失,相当于调整透明度,除了这没有方向,其他的都有
*4.kCATransitionReveal 旧的视图移走,显示出新的视图
//这类是API引入的,在苹果官网是不会承认的,所以不建议使用
*1.animation.type = @"cube"; //立方体效果
*2.animation.type = @"suckEffect";//犹如一块布被抽走
*3. animation.type = @"oglFlip"; //上下翻转效果
*4. animation.type = @"rippleEffect"; //滴水效果
*5. animation.type = @"pageCurl"; //向左翻页
*6.animation.type = @"pageUnCurl"; //向下翻页
// subtype
kCATransitionFromBottom
kCATransitionFromLeft
kCATransitionFromRight
kCATransitionFromTop
// timeFunction
CA_EXTERN CAMediaTimingFunctionName const kCAMediaTimingFunctionLinear
CA_EXTERN CAMediaTimingFunctionName const kCAMediaTimingFunctionEaseIn
CA_EXTERN CAMediaTimingFunctionName const kCAMediaTimingFunctionEaseOut
CA_EXTERN CAMediaTimingFunctionName const kCAMediaTimingFunctionEaseInEaseOut
CA_EXTERN CAMediaTimingFunctionName const kCAMediaTimingFunctionDefault