iOS进阶之旅-可交互式转场动画
来源:互联网 发布:人文社科书籍推荐 知乎 编辑:程序博客网 时间:2024/06/06 02:32
iOS7苹果为开发者引入了一系列新的API。其中一个尤为出色的API是一个新的视图控制器转换API。有趣的是,对于这个API苹果大量使用了协议,而不是具体的对象。虽然有点奇怪,但这种定义方式为我们提供了极大的灵活性,在深入探讨这个API之前,让我们看一下另一个iOS7的新特性。
注意导航控制器在iOS7中默认行为的改变,在导航控制器不同视图切换之间的动画在iOS7之后现在略有不懂,它是可交互的,即我们俗称的右滑返回。
所谓转场动画就是视图切换动画,交互式就是动画切换的进度依赖于用户的操作。本文将围绕UINavigationController的push、pop操作切换控制器进行讨论。但,苹果所提供的API是同样支持控制器的present、dismiss操作切换控制器与UITabbarViewController切换控制器的,其实现原理基本一致,在次就不多赘述了,希望和我一样在探索进阶之路的,如果看到这篇博客后能对你起到帮助,能自己去实现present、dismiss(实现UIViewControllerTransitioningDelegate)与UITabbarViewController(实现UITabBarControllerDelegate)的转场切换。
废话不多说,直入主题,我们今天做一个非常简单的demo,首先是一个不可交互的转场动画,push为渐入效果,pop为从屏幕大小缩小为CGZero。
push、pop操作么,肯定要与navigation controller扯上点关系了,我们说了新的API是代理,让我们来一起看一下UINavigationControllerDelegate中的一个方法
navigationController
operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
官方描述:UIKit calls this method to obtain the timing information for your animations. The value you provide should be the same value that you use when configuring the animations in your animateTransition: method. UIKit uses the value to synchronize the actions of other objects that might be involved in the transition. For example, a navigation controller uses the value to synchronize changes to the navigation bar.
UIKit调用此方法来获得你的动画的时间信息。你配置的值应该与你在animatetransition:方法中设置的动画时间是一致的。UIKit使用该值来同步其他对象可能涉及过渡的行动。例如,导航控制器使用该值来对导航栏进行同步更改。简而言之,就是在这个方法里设置动画的时间
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
官方描述:
UIKit calls this method when presenting or dismissing a view controller. Use this method to configure the animations associated with your custom transition. You can use view-based animations or Core Animation to configure your animations.
看到这里聪明的你脑袋里肯定已经有思路了,我们将一个类声明为UINavigationController的代理,在其中实现
navigationController
operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface BWCustomPushAnimation :NSObject<UIViewControllerAnimatedTransitioning>
@end
#import "BWCustomPushAnimation.h"
@implementation BWCustomPushAnimation
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 3.0;
}
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
// 目的ViewController
UIViewController * toViewController = [transitionContextviewControllerForKey:UITransitionContextToViewControllerKey];
// 起始ViewController
UIViewController * fromViewController = [transitionContextviewControllerForKey:UITransitionContextFromViewControllerKey];
UIView * toView = toViewController.view;
UIView * fromView = fromViewController.view;
// 截图并添加
UIView * snapOfToView = [toViewsnapshotViewAfterScreenUpdates:YES];
[transitionContext.containerView addSubview:snapOfToView];
UIView * snapOfFromView = [fromView snapshotViewAfterScreenUpdates:YES];
[transitionContext.containerView addSubview:snapOfFromView];
// 动画实现
fromViewController.view.alpha =1;
toViewController.view.alpha =1;
[UIView animateWithDuration:[selftransitionDuration:transitionContext] animations:^{
snapOfFromView.alpha = 0;
} completion:^(BOOL finished) {
// 动画完成后一定要移除
[snapOfFromView removeFromSuperview];
[snapOfToView removeFromSuperview];
// 设置transitionContext通知系统动画执行完毕
[[transitionContext containerView]addSubview:toView];
[transitionContext completeTransition:![transitionContexttransitionWasCancelled]];
}];
}
@end
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface BWCustomPopAnimation :NSObject<UIViewControllerAnimatedTransitioning>
@end
.m文件
#import "BWCustomPopAnimation.h"
@implementation BWCustomPopAnimation
- (NSTimeInterval)transitionDuration:(nullableid <UIViewControllerContextTransitioning>)transitionContext{
return 3.0;
}
// This method can only be a nop if the transition is interactive and not a percentDriven interactive transition.
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{
UIViewController * toVC = [transitionContextviewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController * fromVC = [transitionContextviewControllerForKey:UITransitionContextFromViewControllerKey];
UIView * toView = toVC.view;
UIView * fromView = fromVC.view;
UIView * snapOfToView = [toViewsnapshotViewAfterScreenUpdates:YES];
[transitionContext.containerView addSubview:snapOfToView];
UIView * snapOfFromView = [fromView snapshotViewAfterScreenUpdates:YES];
[transitionContext.containerView addSubview:snapOfFromView];
// [snapOfToView setFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2.0, [UIScreen mainScreen].bounds.size.height/2.0, 10, 10)];
[snapOfFromView setFrame:[UIScreenmainScreen].bounds];
// snapOfToView.layer.transform = catran
[UIView animateWithDuration:[selftransitionDuration:transitionContext] animations:^{
[snapOfFromView setFrame:CGRectMake([UIScreenmainScreen].bounds.size.width/2.0, [UIScreenmainScreen].bounds.size.height/2.0,10, 10)];
// [snapOfToView setFrame:[UIScreen mainScreen].bounds];
}completion:^(BOOL finished) {
[snapOfFromView removeFromSuperview];
[snapOfToView removeFromSuperview];
[[transitionContext containerView]addSubview:toView];
[transitionContext completeTransition:![transitionContexttransitionWasCancelled]];
}];
}
@end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindowalloc]initWithFrame:[UIScreenmainScreen].bounds];
BBTFromVC * fromVC = [[BBTFromVCalloc]init];
[self.windowmakeKeyAndVisible];
UINavigationController * nav = [[UINavigationControlleralloc]initWithRootViewController:fromVC];
nav.interactivePopGestureRecognizer.enabled =YES;
self.window.rootViewController = nav;
return YES;
}
- (nullableid <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC{
if (operation ==UINavigationControllerOperationPush) {
return self.customPush;
}elseif (operation ==UINavigationControllerOperationPop){
return self.custonPop;
}
return nil;
}
在viewDidLoad中声明代理
self.navigationController.delegate = self;
customPush与customPop的懒加载
-(BWCustomPushAnimation *)customPush
{
if (_customPush ==nil) {
_customPush = [[BWCustomPushAnimationalloc]init];
}
return_customPush;
}
-(BWCustomPopAnimation *)custonPop{
if (_custonPop ==nil) {
_custonPop = [[BWCustomPopAnimationalloc]init];
}
return_custonPop;
}
至此,你发现我们所需要的功能完美实现了,但真的是完美么,比如右滑返回呢,你会发现右滑返回失效了,专注用户体验三十年的我们,这种事情当然不能忍。我们需要加上右滑返回,而这就是我们所说的可交互式转场动画。(可交换式转场动画并不等于右滑返回,我们前面说了,苹果为我们提供了极大的灵活性,可交换式转场动画比你想象的强大,我们只是以可交互式转场动画作为右划返回的一种实现方式)。一起看一下系统API,同样是在UINavigationControllerDelegaate中
- (nullableid <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>)
官方文档:Implement this delegate method when you want to provide a custom, interactive transition between view controllers as they are added to or removed from the navigation stack.
- (void)updateInteractiveTransition:(CGFloat)
percentComplete
- (nullableid <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController{
returnself.interactionController;
}
@property(nonatomic,strong)UIPercentDrivenInteractiveTransition * interactionController;
注册手势
UIPanGestureRecognizer * panRecognizer = [[UIPanGestureRecognizeralloc]initWithTarget:selfaction:@selector(didClickPanGestureRecognizer:)];
[self.navigationController.viewaddGestureRecognizer:panRecognizer];
-(void)didClickPanGestureRecognizer:(UIPanGestureRecognizer *)recognizer{
UIView * view = self.view;
if (recognizer.state ==UIGestureRecognizerStateBegan) {
if (self.navigationController.viewControllers.count == 2) {
self.interactionController = [[UIPercentDrivenInteractiveTransitionalloc]init];
[self.navigationControllerpopViewControllerAnimated:YES];
}
}elseif (recognizer.state ==UIGestureRecognizerStateChanged){
CGPoint translation = [recognizer translationInView:view];
CGFloat distance = translation.x/CGRectGetWidth(view.bounds);
if (distance > 0) {
[self.interactionControllerupdateInteractiveTransition:distance];
}
}elseif (recognizer.state ==UIGestureRecognizerStateEnded){
CGPoint translation = [recognizer translationInView:view];
CGFloat distance = fabs(translation.x/CGRectGetWidth(view.bounds));
if (distance > 0.5) {
[self.interactionControllerfinishInteractiveTransition];
}else{
[self.interactionControllercancelInteractiveTransition];
}
// self.interactionController一定要设置为nil,否则你可能在你不想返回的时候返回一个interactionController
self.interactionController =nil;
}
}
- iOS进阶之旅-可交互式转场动画
- iOS之转场动画/自定义转场动画
- VCTransitionsLibrary –自定义iOS交互式转场动画的库
- IOS动画之 转场动画 CATransition
- iOS新特性之转场动画
- iOS开发之 转场动画CATransition
- iOS开发之核心转场动画
- iOS学习之——转场动画
- ios开发之自定义转场动画
- 八 iOS之 CATransition (转场动画)
- UIPercentDrivenInteractiveTransition Controller交互式转场切换动画
- iOS抽奖转盘动画之转场动画与动画组
- IOS 动画 核心动画之转场动画CATransition
- UIView转场动画 IOS
- iOS 导航转场动画
- iOS自定义转场动画
- ios 转场动画
- iOS自定义转场动画
- 九度题目1126:打印极值点下标
- 杂谈(fastcgi)
- eclipse 阅读代码 快捷键
- uva10524
- java求百分比
- iOS进阶之旅-可交互式转场动画
- caffe常见问题
- C++中虚析构函数的作用
- poj1311 Octal Fractions
- HDU 1599 find the mincost route(floyd求无向图)
- MongoDB安装
- 具有交互功能的对话框
- 第一篇CSDN文章
- 利用jackson-dataformat-csv读写csv文件