-
Notifications
You must be signed in to change notification settings - Fork 93
/
MLNavigationController.m
250 lines (185 loc) · 7.36 KB
/
MLNavigationController.m
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
//
// MLNavigationController.m
// MultiLayerNavigation
//
// Created by Feather Chan on 13-4-12.
// Copyright (c) 2013年 Feather Chan. All rights reserved.
//
#define KEY_WINDOW [[UIApplication sharedApplication]keyWindow]
#define TOP_VIEW [[UIApplication sharedApplication]keyWindow].rootViewController.view
#import "MLNavigationController.h"
#import <QuartzCore/QuartzCore.h>
@interface MLNavigationController ()
{
CGPoint startTouch;
UIImageView *lastScreenShotView;
UIView *blackMask;
}
@property (nonatomic,retain) UIView *backgroundView;
@property (nonatomic,retain) NSMutableArray *screenShotsList;
@property (nonatomic,assign) BOOL isMoving;
@end
@implementation MLNavigationController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
self.screenShotsList = [[[NSMutableArray alloc]initWithCapacity:2]autorelease];
self.canDragBack = YES;
}
return self;
}
- (void)dealloc
{
self.screenShotsList = nil;
[self.backgroundView removeFromSuperview];
self.backgroundView = nil;
[super dealloc];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// draw a shadow for navigation view to differ the layers obviously.
// using this way to draw shadow will lead to the low performace
// the best alternative way is making a shadow image.
//
//self.view.layer.shadowColor = [[UIColor blackColor]CGColor];
//self.view.layer.shadowOffset = CGSizeMake(5, 5);
//self.view.layer.shadowRadius = 5;
//self.view.layer.shadowOpacity = 1;
UIImageView *shadowImageView = [[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"leftside_shadow_bg"]]autorelease];
shadowImageView.frame = CGRectMake(-10, 0, 10, TOP_VIEW.frame.size.height);
[TOP_VIEW addSubview:shadowImageView];
UIPanGestureRecognizer *recognizer = [[[UIPanGestureRecognizer alloc]initWithTarget:self
action:@selector(paningGestureReceive:)]autorelease];
recognizer.delegate = self;
[recognizer delaysTouchesBegan];
[self.view addGestureRecognizer:recognizer];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:(BOOL)animated];
if (self.screenShotsList.count == 0) {
UIImage *capturedImage = [self capture];
if (capturedImage) {
[self.screenShotsList addObject:capturedImage];
}
}
}
// override the push method
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
UIImage *capturedImage = [self capture];
if (capturedImage) {
[self.screenShotsList addObject:capturedImage];
}
[super pushViewController:viewController animated:animated];
}
// override the pop method
- (UIViewController *)popViewControllerAnimated:(BOOL)animated
{
[self.screenShotsList removeLastObject];
return [super popViewControllerAnimated:animated];
}
#pragma mark - Utility Methods -
// get the current view screen shot
- (UIImage *)capture
{
UIGraphicsBeginImageContextWithOptions(TOP_VIEW.bounds.size, TOP_VIEW.opaque, 0.0);
[TOP_VIEW.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
// set lastScreenShotView 's position and alpha when paning
- (void)moveViewWithX:(float)x
{
NSLog(@"Move to:%f",x);
x = x>320?320:x;
x = x<0?0:x;
CGRect frame = TOP_VIEW.frame;
frame.origin.x = x;
TOP_VIEW.frame = frame;
float scale = (x/6400)+0.95;
float alpha = 0.4 - (x/800);
lastScreenShotView.transform = CGAffineTransformMakeScale(scale, scale);
blackMask.alpha = alpha;
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (self.viewControllers.count <= 1 || !self.canDragBack) return NO;
return YES;
}
#pragma mark - Gesture Recognizer -
- (void)paningGestureReceive:(UIPanGestureRecognizer *)recoginzer
{
// If the viewControllers has only one vc or disable the interaction, then return.
if (self.viewControllers.count <= 1 || !self.canDragBack) return;
// we get the touch position by the window's coordinate
CGPoint touchPoint = [recoginzer locationInView:KEY_WINDOW];
// begin paning, show the backgroundView(last screenshot),if not exist, create it.
if (recoginzer.state == UIGestureRecognizerStateBegan) {
_isMoving = YES;
startTouch = touchPoint;
if (!self.backgroundView)
{
CGRect frame = TOP_VIEW.frame;
self.backgroundView = [[[UIView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width , frame.size.height)]autorelease];
[TOP_VIEW.superview insertSubview:self.backgroundView belowSubview:TOP_VIEW];
blackMask = [[[UIView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width , frame.size.height)]autorelease];
blackMask.backgroundColor = [UIColor blackColor];
[self.backgroundView addSubview:blackMask];
}
self.backgroundView.hidden = NO;
if (lastScreenShotView) [lastScreenShotView removeFromSuperview];
UIImage *lastScreenShot = [self.screenShotsList lastObject];
lastScreenShotView = [[[UIImageView alloc]initWithImage:lastScreenShot]autorelease];
[self.backgroundView insertSubview:lastScreenShotView belowSubview:blackMask];
//End paning, always check that if it should move right or move left automatically
}else if (recoginzer.state == UIGestureRecognizerStateEnded){
if (touchPoint.x - startTouch.x > 50)
{
[UIView animateWithDuration:0.3 animations:^{
[self moveViewWithX:320];
} completion:^(BOOL finished) {
[self popViewControllerAnimated:NO];
CGRect frame = TOP_VIEW.frame;
frame.origin.x = 0;
TOP_VIEW.frame = frame;
_isMoving = NO;
self.backgroundView.hidden = YES;
}];
}
else
{
[UIView animateWithDuration:0.3 animations:^{
[self moveViewWithX:0];
} completion:^(BOOL finished) {
_isMoving = NO;
self.backgroundView.hidden = YES;
}];
}
return;
// cancal panning, alway move to left side automatically
}else if (recoginzer.state == UIGestureRecognizerStateCancelled){
[UIView animateWithDuration:0.3 animations:^{
[self moveViewWithX:0];
} completion:^(BOOL finished) {
_isMoving = NO;
self.backgroundView.hidden = YES;
}];
return;
}
// it keeps move with touch
if (_isMoving) {
[self moveViewWithX:touchPoint.x - startTouch.x];
}
}
@end