iOS8中苹果给我们来带来了一个新的类—— UIPresentationController
。和UIViewControllerTransitioning
一样,它也是配合自定义过渡的。在实践中,往往也是配合UIViewControllerTransitioning
一起来实现自定义的转场动画。今天我们要实现的一个转场是这样的:
我们的 UIPresentationController
的子类是负责「被呈现」(presented) 及「负责呈现」(presenting) 的 controller 以外的 controller 的,看着很绕口,说白了,在我们的例子中,它负责的仅仅是那个带渐变效果的黑色模糊背景 View和背景视图的动态缩放。
UIPresentationController.h
的内容其实不多,也就80行代码。其中我们我们必须实现的有这四个方法:
- (void)presentationTransitionWillBegin;////在呈现过渡即将开始的时候被调用的
- (void)presentationTransitionDidEnd:(BOOL)completed;////在呈现过渡结束时被调用的
- (void)dismissalTransitionWillBegin;//在退出过渡即将开始的时候被调用的
- (void)dismissalTransitionDidEnd:(BOOL)completed;//在退出的过渡结束时被调用的
按照上面gif显示的效果,我们可以在- (void)presentationTransitionWillBegin;
中做如下操作:
- (void)presentationTransitionWillBegin{
//创建视图
self.bgView = [[UIView alloc]initWithFrame:[UIScreen mainScreen].bounds];
self.blurView = [[UIVisualEffectView alloc]initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
self.blurView.frame = self.containerView.bounds;
[self.bgView insertSubview:self.blurView atIndex:0];
self.contview = self.containerView;
[self.contview addSubview:self.presentingViewController.view];
[self.contview addSubview:self.bgView];
[self.contview addSubview:self.presentedView];
// 使用 presentingViewController 的 transitionCoordinator,
// 背景 bgView 的淡入效果与过渡效果一起执行
self.bgView.alpha = 0.0;
self.transitionCoordinator = self.presentingViewController.transitionCoordinator;
[self.transitionCoordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
self.bgView.alpha = 0.7;
self.presentingViewController.view.transform = CGAffineTransformScale(self.presentingViewController.view.transform, 0.92, 0.92);
} completion:nil];
}
还是比较容易看懂的。无非就是就是新建了一个背景,上面加一个UIVisualEffectView
的带模糊效果的视图。然后让背景的alpha从0变到1。同时我们还做了让底下那个视图x、y都缩放到原来的0.92倍。
如果没有完成,移除视图。
//在呈现过渡结束时被调用的
//如果呈现没有完成,那就移除背景 View
- (void)presentationTransitionDidEnd:(BOOL)completed{
if (!completed) {
[self.bgView removeFromSuperview];
}
}
同理,dismissalTransitionWillBegin
方法中,我们把背景层的透明度恢复到0.同时也让底下的视图恢复transform.
- (void)dismissalTransitionWillBegin{
// 与过渡效果一起执行背景 View 的淡出效果
self.transitionCoordinator = self.presentingViewController.transitionCoordinator;
[self.transitionCoordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
self.bgView.alpha = 0;
self.presentingViewController.view.transform = CGAffineTransformIdentity;
} completion:nil];
}
最后,成功完成dismiss之后移除视图。
- (void)dismissalTransitionDidEnd:(BOOL)completed{
if (completed) {
[self.bgView removeFromSuperview];
}
[[[UIApplication sharedApplication]keyWindow]addSubview:self.presentingViewController.view];
}
这里要说明一点的是,如果没有[[[UIApplication sharedApplication]keyWindow]addSubview:self.presentingViewController.view];
这一句的话,dismiss结束之后背景会变黑,原因是presentingViewController
随着self.containerView
被一同销毁了。我在Stackoverflow终于找到了答案,据说是iOS8的bug,同时解决方案是在window上重新添加一下,也就是[[[UIApplication sharedApplication]keyWindow]addSubview:self.presentingViewController.view];
.
使用方式和前三篇博文提到的UIViewControllerTransitioning
一样,在presented的ViewController中实现UIViewControllerTransitioningDelegate
协议,并且重载下面这个方法就可以了:
- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator{
if (animator) {
return percentDrivenInteractiveTransition;
}else{
return nil;
}
}
老规矩,全部代码已开源(这里),供学习参考。
转载请注明出处,万分感谢!