在APP开发过程中,总要设计到控制器的跳转。在IOS8中,苹果推出了UIPresentationController来管理所有modal的控制器。在这里,我们首选回顾一下,系统自带的modal转场动画效果。modalTransitionStyle分别有已下四种效果:
/*
UIModalTransitionStyleCoverVertical 默认效果:自下而上
UIModalTransitionStyleFlipHorizontal 翻转效果
UIModalTransitionStyleCrossDissolve 淡出效果
UIModalTransitionStylePartialCurl 上下翻页效果
*/
这个在使用的过程中,仅仅需要修改需要切换控制器的modalTransitionStyle分隔即可。
例如,单击主控制器的跳转到下一个控制器的实现
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//初始化要切换的控制器
UIViewController *vc = [[UIViewController alloc] init];
//设置其背景颜色
vc.view.backgroundColor = [UIColor redColor];
// 设置动画样式(系统自带的调整方式四种)
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
//控制器跳转
[self presentViewController:vc animated:YES completion:nil];
}
而到了IOS8以后,苹果推出UIPresentationController可以实现自定义的控制器切换效果,下面我们具体的来学习使用一下。
我们采用一个小demo示例来对其进行演示,首次采用了自动布局的来搭建界面。如下图所示:
其中前四个转场效果为苹果系统自带的,如前面讲到的只需要修改modalTransitionStyle的值即可。最后一个效果是自定义转场实现出来的效果,下面我们来进行具体的阐述
在单击了“自定义左右效果”按钮后,需要设置其 设置展示样式为自定义样式
vc.modalPresentationStyle = UIModalPresentationCustom;
除此之外,还需要三个对象来实现自定义过渡,一个UIPresentationController 的子类、一个遵从 UIViewControllerAnimatedTransitioning 协议的类以及遵从UIViewControllerTransitioningDelegate协议的类。
具体代码为:
//在ViewController中点击事件实现:
//要切换的控制器
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//初始化要切换的控制器
UIViewController *vc = [[UIViewController alloc] init];
//设置其背景颜色
vc.view.backgroundColor = [UIColor redColor];
//设置展示样式(自定义)
vc.modalPresentationStyle = UIModalPresentationCustom;
//设置代理(设置UIPresentationController)(为实现UIViewControllerTransitioningDelegate协议的类)
vc.transitioningDelegate = [Transition sharedtransition];
//控制器跳转
[self presentViewController:vc animated:YES completion:nil];
}
需要自定义转场动画后,需要实现要调整控制器的transitioningDelegate代理。创建实现UIViewControllerTransitioningDelegate协议的类(这里我们命名为Transition (并且将其设置成为单例)),在这个类中实现UIViewControllerTransitioningDelegate协议方法
#pragma mark - UIViewControllerTransitioningDelegate
//设置继承自UIPresentationController 的自定义类的属性
- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source
{
//return 一个UIPresentationController 的子类;
return [[PresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting];
}
//控制器创建执行的动画(返回一个实现UIViewControllerAnimatedTransitioning协议的类)
- (id )animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
//return 一个 UIViewControllerAnimatedTransitioning 协议的类;
//创建实现UIViewControllerAnimatedTransitioning协议的类(命名为AnimatedTransitioning)
AnimatedTransitioning *anim = [[AnimatedTransitioning alloc] init];
//将其状态改为出现
anim.presented = YES;
return anim;
}
//控制器销毁执行的动画(返回一个实现UIViewControllerAnimatedTransitioning协议的类)
- (id )animationControllerForDismissedController:(UIViewController *)dismissed
{
//return 一个 UIViewControllerAnimatedTransitioning 协议的类;
//创建实现UIViewControllerAnimatedTransitioning协议的类(命名为AnimatedTransitioning)
AnimatedTransitioning *anim = [[AnimatedTransitioning alloc] init];
//将其状态改为出现
anim.presented = NO;
return anim;
}
详细信息可以点此查看完整代码
下面首先实现一个 UIPresentationController 的子类(PresentationController)
//即将出现调用
- (void)presentationTransitionWillBegin{
//添加半透明背景 View 到视图中
UIView *transtioningView = [[UIView alloc] init];
transtioningView.backgroundColor = [UIColor colorWithRed:1.0 green:0.0 blue:1.0 alpha:0.5];
self.transtioningView = transtioningView;
self.transtioningView.frame = self.containerView.bounds;
self.transtioningView.alpha = 0.0;
[self.containerView addSubview:self.transtioningView];
//一旦要自定义动画,必须自己手动添加控制器
//设置尺寸(在动画中注意调整尺寸)
self.presentedView.frame = CGRectInset(self.containerView.bounds, 40, 60);
// 添加到containerView 上
[self.containerView addSubview:self.presentedView];
// 与过渡效果一起执行背景 View 的淡入效果
[[self.presentingViewController transitionCoordinator] animateAlongsideTransitionInView:self.transtioningView animation:^(id _Nonnull context) {
self.transtioningView.alpha = 1.0;
} completion:^(id _Nonnull context) {
}];
}
//出现调用
- (void)presentationTransitionDidEnd:(BOOL)completed{
// 如果呈现没有完成,那就移除背景 View
if (!completed){
[self.transtioningView removeFromSuperview];
}
}
//即将销毁调用
- (void)dismissalTransitionWillBegin{
// 与过渡效果一起执行背景 View 的淡入效果
[[self.presentingViewController transitionCoordinator] animateAlongsideTransitionInView:self.transtioningView animation:^(id _Nonnull context) {
self.transtioningView.alpha = 0.0;
} completion:^(id _Nonnull context) {
}];
}
//销毁调用
- (void)dismissalTransitionDidEnd:(BOOL)completed{
if (completed) {
//一旦要自定义动画,必须自己手动移除控制器
[self.presentedView removeFromSuperview];
[self.transtioningView removeFromSuperview];
}
详细信息可以点此查看完整代码
最后实现一个遵守UIViewControllerAnimatedTransitioning 协议的类(AnimatedTransitioning)
实现方法
#pragma mark - UIViewControllerAnimatedTransitioning
- (NSTimeInterval)transitionDuration:(nullable id )transitionContext{
//动画执行时间
return duration;
}
//实际动画效果(以后需要改的地方只有这里)
- (void)animateTransition:(id )transitionContext{
if (self.presented) {//创建控制器
UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
//toView.layer.transform = CATransform3DMakeRotation(M_PI_2, 1, 1, 1);3D动画
//toView.y = -toView.height;
toView.x = toView.width;
[UIView animateWithDuration:duration animations:^{
//toView.layer.transform = CATransform3DIdentity;3D动画
//toView.y = 0;
toView.x = 40;//注意同PresentationController设置的尺寸位置相关
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}else{//销毁控制器
[UIView animateWithDuration:duration animations:^{
UIView *fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
//fromView.layer.transform = CATransform3DMakeRotation(M_PI_2, 1, 1, 1);
//fromView.y = -fromView.height;
fromView.x = -fromView.width;
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
}
详细信息点此查看完整代码
这样只需要
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
这个方法中修改完成相应的转场动画。
最后对上述步骤进行总结归纳:
第一步:创建需要modal的控制器
UIViewController *vc = [[UIViewController alloc] init];
第二步: 设置展示样式(自定义)
vc.modalPresentationStyle = UIModalPresentationCustom;
第三步:成为其transitioningDelegate的代理
//Transition(单例)为一个实现UIViewControllerTransitioningDelegate协议的类
vc.transitioningDelegate = [Transition sharedtransition];
第四步:modal控制器
[self presentViewController:vc animated:YES completion:nil];
第五步:实现Transition(单例)类(一个实现了UIViewControllerTransitioningDelegate协议的类)
并实现代理方法
#pragma mark - UIViewControllerTransitioningDelegate
//设置继承自UIPresentationController 的自定义类的属性
- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source;
//控制器创建执行的动画(返回一个实现UIViewControllerAnimatedTransitioning协议的类)
- (id )animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
控制器销毁执行的动画(返回一个实现UIViewControllerAnimatedTransitioning协议的类)
- (id )animationControllerForDismissedController:(UIViewController *)dismissed;
第六步:根据第五步的代理方法创建一个继承自UIPresentationController 的自定义类,并在其中实现方法下述方法
//即将出现调用
- (void)presentationTransitionWillBegin;
//出现调用
- (void)presentationTransitionDidEnd:(BOOL)completed;
//即将销毁调用
- (void)dismissalTransitionWillBegin;
//销毁调用
- (void)dismissalTransitionDidEnd:(BOOL)completed;
第七步:根据第五步的代理方法创建一个实现UIViewControllerAnimatedTransitioning协议的类,并在其中实现下述方法,设置转场动画效果。
//常量,动画执行的时间
const CGFloat duration = 1.0;
#pragma mark - UIViewControllerAnimatedTransitioning
//动画执行的时间
- (NSTimeInterval)transitionDuration:(id)transitionContext;
//实际动画效果(以后需要改的地方只有这里)
- (void)animateTransition:(id )transitionContext;
按照相应逻辑实现,即可完成自定义转场动画。
最后:一个上述方法实现的小demo已经上传到github上,可以单击此处下载