@上一章,介绍了主要的iOS7所增加的API,可以发现,它们不是一个个死的方法,苹果给我们开发者提供的是都是协议接口,所以我们能够很好的单独提出来写成一个个类,在里面实现我们各种自定义效果.
1.先来看看实现UIViewControllerAnimatedTransitioning的自定义动画类
/**
* 自定义的动画类
* 实现协议——>@protocol UIViewControllerAnimatedTransitioning
* 这个接口负责切换的具体内容,也即“切换中应该发生什么”
*/
@interface MTHCustomAnimator : NSObject
@end
@implementation MTHCustomAnimator
// 系统给出一个切换上下文,我们根据上下文环境返回这个切换所需要的花费时间
- (NSTimeInterval)transitionDuration:(id)transitionContext
{
return 1.0;
}
// 完成容器转场动画的主要方法,我们对于切换时的UIView的设置和动画都在这个方法中完成
- (void)animateTransition:(id)transitionContext
{
// 可以看做为destination ViewController
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// 可以看做为source ViewController
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
// 添加toView到容器上
[[transitionContext containerView] addSubview:toViewController.view];
toViewController.view.alpha = 0.0;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
// 动画效果有很多,这里就展示个左偏移
fromViewController.view.transform = CGAffineTransformMakeTranslation(-320, 0);
toViewController.view.alpha = 1.0;
} completion:^(BOOL finished) {
fromViewController.view.transform = CGAffineTransformIdentity;
// 声明过渡结束–>记住,一定别忘了在过渡结束时调用 completeTransition: 这个方法
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
PS:从协议中两个方法可以看出,上面两个必须实现的方法需要一个转场上下文参数,这是一个遵从UIViewControllerContextTransitioning 协议的对象。通常情况下,当我们使用系统的类时,系统框架为我们提供的转场代理(Transitioning Delegates),为我们创建了转场上下文对象,并把它传递给动画控制器。
// MainViewController
@interface MTHMainViewController ()
#pragma mark - UINavigationControllerDelegate iOS7新增的2个方法
// 动画特效
- (id) navigationController:(UINavigationController )navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController )fromVC toViewController:(UIViewController *)toVC
{
/**
* typedef NS_ENUM(NSInteger, UINavigationControllerOperation) {
* UINavigationControllerOperationNone,
* UINavigationControllerOperationPush,
* UINavigationControllerOperationPop,
* };
*/
if (operation == UINavigationControllerOperationPush) {
return self.customAnimator;
}else{
return nil;
}
}
// 交互
- (id )navigationController:(UINavigationController*)navigationController interactionControllerForAnimationController:(id )animationController
{
/**
* 在非交互式动画效果中,该方法返回 nil
* 交互式转场,自我理解意思是,用户能通过自己的动作来(常见:手势)控制,不同于系统缺省给定的push或者pop(非交互式)
*/
return _interactionController;
}
#pragma mark - Transitioning Delegate (Modal)
// 前2个用于动画
-(id)animationControllerForPresentedController:(UIViewController )presented presentingController:(UIViewController )presenting sourceController:(UIViewController *)source
{
self.minToMaxAnimator.animationType = AnimationTypePresent;
return _minToMaxAnimator;
}
-(id)animationControllerForDismissedController:(UIViewController *)dismissed
{
self.minToMaxAnimator.animationType = AnimationTypeDismiss;
return _minToMaxAnimator;
}
// 后2个用于交互
- (id )interactionControllerForPresentation:(id )animator
{
return _interactionController;
}
#pragma mark - 手势交互的主要实现--->UIPercentDrivenInteractiveTransition
@implementation PDTransitionAnimator
#define Switch_Time 1.2
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
return Switch_Time;
}
#define Button_Width 50.f
#define Button_Space 10.f
(void)animateTransition:(id )transitionContext {
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIView * toView = toViewController.view;
UIView * fromView = fromViewController.view;
if (self.animationType == AnimationTypeDismiss) {
// 这个方法能够高效的将当前显示的view截取成一个新的view.你可以用这个截取的view用来显示.例如,也许你只想用一张截图来做动画,毕竟用原始的view做动画代价太高.因为是截取了已经存在的内容,这个方法只能反应出这个被截取的view当前的状态信息,而不能反应这个被截取的view以后要显示的信息.然而,不管怎么样,调用这个方法都会比将view做成截图来加载效率更高.
UIView * snap = [toView snapshotViewAfterScreenUpdates:YES];
[transitionContext.containerView addSubview:snap];
[snap setFrame:CGRectMake([UIScreen mainScreen].bounds.size.width - Button_Width - Button_Space, [UIScreen mainScreen].bounds.size.height - Button_Width - Button_Space, Button_Width, Button_Width)];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
[snap setFrame:[UIScreen mainScreen].bounds];
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.5 animations:^{
[[transitionContext containerView] addSubview:toView];
snap.alpha = 0;
} completion:^(BOOL finished) {
[snap removeFromSuperview];
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}];
} else {
UIView * snap2 = [toView snapshotViewAfterScreenUpdates:YES];
[transitionContext.containerView addSubview:snap2];
UIView * snap = [fromView snapshotViewAfterScreenUpdates:YES];
[transitionContext.containerView addSubview:snap];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
[snap setFrame:CGRectMake([UIScreen mainScreen].bounds.size.width - Button_Width - Button_Space+ (Button_Width/2), [UIScreen mainScreen].bounds.size.height - Button_Width - Button_Space + (Button_Width/2), 0, 0)];
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.5 animations:^{
//snap.alpha = 0;
} completion:^(BOOL finished) {
[snap removeFromSuperview];
[snap2 removeFromSuperview];
[[transitionContext containerView] addSubview:toView];
// 切记不要忘记了噢
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}];
}
}
@其中,snapshotViewAfterScreenUpdates 方法的解释,我也不是很懂,反正初级来说会用就行,还可以参照下面的解析:
在iOS7 以前, 获取一个UIView的快照有以下步骤: 首先创建一个UIGraphics的图像上下文,然后将视图的layer渲染到该上下文中,从而取得一个图像,最后关闭图像上下文,并将图像显示在UIImageView中。现在我们只需要一行代码就可以完成上述步骤了:
[view snapshotViewAfterScreenUpdates:NO];
这个方法制作了一个UIView的副本,如果我们希望视图在执行动画之前保存现在的外观,以备之后使用(动画中视图可能会被子视图遮盖或者发生其他一些变化),该方法就特别方便。
afterUpdates参数表示是否在所有效果应用在视图上了以后再获取快照。例如,如果该参数为NO,则立马获取该视图现在状态的快照,反之,以下代码只能得到一个空白快照:
[view snapshotViewAfterScreenUpdates:YES];
[view setAlpha:0.0];
由于我们设置afterUpdates参数为YES,而视图的透明度值被设置成了0,所以方法将在该设置应用在视图上了之后才进行快照,于是乎屏幕空空如也。另外就是……你可以对快照再进行快照……继续快照……
原文:http://www.csdn123.com/html/topnews201408/58/1858.htm