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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//
// XWMagicMoveAnimator.m
// XWTADemo
//
// Created by wazrx on 16/6/8.
// Copyright © 2016年 wazrx. All rights reserved.
//
#import "XWMagicMoveAnimator.h"
#import <objc/runtime.h>
static NSString *const kXWMagicMovePropertyInViewKey = @"kXWMagicMovePropertyInViewKey";
@implementation UIView (XWTransition)
- (void)setMagicMoveImageMode:(BOOL)magicMoveImageMode{
objc_setAssociatedObject(self, &kXWMagicMovePropertyInViewKey, @(magicMoveImageMode), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)magicMoveImageMode{
return [objc_getAssociatedObject(self, &kXWMagicMovePropertyInViewKey) boolValue];
}
@end
@implementation XWMagicMoveAnimator
- (void)xw_setToAnimation:(id<UIViewControllerContextTransitioning>)transitionContext{
[self _xw_doAniamtionWithContext:transitionContext fromFlag:YES];
}
- (void)xw_setBackAnimation:(id<UIViewControllerContextTransitioning>)transitionContext{
[self _xw_doAniamtionWithContext:transitionContext fromFlag:NO];
}
-(void)_xw_doAniamtionWithContext:(id<UIViewControllerContextTransitioning>)transitionContext fromFlag:(BOOL)flag{
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController *realFromVC = [self _xw_getRealContainsGroupViewController:fromVC];
UIViewController *realToVC = [self _xw_getRealContainsGroupViewController:toVC];
NSArray<UIView *> *startViewGroup = objc_getAssociatedObject(realFromVC, flag ? &kXWMagicMoveAnimatorStartViewVCKey : &kXWMagicMoveAnimatorEndViewVCKey);
NSArray<UIView *> *endViewGroup = objc_getAssociatedObject(realToVC, !flag ? &kXWMagicMoveAnimatorStartViewVCKey : &kXWMagicMoveAnimatorEndViewVCKey);
if (!startViewGroup.count || !endViewGroup.count || startViewGroup.count != endViewGroup.count) {
NSLog(@"神奇移动的视图为空,或者移动前后视图不相等");
[transitionContext completeTransition:NO];
return;
}
UIView *containerView = [transitionContext containerView];
toVC.view.alpha = 0.0f;
[containerView addSubview:toVC.view];
NSArray *toRects = [self _xw_getFrameValueFromViewGroup:endViewGroup inContainerView:containerView];
NSArray<UIView *> *tempViewGroup = [self _xw_makeTempViewGroupWithViewGroup:startViewGroup inContainerView:containerView];
[self _xw_changeHiddenViewInGroup:startViewGroup hidden:YES];
[self _xw_changeHiddenViewInGroup:endViewGroup hidden:YES];
if (self.dampingEnable) {
[UIView animateWithDuration:flag ? self.toDuration : self.backDuration delay:0.0f usingSpringWithDamping:0.55 initialSpringVelocity:1 / 0.55 options:UIViewAnimationOptionCurveLinear animations:^{
fromVC.view.alpha = 0.0f;
toVC.view.alpha = 1.0f;
[tempViewGroup enumerateObjectsUsingBlock:^(UIView *tempSubView, NSUInteger idx, BOOL * _Nonnull stop) {
CGRect toRect = [toRects[idx] CGRectValue];
tempSubView.frame = toRect;
}];
} completion:^(BOOL finished) {
[tempViewGroup makeObjectsPerformSelector:@selector(removeFromSuperview)];
fromVC.view.alpha = 1.0f;
[self _xw_changeHiddenViewInGroup:startViewGroup hidden:NO];
[self _xw_changeHiddenViewInGroup:endViewGroup hidden:NO];
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}else{
[UIView animateWithDuration:flag ? self.toDuration : self.backDuration animations:^{
fromVC.view.alpha = 0.0f;
toVC.view.alpha = 1.0f;
[tempViewGroup enumerateObjectsUsingBlock:^(UIView *tempSubView, NSUInteger idx, BOOL * _Nonnull stop) {
CGRect toRect = [toRects[idx] CGRectValue];
tempSubView.frame = toRect;
}];
} completion:^(BOOL finished) {
[tempViewGroup makeObjectsPerformSelector:@selector(removeFromSuperview)];
fromVC.view.alpha = 1.0f;
[self _xw_changeHiddenViewInGroup:startViewGroup hidden:NO];
[self _xw_changeHiddenViewInGroup:endViewGroup hidden:NO];
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
}
/**
* 判断当前控制器的类型,从而找到从出存有移动视图组的控制器
*/
- (UIViewController *)_xw_getRealContainsGroupViewController:(UIViewController *)controller{
UIViewController *realVC = controller;
if ([controller isKindOfClass:[UITabBarController class]]) {
UITabBarController *tabBarVC = (UITabBarController *)realVC;
if ([tabBarVC.selectedViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navVC = (UINavigationController *)tabBarVC.selectedViewController;
realVC = navVC.topViewController;
}else{
realVC = tabBarVC.selectedViewController;
}
}
if ([controller isKindOfClass:[UINavigationController class]]) {
UINavigationController *navVC = (UINavigationController *)controller;
realVC = navVC.topViewController;
}
return realVC;
}
- (NSArray *)_xw_getFrameValueFromViewGroup:(NSArray<UIView *> *)group inContainerView:(UIView *)containerView{
NSMutableArray *temp = @[].mutableCopy;
[group enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL * _Nonnull stop) {
CGRect rect = [view convertRect:view.bounds toView:containerView];
[temp addObject:[NSValue valueWithCGRect:rect]];
}];
return temp.copy;
}
- (NSArray<UIView *> *)_xw_makeTempViewGroupWithViewGroup:(NSArray<UIView *> *)group inContainerView:(UIView *)containerView{
NSMutableArray *temp = @[].mutableCopy;
[group enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL * _Nonnull stop) {
UIView *tempView = [self _xw_snapshotView:view];
tempView.frame = [view convertRect:view.bounds toView:containerView];
[containerView addSubview:tempView];
[temp addObject:tempView];
}];
return temp.copy;
}
- (void)_xw_changeHiddenViewInGroup:(NSArray<UIView *> *)group hidden:(BOOL)flag{
[group enumerateObjectsUsingBlock:^(UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
obj.hidden = flag;
}];
}
- (UIView *)_xw_snapshotView:(UIView *)view{
CALayer *layer = view.layer;
UIView *snapView = [UIView new];
snapView.frame = view.frame;
BOOL imgMode = [objc_getAssociatedObject(view, &kXWMagicMovePropertyInViewKey) boolValue] || _imageMode;
UIImage *img = nil;
if (imgMode) {//如果开启imgMode,优先直接获取图片,避免截图时时从小到大造成的模糊
if ([view isKindOfClass:[UIImageView class]]) {//取imageView中的image
img = [(UIImageView *)view image];
}else if ([view isKindOfClass:[UIButton class]]){//取button中的image
img = [(UIButton *)view currentImage];
}
if (!img && [view isKindOfClass:[UIView class]]) {//没取到尝试取content
img = [UIImage imageWithCGImage:(__bridge CGImageRef)view.layer.contents];
}
}
//若都没有取到,则截图
if (!img) {
UIGraphicsBeginImageContextWithOptions(layer.bounds.size, layer.opaque, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
[layer renderInContext:context];
img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
snapView.layer.contents = (__bridge id)img.CGImage;
return snapView;
}
@end
NSString *const kXWMagicMoveAnimatorStartViewVCKey = @"kXWMagicMoveAnimatorStartViewVCKey";
NSString *const kXWMagicMoveAnimatorEndViewVCKey = @"kXWMagicMoveAnimatorEndViewVCKey";