iOS开发自定义转场动画
1、转场动画
iOS7之后开发者可以自定义界面切换的转场动画,就是在模态弹出(present、dismiss),Navigation的(push、pop),TabBar的系统切换效果之外自定义切换动画!
模态弹出自定义出push、pop效果,可以侧滑:
2、实现步骤
2.1、自定义转场动画
1》创建自定义文件
@interface CustomTransform : NSObject<UIViewControllerAnimatedTransitioning>
2》实现UIViewControllerAnimatedTransitioning方法
//设置转场时间
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
//设置转场效果
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
.m相关类说明:
//表示转场动画上下文
UIViewControllerContextTransitioning
//当前控制器fromVC和目标控制器toVC
//vc1-->present-->vc2: fromVC是vc1,toVC是vc2
//vc2-->dismiss-->vc1: fromVC是vc2,toVC是vc1
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//对应控制器的view视图
UIView *fromView =[transitionContext viewForKey:UITransitionContextFromViewKey];
UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey]; //presentingViewController,presentedViewController
vc1-->present-->vc2,vc1.presentedViewController 就是vc2;vc2.presentingViewController 就是vc1。 //更新动画进度
- (void)updateInteractiveTransition:(CGFloat)percentComplete;
//转场结束
- (void)finishInteractiveTransition;
//转场取消
- (void)cancelInteractiveTransition;
自定义文件:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h> typedef NS_ENUM(NSInteger, PresentType){
PresentTypePresent,
PresentTypeDismiss
}; @interface CustomTransform : NSObject<UIViewControllerAnimatedTransitioning> + (instancetype)makeWithTransitionType:(PresentType)type;
- (instancetype)initWithTransitionType:(PresentType)type; @end
.h文件
#import "CustomTransform.h" @interface CustomTransform() @property(nonatomic, assign)PresentType type;
@property(nonatomic, strong)UIView *containerView;
@end @implementation CustomTransform
+ (instancetype)makeWithTransitionType:(PresentType)type
{
return [[self alloc] initWithTransitionType:type];
} - (instancetype)initWithTransitionType:(PresentType)type
{
if (self == [super init]) {
_type = type;
}
return self;
} - (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext
{
return .;
} - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
switch (_type) {
case PresentTypePresent:
[self presentTransform:transitionContext];
break;
case PresentTypeDismiss:
[self dismissTransform:transitionContext];
break;
default:
break;
} } - (void)presentTransform:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
self.containerView = [transitionContext containerView]; UIView *fromView =[transitionContext viewForKey:UITransitionContextFromViewKey];
UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey];
[self.containerView addSubview:toView];
CGRect visibleFrame = [transitionContext initialFrameForViewController:fromVC];
CGRect rightHiddenFrame = CGRectMake( CGRectGetWidth(visibleFrame), ,CGRectGetWidth(visibleFrame),CGRectGetHeight(visibleFrame));
CGRect leftHiddenFrame =CGRectMake(- CGRectGetWidth(visibleFrame), , CGRectGetWidth(visibleFrame), CGRectGetHeight(visibleFrame));
fromView.frame = visibleFrame;
toView.frame = rightHiddenFrame;
fromView.layer.masksToBounds = toView.layer.masksToBounds = YES;
[self.containerView insertSubview:toView atIndex:];
[UIView animateWithDuration:.
animations:^{
fromView.frame = leftHiddenFrame;
toView.frame = visibleFrame;
}
completion:^(BOOL finished) {
if ([transitionContext transitionWasCancelled]) {
[toView removeFromSuperview];
}
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}]; } - (void)dismissTransform:(id<UIViewControllerContextTransitioning>)transitionContext
{ UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
self.containerView = [transitionContext containerView]; UIView *fromView =[transitionContext viewForKey:UITransitionContextFromViewKey];
UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey];
[self.containerView addSubview:toView];
CGRect visibleFrame = [transitionContext initialFrameForViewController:fromVC];
CGRect rightHiddenFrame = CGRectMake( CGRectGetWidth(visibleFrame), ,CGRectGetWidth(visibleFrame),CGRectGetHeight(visibleFrame));
CGRect leftHiddenFrame =CGRectMake(- CGRectGetWidth(visibleFrame), , CGRectGetWidth(visibleFrame), CGRectGetHeight(visibleFrame));
fromView.frame = visibleFrame;
toView.frame = leftHiddenFrame;
fromView.layer.masksToBounds = toView.layer.masksToBounds = YES;
[UIView animateWithDuration:.
animations:^{
fromView.frame = rightHiddenFrame;
toView.frame = visibleFrame;
}
completion:^(BOOL finished) {
if ([transitionContext transitionWasCancelled]) {
[toView removeFromSuperview];
}
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
} @end
.m文件
2.2、自定义交互手势
1》创建自定义文件
@interface CustonInteractive : UIPercentDrivenInteractiveTransition
因为UIPercentDrivenInteractiveTransition : NSObject <UIViewControllerInteractiveTransitioning>,所以自定义时继承遵循UIViewControllerInteractiveTransitioning协议的UIPercentDrivenInteractiveTransition子类!
2》相关文件:
#import <UIKit/UIKit.h> @interface CustonInteractive : UIPercentDrivenInteractiveTransition @property (nonatomic, assign) BOOL interacting; - (void)wireToViewController:(UIViewController*)viewController; @end
.h
#import "CustonInteractive.h" @interface CustonInteractive()
@property (nonatomic, strong) UIViewController *presentingVC; @end @implementation CustonInteractive
-(void)wireToViewController:(UIViewController *)viewController
{
self.presentingVC = viewController;
[self prepareGestureRecognizerInView:viewController.view];
} - (void)prepareGestureRecognizerInView:(UIView*)view {
UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
[view addGestureRecognizer:gesture];
}
- (void)handleGesture:(UIPanGestureRecognizer *)gestureRecognizer {
CGFloat progress = [gestureRecognizer translationInView:gestureRecognizer.view.superview].x / (self.presentingVC.view.bounds.size.width * 1.0);
progress = MIN(1.0, MAX(0.0, progress));//把这个百分比限制在0~1之间
NSLog(@"===%lf",progress);
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
self.interacting = YES;
[self.presentingVC dismissViewControllerAnimated:YES completion:nil];
}
else if (gestureRecognizer.state == UIGestureRecognizerStateChanged){
if (self.interacting) {
[self updateInteractiveTransition:progress];
}
}else if (gestureRecognizer.state == UIGestureRecognizerStateCancelled||gestureRecognizer.state==UIGestureRecognizerStateEnded){
if (self.interacting) {
if (progress>0.5) {
[self finishInteractiveTransition];
}else{
[self cancelInteractiveTransition];
}
self.interacting = NO;
}
}
} @end
.m
2.3、使用自定义转场动画
1》设置代理(以模态弹出为例)设置目标控制器的 transitioningDelegate
- (IBAction)present:(id)sender {
PresentedViewController *vc = [[PresentedViewController alloc] init];
vc.transitioningDelegate = self;
[_transitionController wireToViewController:vc];
[self presentViewController:vc animated:YES completion:nil];
}
附加:Navigation和TabBar代理设置(self.delegate = self)
2》实现UIViewControllerTransitioningDelegate代理方法
//设置弹出时动画协议
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
//设置消失时动画协议
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;
//设置消失时手势协议
- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator;
vc1的.m文件:
#import "PresentingViewController.h"
#import "CustomTransform.h"
#import "CustonInteractive.h"
#import "PresentedViewController.h" #import "SecondTransform.h"
#import "SecondInteractive.h"
@interface PresentingViewController ()<UIViewControllerTransitioningDelegate,UINavigationControllerDelegate,UITabBarControllerDelegate>{
SecondTransform *_presentAnimation;
SecondInteractive *_transitionController;
} @end @implementation PresentingViewController - (void)viewDidLoad {
[super viewDidLoad];
_presentAnimation = [SecondTransform new];
_transitionController = [SecondInteractive new];
// Do any additional setup after loading the view from its nib.
}
- (IBAction)present:(id)sender {
PresentedViewController *vc = [[PresentedViewController alloc] init];
vc.transitioningDelegate = self;
[_transitionController wireToViewController:vc];
[self presentViewController:vc animated:YES completion:nil];
}
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
return _presentAnimation;
} - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
return [SecondTransform makeWithTransitionType:PresentTransformAnimationTypeDismissed];
} -(id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator {
return _transitionController.isInterraction ? _transitionController : nil;
}
@end
.m
Navigation和TabBar的代理方法:
#pragma mark---UINavigationControllerDelegate
/*
- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0); - (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);
*/ #pragma mark-UITabBarControllerDelegate
/*
- (nullable id <UIViewControllerInteractiveTransitioning>)tabBarController:(UITabBarController *)tabBarController
interactionControllerForAnimationController: (id <UIViewControllerAnimatedTransitioning>)animationController NS_AVAILABLE_IOS(7_0); - (nullable id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController
animationControllerForTransitionFromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);
*/
Navigation和TabBar的delegate
iOS开发自定义转场动画的更多相关文章
- iOS开发——自定义转场动画
首先是UIPresentationController,这个控制器给modal新的viewController提供了下一步的view和转场的管理,从一个viewController被modal出来到被 ...
- iOS CATransition 自定义转场动画
https://www.jianshu.com/p/39c051cfe7dd CATransition CATransition 是CAAnimation的子类(如下图所示),用于控制器和控制器之间的 ...
- 一行代码实现自定义转场动画--iOS自定义转场动画集
WXSTransition 这款非常不错,力推 这是作者源码简书地址: http://www.jianshu.com/p/fd3154946919 这是作者源码github地址 https://git ...
- iOS开发UI篇—核心动画(转场动画和组动画)
转自:http://www.cnblogs.com/wendingding/p/3801454.html iOS开发UI篇—核心动画(转场动画和组动画) 一.转场动画简单介绍 CAAnimation的 ...
- iOS自定义转场动画的实现
iOS中熟悉的是导航栏中的push和pop这两种动画效果,在这里我们可以自己实现自己想要的一些转场动画 下面是我自己创建转场动画的过程 1.新建一个文件继承自NSObject ,遵循协议UIViewC ...
- iOS 自定义转场动画
代码地址如下:http://www.demodashi.com/demo/12955.html 一.总效果 本文记录分享下自定义转场动画的实现方法,具体到动画效果:新浪微博图集浏览转场效果.手势过渡动 ...
- iOS 自定义转场动画浅谈
代码地址如下:http://www.demodashi.com/demo/11612.html 路漫漫其修远兮,吾将上下而求索 前记 想研究自定义转场动画很久了,时间就像海绵,挤一挤还是有的,花了差不 ...
- iOS自定义转场动画实战讲解
iOS自定义转场动画实战讲解 转场动画这事,说简单也简单,可以通过presentViewController:animated:completion:和dismissViewControllerA ...
- Swift开发小技巧--自定义转场动画
自定义转场动画 个人理解为重写了被弹出控制器的modal样式,根据自己的样式来显示modal出来的控制器 例:presentViewController(aVC, animated: true, co ...
随机推荐
- css元素垂直居中
一.碎碎念:啊啊啊,原谅我只能起一个酱紫微大众微俗气的标题,因为实在没有什么能比这样表达的更清楚直观了呢! 二.没有知识储备,直接上示例: 1.思路:给父元素添加display: table属性:给子 ...
- RabbitMQ学习第二记:工作队列的两种分发方式,轮询分发(Round-robin)和 公平分发(Fair dispatch)
1.什么是RabbitMQ工作队列 我们在应用程序使用消息系统时,一般情况下生产者往队列里插入数据时速度是比较快的,但是消费者消费数据往往涉及到一些业务逻辑处理导致速度跟不上生产者生产数据.因此如果一 ...
- C++之constexpr
一.常量表达式:是指值不会改变并且在编译过程就能得到计算结果的表达式.一个对象是不是常量表达式是由它的数据类型和初始值共同决定. ;//虽然初始值是字面值常量,但是它的数据类型只是普通int. con ...
- Odoo Javascript 参考
本文介绍了odoo javascript框架.从代码行的角度来看,这个框架不是一个大的应用程序,但它是非常通用的,因为它基本上是一个将声明性接口描述转换为活动应用程序的机器,能够与数据库中的每个模型和 ...
- centos 下载并安装nodejs
安装方法1——直接部署 1.首先安装wget ,这个一般都有自带有的,可能已经在系统里安装好了的. yum install -y wget 如果已经安装了可以跳过该步 2.下载nodejs最新的tar ...
- 初识Qgis
折腾了一天,qgis终于能在跟了自己8年的本本上顺利打开了,官网先后下载了3.8和3.4版本的都出现了同样的问题,"could not load qgis_app.dll",goo ...
- 异或+桶——cf768C
有个结论是到最后肯定出现循环节..感觉这种做法有点歪 正解当然是题解啦 虽然到了1e8,但是cf上还是能过的 #include<bits/stdc++.h> #define rep(i,s ...
- HTTP协议基础篇(帮助理解)
用uml 来描述一个功能是怎样按照时间的顺序完成的 实际的需求(配置网站/配置虚拟主机) 步骤 (1) 打开 apache/conf/httpd.conf 文件 (2)找到hosts文件 c:/win ...
- 如何使用Python-GnuPG和Python3 实现数据的解密和加密
介绍 GnuPG包提供用于生成和存储加密密钥的完整解决方案.它还允许您加密和签名数据和通信. 在本教程中,您将创建一系列使用Python 3和python-gnupg模块的脚本.这些脚本允许您对多个文 ...
- URL类发送请求
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import jav ...