0%

Controller 转换

UINavigationControllerDelegate中相关方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

- (id<UIViewControllerAnimatedTransitioning>)

navigationController:(UINavigationController *)navigationController

animationControllerForOperation:(UINavigationControllerOperation)operation

fromViewController:(UIViewController*)fromVC

toViewController:(UIViewController*)toVC

{

if (operation == UINavigationControllerOperationPush) {

//可以给每个转场创建新的animator对象,或者共用同一个animator

return self.animator;

}

return nil;

}

创建一个自定义的动画类

示例代码下载地址:https://github.com/objcio/issue5-view-controller-transitions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

//实现这个协议

@interface Animator : NSObject <UIViewControllerAnimatedTransitioning>

@end

//动画持续时间

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext

{

return 0.25;

}

//动画执行效果

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext

{

UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

[[transitionContext containerView] addSubview:toViewController.view];

toViewController.view.alpha = 0;

[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{

fromViewController.view.transform = CGAffineTransformMakeScale(0.1, 0.1);

toViewController.view.alpha = 1;

} completion:^(BOOL finished) {

fromViewController.view.transform = CGAffineTransformIdentity;

[transitionContext completeTransition:![transitionContext transitionWasCancelled]];

}];

}

//实现交互式转场动画,只需要覆盖另一个UINavigationControllerDelegate的方法

- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController*)navigationController

interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>)animationController

{

//返回的是UIPercentDrivenInteractionTransition类的一个实例

return self.interactionController;

}

//创建一个拖动手势Pan Rcognizer

if (panGestureRecognizer.state == UIGestureRecognizerStateBegan) {

//当用户从屏幕右半部分开始触摸时,把下次动画效果设置为交互式

if (location.x > CGRectGetMidX(view.bounds)) {

navigationControllerDelegate.interactionController = [[UIPercentDrivenInteractiveTransition alloc] init];

[self performSegueWithIdentifier:PushSegueIdentifier sender:self];

}

} else if (panGestureRecognizer.state == UIGestureRecognizerStateChanged) {

//根据用户手指拖动的距离计算一个百分比,切换的动画效果也跟这个百分比走。

CGFloat d = (translation.x / CGRectGetWidth(view.bounds)) * -1;

[interactionController updateInteractiveTransition:d];

} else if (panGestureRecognizer.state == UIGestureRecognizerStateEnded) {

//根据用户手势的停止状态来判断该操作是结束还是取消

if ([panGestureRecognizer velocityInView:view].x < 0) {

[interactionController finishInteractiveTransition];

} else {

[interactionController cancelInteractiveTransition];

}

navigationControllerDelegate.interactionController = nil;

}

用GPUImage做转场动画

示例代码地址:https://github.com/FangYiXiong/ViewControllerTransitionsDemo/tree/master/issue5-demo2%EF%BC%88GPUImage%EF%BC%89
实现的效果是两个view controller像素化,然后相互消融在一起。
先创建一个自定义类,实现UIViewControllerAnimatedTransitioning 和 UIViewControllerInteractiveTransitioning两个协议。将图片一次性加载到GPU中。直接用OpenGL画图使用GPUImage封装好的接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

@interface GPUImageAnimator : NSObject

<UIViewControllerAnimatedTransitioning,

UIViewControllerInteractiveTransitioning>

@property (nonatomic) BOOL interactive;

@property (nonatomic) CGFloat progress;

- (void)finishInteractiveTransition;

- (void)cancelInteractiveTransition;

@end

创建滤镜链filter chain也很直观。GPUImage没有提供动画效果,可以使用CADisplayLink完成渲染一帧就更新下一滤镜的动态滤镜效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(frame:)];

[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

//在frame方法中,可以根据时间来更新动画,相应的更新滤镜:

- (void)frame:(CADisplayLink*)link

{

self.progress = MAX(0, MIN((link.timestamp - self.startTime) / duration, 1));

self.blend.mix = self.progress;

self.sourcePixellateFilter.fractionalWidthOfAPixel = self.progress *0.1;

self.targetPixellateFilter.fractionalWidthOfAPixel = (1- self.progress)*0.1;

[self triggerRenderOfNextFrame];

}

GPUImage开源库地址:https://github.com/BradLarson/GPUImage