iOS7自定义视图控制器过渡3-关于Push和Pop的过渡
来源:互联网 发布:怎么查淘宝买家信息 编辑:程序博客网 时间:2024/06/05 23:50
前言:在之前的俩篇中,很多人可能发现我们一直在用模态的方式转换控制器,但是在开发过程中大多数情况下是用导航控制器来管理自己的视图控制器的。那么在Push或Pop的时候怎么实现过渡效果呢?其实很简单,和之前的基本一样,只是返回事件动画对象和手势交互动画对象的代理方法不一样了(此时是UINavigationControllerDelegate中的方法)仅此而已。那么,举个例子来练习一下吧。
正文:
Push时的效果:
Pop时的效果:
1. 创建俩个视图控制器,FirstCollectionViewController和SecondViewController
在这里只贴出一些关键性的代码,以免影响阅读,完整代码在文章最后有下载。
FirstCollectionViewController
@interface FirstCollectionViewController : UICollectionViewController@property (nonatomic, strong) NSIndexPath *seletedIndexPath;@end@interface FirstCollectionViewController () <UINavigationControllerDelegate>@end@implementation FirstCollectionViewController- (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; self.navigationController.delegate = self;}- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ SecondViewController *secondVc = [[SecondViewController alloc] init]; [self.navigationController pushViewController:secondVc animated:YES];}#pragma mark - UINavigationControllerDelegate- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{ if (operation == UINavigationControllerOperationPush) { FlatZoomPushTransition *pushTransition = [[FlatZoomPushTransition alloc] init]; return pushTransition; } return nil;}
(1) 可以看出只要在NavigationController的代理方法中,返回事件动画对象就ok了。和模态方式比较只是返回的方法不同而已。
SecondViewController
@interface SecondViewController : UIViewController@property (nonatomic, assign) UIImageView *imageInSecond;@end@interface SecondViewController () <UINavigationControllerDelegate>@property (nonatomic, strong) FlatZoomInteractivePopTransition *popInteractiveTransition;@end@implementation SecondViewController- (void)viewDidLoad { [super viewDidLoad]; self.popInteractiveTransition = [[FlatZoomInteractivePopTransition alloc] initWithController:self];}- (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; self.navigationController.delegate = self;}- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{ if (operation == UINavigationControllerOperationPop) { FlatZoomPopTransition *popTransition = [[FlatZoomPopTransition alloc] init]; return popTransition; } return nil;}- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController{ if ([animationController isKindOfClass:[FlatZoomPopTransition class]]) { return self.popInteractiveTransition.interactiving ? self.popInteractiveTransition : nil; } return nil;}
(1)注意俩个视图控制器中代理对象设置的位置都是在viewWillAppear中。这是为什么呢?
首先,当SecondViewController显示出来后,当前NavigationController的代理对象变为当前控制器,所以在FirstCollectionViewController重新出现时,需要将代理对象变为FirstCollectionViewController,所以viewWillAppear是比较合适的位置。
其次,当在当SecondViewController中用手势移除控制器的过程中,有可能会取消手势,此时会比较尴尬,因为FirstCollectionViewController的View已经出现了,所以navigationController的代理又被设置成了FirstCollectionViewController对象,所以需要在viewWillAppear中将代理对象重新设置回SecondViewController。
2.分析动画实现的策略:
Push的动画过程
在点击cell之后,将点击的cell截图
—>截图放在containerView上覆盖住cell上的图片(坐标系转换),并隐藏cell上的图片
—> 获取详情控制器中大图,算出该图在containerView中的坐标(坐标系转换),并隐藏该图
—> 图层关系:FirstCollectionViewController的View(最下面),SecondViewController的View(中间),截图(最上面)
—> 对SecondViewController的view的alpha和截图的frame做动画
—> 动画结束后,将截图移除,大图和cell上的图片都显示出来即可。
Pop的过程基本上是Push的逆向:
在过渡开始时,将SecondViewController中的大图截图放在containerView上覆盖住原图片(坐标系转换),隐藏大图。
—> 获取FirstCollectionViewController中之前被选中的cell,算出该cell中图片在containerView中的坐标(坐标系转换),隐藏该图片。
—> 图层关系:FirstCollectionViewController的View(最下面),SecondViewController的View(中间),截图(最上面)
—> 对SecondViewController的view的alpha和截图的frame做动画
—> 动画结束后,将截图移除,cell上的图片显示出来即可。
坐标转换可用下面方法完成:
- (CGRect)convertRect:(CGRect)rect fromView:(UIView *)view;
Push的事件动画对象:FlatZoomPushTransition
@implementation FlatZoomPushTransition- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{ return 0.8f;}- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{ // 1. 获取源和目标控制器 FirstCollectionViewController *fromVc = (FirstCollectionViewController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; SecondViewController *toVc = (SecondViewController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIView *containerView = [transitionContext containerView]; // 2. 将cell中的imageView截图,并对截图设置frame // 1) 找到选中的cell NSIndexPath *seletedIndexPath = [[fromVc.collectionView indexPathsForSelectedItems] firstObject]; // pop时会用到 fromVc.seletedIndexPath = seletedIndexPath; FirstCellCollectionViewCell *cell = (FirstCellCollectionViewCell *)[fromVc.collectionView cellForItemAtIndexPath:seletedIndexPath]; // 2) 截图 UIView *snapShotView = [cell.imageInCell snapshotViewAfterScreenUpdates:NO]; cell.imageInCell.hidden = YES; // 3) 转换坐标系 CGRect snapShotFrame = [containerView convertRect:cell.imageInCell.frame fromView:cell]; snapShotView.frame = snapShotFrame; // 3. 设置目标控制器的view的初始状态 toVc.view.frame = [transitionContext finalFrameForViewController:toVc]; toVc.view.alpha = 0.0f; toVc.imageInSecond.hidden = YES; // 注意顺序 [containerView addSubview:toVc.view]; [containerView addSubview:snapShotView]; // 4. 动画 NSTimeInterval duration = [self transitionDuration:transitionContext]; CGRect snapShotFinialFrame = [containerView convertRect:toVc.imageInSecond.frame fromView:toVc.view]; [UIView animateWithDuration:duration delay:0 usingSpringWithDamping:0.5f initialSpringVelocity:0.5f options:UIViewAnimationOptionCurveEaseIn animations:^{ snapShotView.frame = snapShotFinialFrame; toVc.view.alpha = 1.0f; } completion:^(BOOL finished) { cell.imageInCell.hidden = NO; toVc.imageInSecond.hidden = NO; [snapShotView removeFromSuperview]; [transitionContext completeTransition:YES]; }];}
Pop的事件动画对象:FlatZoomPopTransition
@implementation FlatZoomPopTransition- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{ return 0.8f;}- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{ // 1. 获取源和目标控制器 SecondViewController *fromVc = (SecondViewController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; FirstCollectionViewController *toVc = (FirstCollectionViewController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIView *containerView = [transitionContext containerView]; // 2. 截图,并设置截图在containerView中的frame UIView *snapShotView = [fromVc.imageInSecond snapshotViewAfterScreenUpdates:NO]; fromVc.imageInSecond.hidden = YES; CGRect currentFrame = [containerView convertRect:fromVc.imageInSecond.frame fromView:fromVc.view]; snapShotView.frame = currentFrame; // 3. 设置目标控制器的初始状态 toVc.view.frame = [transitionContext finalFrameForViewController:toVc]; // 1). 获取cell隐藏图片 FirstCellCollectionViewCell *cell =(FirstCellCollectionViewCell *)[toVc.collectionView cellForItemAtIndexPath:toVc.seletedIndexPath]; cell.imageInCell.hidden = YES; // 注意放置顺序 [containerView insertSubview:toVc.view belowSubview:fromVc.view]; [containerView addSubview:snapShotView]; // 4. 动画 CGRect finialFrame = [containerView convertRect:cell.imageInCell.frame fromView:cell]; [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:0.8 options:UIViewAnimationOptionCurveEaseInOut animations:^{ fromVc.view.alpha = 0.0f; snapShotView.frame = finialFrame; } completion:^(BOOL finished) { cell.imageInCell.hidden = NO; fromVc.imageInSecond.hidden = NO; [snapShotView removeFromSuperview]; [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; }];}
Pop的手势交互动画对象:FlatZoomInteractivePopTransition
@interface FlatZoomInteractivePopTransition : UIPercentDrivenInteractiveTransition- (instancetype)initWithController:(UIViewController *)vc;@property (nonatomic, assign) BOOL interactiving;@end@interface FlatZoomInteractivePopTransition ()@property (nonatomic, strong) UIViewController *vc;@end@implementation FlatZoomInteractivePopTransition- (instancetype)initWithController:(UIViewController *)vc{ if (self = [super init]) { UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)]; [vc.view addGestureRecognizer:panGestureRecognizer]; self.vc = vc; } return self;}- (void)panAction:(UIPanGestureRecognizer *)panGestureRecognizer{ CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width; // 手指横向移动距离 CGFloat translationx = [panGestureRecognizer translationInView:panGestureRecognizer.view].x; // 手势完成度 CGFloat complatedRation = translationx / (screenWidth * 1); // 将比例限制在0~1之间 complatedRation = MIN(1.0, MAX(0.0, complatedRation)); if (panGestureRecognizer.state == UIGestureRecognizerStateBegan) { self.interactiving = YES; [self.vc.navigationController popViewControllerAnimated:YES]; } else if (panGestureRecognizer.state == UIGestureRecognizerStateChanged) { // 告知系统汇报进度 [self updateInteractiveTransition:complatedRation]; } else if (panGestureRecognizer.state == UIGestureRecognizerStateCancelled) { self.interactiving = NO; // 告知系统取消过渡 [self cancelInteractiveTransition]; } else if (panGestureRecognizer.state == UIGestureRecognizerStateEnded) { self.interactiving = NO; // 手指从屏幕抬起时,手势进行一半即可认为是完成过渡,反则取消过渡 if (complatedRation > 0.5) { [self finishInteractiveTransition]; } else { [self cancelInteractiveTransition]; } }}@end
Demo地址:FlatZoomTransition-Demo
- iOS7自定义视图控制器过渡3-关于Push和Pop的过渡
- iOS7自定义视图控制器过渡4-自定义手势过渡动画
- iOS7自定义视图控制器过渡1-动作过渡
- iOS7自定义视图控制器过渡2-手势交互过渡
- 实例 关于自定义Push Pop过渡
- 自定义Push和Pop过渡动画
- 自定义NavigationController 的Push 和 Pop过渡动画
- iOS7 interactive transitions(视图控制器的过渡动画 )
- ios开发 自定义带弧度的UITabBar,保留系统原有push和pop过渡效果
- pop push UIViewController 手势过渡动画
- ios7在push和pop视图出现视图少一块的解决方法
- iOS7新特性 ViewController转场切换(二) 系统视图控制器容器的切换动画---push pop present dismis
- iOS7新特性 ViewController转场切换(二) 系统视图控制器容器的切换动画---push pop present
- iOS7新特性 ViewController转场切换(二) 系统视图控制器容器的切换动画---push pop present dismis
- 自定义控制器的转场动画(Push、Pop)
- 自定义控制器的转场动画(Push、Pop)
- 控制器转场动画自定义(1):push/pop的实现
- 自定义过渡
- php 安装以及入门脚本
- 如何让 IIS Express 支持其他机器访问
- 微信公众帐号开发教程第1篇-引言
- [H2]嵌入式数据库配置及自定义函数扩展
- phpMyAdmin 安装配置
- iOS7自定义视图控制器过渡3-关于Push和Pop的过渡
- Binary Tree Inorder Traversal
- 【美团】外卖配送事业部面试
- MVC 原理
- Sql server2008 判断字段不为空
- Xcode - ld: library not found for -lPods -******* 错误
- 微信公众帐号开发教程第3篇-开发模式启用及接口配置
- 利用ajax的getJSON读取数据时注意的问题
- 《开源框架那点事儿34》:Tiny模板语言(VelocityPlus)初步入门