46 #pragma mark Orientation helpers |
45 #pragma mark Orientation helpers |
47 |
46 |
48 |
47 |
49 - (NSString *)nameOfInterfaceOrientation:(UIInterfaceOrientation)theOrientation |
48 - (NSString *)nameOfInterfaceOrientation:(UIInterfaceOrientation)theOrientation |
50 { |
49 { |
51 NSString *orientationName = nil; |
50 NSString *orientationName = nil; |
52 switch (theOrientation) { |
51 switch (theOrientation) { |
53 case UIInterfaceOrientationPortrait: |
52 case UIInterfaceOrientationPortrait: |
54 orientationName = @"Portrait"; // Home button at bottom |
53 orientationName = @"Portrait"; // Home button at bottom |
55 break; |
54 break; |
56 case UIInterfaceOrientationPortraitUpsideDown: |
55 case UIInterfaceOrientationPortraitUpsideDown: |
57 orientationName = @"Portrait (Upside Down)"; // Home button at top |
56 orientationName = @"Portrait (Upside Down)"; // Home button at top |
58 break; |
57 break; |
59 case UIInterfaceOrientationLandscapeLeft: |
58 case UIInterfaceOrientationLandscapeLeft: |
60 orientationName = @"Landscape (Left)"; // Home button on left |
59 orientationName = @"Landscape (Left)"; // Home button on left |
61 break; |
60 break; |
62 case UIInterfaceOrientationLandscapeRight: |
61 case UIInterfaceOrientationLandscapeRight: |
63 orientationName = @"Landscape (Right)"; // Home button on right |
62 orientationName = @"Landscape (Right)"; // Home button on right |
64 break; |
63 break; |
65 default: |
64 default: |
66 break; |
65 break; |
67 } |
66 } |
68 |
67 |
69 return orientationName; |
68 return orientationName; |
70 } |
69 } |
71 |
70 |
72 |
71 |
73 - (BOOL)isLandscape |
72 - (BOOL)isLandscape |
74 { |
73 { |
75 return UIInterfaceOrientationIsLandscape(self.interfaceOrientation); |
74 return UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]); |
76 } |
75 } |
77 |
76 |
78 |
77 |
79 - (BOOL)shouldShowMasterForInterfaceOrientation:(UIInterfaceOrientation)theOrientation |
78 - (BOOL)shouldShowMasterForInterfaceOrientation:(UIInterfaceOrientation)theOrientation |
80 { |
79 { |
81 // Returns YES if master view should be shown directly embedded in the splitview, instead of hidden in a popover. |
80 // Returns YES if master view should be shown directly embedded in the splitview, instead of hidden in a popover. |
82 return ((UIInterfaceOrientationIsLandscape(theOrientation)) ? _showsMasterInLandscape : _showsMasterInPortrait); |
81 return ((UIInterfaceOrientationIsLandscape(theOrientation)) ? _showsMasterInLandscape : _showsMasterInPortrait); |
83 } |
82 } |
84 |
83 |
85 |
84 |
86 - (BOOL)shouldShowMaster |
85 - (BOOL)shouldShowMaster |
87 { |
86 { |
88 return [self shouldShowMasterForInterfaceOrientation:self.interfaceOrientation]; |
87 return [self shouldShowMasterForInterfaceOrientation:[[UIApplication sharedApplication] statusBarOrientation]]; |
89 } |
88 } |
90 |
89 |
91 |
90 |
92 - (BOOL)isShowingMaster |
91 - (BOOL)isShowingMaster |
93 { |
92 { |
94 return [self shouldShowMaster] && self.masterViewController && self.masterViewController.view && ([self.masterViewController.view superview] == self.view); |
93 return [self shouldShowMaster] && self.masterViewController && self.masterViewController.view && ([self.masterViewController.view superview] == self.view); |
95 } |
94 } |
96 |
95 |
97 |
96 |
98 #pragma mark - |
97 #pragma mark - |
99 #pragma mark Setup and Teardown |
98 #pragma mark Setup and Teardown |
100 |
99 |
101 |
100 |
102 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil |
101 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil |
103 { |
102 { |
104 if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) { |
103 if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) { |
105 [self setup]; |
104 [self setup]; |
106 } |
105 } |
107 |
106 |
108 return self; |
107 return self; |
109 } |
108 } |
110 |
109 |
111 |
110 |
112 - (id)initWithCoder:(NSCoder *)aDecoder |
111 - (id)initWithCoder:(NSCoder *)aDecoder |
113 { |
112 { |
114 if ((self = [super initWithCoder:aDecoder])) { |
113 if ((self = [super initWithCoder:aDecoder])) { |
115 [self setup]; |
114 [self setup]; |
116 } |
115 } |
117 |
116 |
118 return self; |
117 return self; |
119 } |
118 } |
120 |
119 |
121 |
120 |
122 - (void)setup |
121 - (void)setup |
123 { |
122 { |
124 // Configure default behaviour. |
123 // Configure default behaviour. |
125 _viewControllers = [[NSMutableArray alloc] initWithObjects:[NSNull null], [NSNull null], nil]; |
124 _viewControllers = [[NSMutableArray alloc] initWithObjects:[NSNull null], [NSNull null], nil]; |
126 _splitWidth = MG_DEFAULT_SPLIT_WIDTH; |
125 _splitWidth = MG_DEFAULT_SPLIT_WIDTH; |
127 _showsMasterInPortrait = NO; |
126 _showsMasterInPortrait = NO; |
128 _showsMasterInLandscape = YES; |
127 _showsMasterInLandscape = YES; |
129 _reconfigurePopup = NO; |
128 _reconfigurePopup = NO; |
130 _vertical = YES; |
129 _vertical = YES; |
131 _masterBeforeDetail = YES; |
130 _masterBeforeDetail = YES; |
132 _splitPosition = MG_DEFAULT_SPLIT_POSITION; |
131 _splitPosition = MG_DEFAULT_SPLIT_POSITION; |
133 CGRect divRect = self.view.bounds; |
132 CGRect divRect = self.view.bounds; |
134 if ([self isVertical]) { |
133 if ([self isVertical]) { |
135 divRect.origin.y = _splitPosition; |
134 divRect.origin.y = _splitPosition; |
136 divRect.size.height = _splitWidth; |
135 divRect.size.height = _splitWidth; |
137 } else { |
136 } else { |
138 divRect.origin.x = _splitPosition; |
137 divRect.origin.x = _splitPosition; |
139 divRect.size.width = _splitWidth; |
138 divRect.size.width = _splitWidth; |
140 } |
139 } |
141 _dividerView = [[MGSplitDividerView alloc] initWithFrame:divRect]; |
140 _dividerView = [[MGSplitDividerView alloc] initWithFrame:divRect]; |
142 _dividerView.splitViewController = self; |
141 _dividerView.splitViewController = self; |
143 _dividerView.backgroundColor = MG_DEFAULT_CORNER_COLOR; |
142 _dividerView.backgroundColor = MG_DEFAULT_CORNER_COLOR; |
144 _dividerStyle = MGSplitViewDividerStyleThin; |
143 _dividerStyle = MGSplitViewDividerStyleThin; |
|
144 |
|
145 // fix for iOS 6 layout |
|
146 self.view.autoresizesSubviews = NO; |
145 } |
147 } |
146 |
148 |
147 |
149 |
148 - (void)dealloc |
150 - (void)dealloc |
149 { |
151 { |
150 _delegate = nil; |
152 _delegate = nil; |
151 [self.view.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; |
153 _viewControllers = nil; |
152 [_viewControllers release]; |
154 [self.view.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; |
153 [_barButtonItem release]; |
155 |
154 [_hiddenPopoverController release]; |
|
155 [_dividerView release]; |
|
156 [_cornerViews release]; |
|
157 |
|
158 [super dealloc]; |
156 [super dealloc]; |
159 } |
157 } |
160 |
158 |
161 |
159 |
162 #pragma mark - |
160 #pragma mark - |
163 #pragma mark View management |
161 #pragma mark View management |
164 |
162 |
165 |
163 |
166 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation |
164 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation |
167 { |
165 { |
|
166 if (self.detailViewController) |
|
167 { |
|
168 return [self.detailViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation]; |
|
169 } |
|
170 |
168 return YES; |
171 return YES; |
169 } |
172 } |
170 |
173 |
171 |
174 |
172 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration |
175 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration |
173 { |
176 { |
174 [self.masterViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
177 [self.masterViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
175 [self.detailViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
178 [self.detailViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
176 } |
179 } |
177 |
180 |
178 |
181 |
179 - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation |
182 - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation |
180 { |
183 { |
181 [self.masterViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation]; |
184 [self.masterViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation]; |
182 [self.detailViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation]; |
185 [self.detailViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation]; |
183 } |
186 } |
184 |
187 |
185 |
188 |
186 - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation |
189 - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation |
187 duration:(NSTimeInterval)duration |
190 duration:(NSTimeInterval)duration |
188 { |
191 { |
189 [self.masterViewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
192 [self.masterViewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
190 [self.detailViewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
193 [self.detailViewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
191 |
194 |
192 // Hide popover. |
195 // Hide popover. |
193 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
196 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
194 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
197 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
|
198 } |
|
199 |
|
200 // Re-tile views. |
|
201 _reconfigurePopup = YES; |
|
202 [self layoutSubviewsForInterfaceOrientation:toInterfaceOrientation withAnimation:YES]; |
|
203 } |
|
204 |
|
205 |
|
206 - (CGSize)splitViewSizeForOrientation:(UIInterfaceOrientation)theOrientation |
|
207 { |
|
208 UIScreen *screen = [UIScreen mainScreen]; |
|
209 CGRect fullScreenRect = screen.bounds; // always implicitly in Portrait orientation. |
|
210 CGRect appFrame = screen.applicationFrame; |
|
211 |
|
212 // Find status bar height by checking which dimension of the applicationFrame is narrower than screen bounds. |
|
213 // Little bit ugly looking, but it'll still work even if they change the status bar height in future. |
|
214 float statusBarHeight = MAX((fullScreenRect.size.width - appFrame.size.width), (fullScreenRect.size.height - appFrame.size.height)); |
|
215 |
|
216 // In iOS 7 the status bar is transparent, so don't adjust for it. |
|
217 if (NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_7_0) { |
|
218 statusBarHeight = 0; |
195 } |
219 } |
196 |
220 |
197 // Re-tile views. |
221 float navigationBarHeight = 0; |
198 _reconfigurePopup = YES; |
222 if ((self.navigationController)&&(!self.navigationController.navigationBarHidden)) { |
199 [self layoutSubviewsForInterfaceOrientation:toInterfaceOrientation withAnimation:YES]; |
223 navigationBarHeight = self.navigationController.navigationBar.frame.size.height; |
200 } |
224 } |
201 |
225 |
202 |
226 // Initially assume portrait orientation. |
203 - (void)willAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration |
227 float width = fullScreenRect.size.width; |
204 { |
228 float height = fullScreenRect.size.height; |
205 [self.masterViewController willAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
229 |
206 [self.detailViewController willAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
230 // Correct for orientation (only for iOS7.1 and earlier, since iOS8 it will do it automatically). |
207 } |
231 if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1 && UIInterfaceOrientationIsLandscape(theOrientation)) { |
208 |
232 width = height; |
209 |
233 height = fullScreenRect.size.width; |
210 - (void)didAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation |
234 } |
211 { |
235 |
212 [self.masterViewController didAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation]; |
236 // Account for status bar, which always subtracts from the height (since it's always at the top of the screen). |
213 [self.detailViewController didAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation]; |
237 height -= statusBarHeight; |
214 } |
238 height -= navigationBarHeight; |
215 |
239 |
216 |
240 return CGSizeMake(width, height); |
217 - (void)willAnimateSecondHalfOfRotationFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation duration:(NSTimeInterval)duration |
|
218 { |
|
219 [self.masterViewController willAnimateSecondHalfOfRotationFromInterfaceOrientation:fromInterfaceOrientation duration:duration]; |
|
220 [self.detailViewController willAnimateSecondHalfOfRotationFromInterfaceOrientation:fromInterfaceOrientation duration:duration]; |
|
221 } |
|
222 |
|
223 |
|
224 - (CGSize)splitViewSizeForOrientation:(UIInterfaceOrientation)theOrientation |
|
225 { |
|
226 UIScreen *screen = [UIScreen mainScreen]; |
|
227 CGRect fullScreenRect = screen.bounds; // always implicitly in Portrait orientation. |
|
228 CGRect appFrame = screen.applicationFrame; |
|
229 |
|
230 // Find status bar height by checking which dimension of the applicationFrame is narrower than screen bounds. |
|
231 // Little bit ugly looking, but it'll still work even if they change the status bar height in future. |
|
232 float statusBarHeight = MAX((fullScreenRect.size.width - appFrame.size.width), (fullScreenRect.size.height - appFrame.size.height)); |
|
233 |
|
234 // Initially assume portrait orientation. |
|
235 float width = fullScreenRect.size.width; |
|
236 float height = fullScreenRect.size.height; |
|
237 |
|
238 // Correct for orientation. |
|
239 if (UIInterfaceOrientationIsLandscape(theOrientation)) { |
|
240 width = height; |
|
241 height = fullScreenRect.size.width; |
|
242 } |
|
243 |
|
244 // Account for status bar, which always subtracts from the height (since it's always at the top of the screen). |
|
245 height -= statusBarHeight; |
|
246 |
|
247 return CGSizeMake(width, height); |
|
248 } |
241 } |
249 |
242 |
250 |
243 |
251 - (void)layoutSubviewsForInterfaceOrientation:(UIInterfaceOrientation)theOrientation withAnimation:(BOOL)animate |
244 - (void)layoutSubviewsForInterfaceOrientation:(UIInterfaceOrientation)theOrientation withAnimation:(BOOL)animate |
252 { |
245 { |
253 if (_reconfigurePopup) { |
246 if (_reconfigurePopup) { |
254 [self reconfigureForMasterInPopover:![self shouldShowMasterForInterfaceOrientation:theOrientation]]; |
247 [self reconfigureForMasterInPopover:![self shouldShowMasterForInterfaceOrientation:theOrientation]]; |
255 } |
248 } |
256 |
249 |
257 // Layout the master, detail and divider views appropriately, adding/removing subviews as needed. |
250 // Layout the master, detail and divider views appropriately, adding/removing subviews as needed. |
258 // First obtain relevant geometry. |
251 // First obtain relevant geometry. |
259 CGSize fullSize = [self splitViewSizeForOrientation:theOrientation]; |
252 CGSize fullSize = [self splitViewSizeForOrientation:theOrientation]; |
260 float width = fullSize.width; |
253 float width = fullSize.width; |
261 float height = fullSize.height; |
254 float height = fullSize.height; |
262 |
255 |
263 if (NO) { // Just for debugging. |
256 if (NO) { // Just for debugging. |
264 NSLog(@"Target orientation is %@, dimensions will be %.0f x %.0f", |
257 NSLog(@"Target orientation is %@, dimensions will be %.0f x %.0f", |
265 [self nameOfInterfaceOrientation:theOrientation], width, height); |
258 [self nameOfInterfaceOrientation:theOrientation], width, height); |
266 } |
259 } |
267 |
260 |
268 // Layout the master, divider and detail views. |
261 // Layout the master, divider and detail views. |
269 CGRect newFrame = CGRectMake(0, 0, width, height); |
262 CGRect newFrame = CGRectMake(0, 0, width, height); |
270 UIViewController *controller; |
263 UIViewController *controller; |
271 UIView *theView; |
264 UIView *theView; |
272 BOOL shouldShowMaster = [self shouldShowMasterForInterfaceOrientation:theOrientation]; |
265 BOOL shouldShowMaster = [self shouldShowMasterForInterfaceOrientation:theOrientation]; |
273 BOOL masterFirst = [self isMasterBeforeDetail]; |
266 BOOL masterFirst = [self isMasterBeforeDetail]; |
274 if ([self isVertical]) { |
267 if ([self isVertical]) { |
275 // Master on left, detail on right (or vice versa). |
268 // Master on left, detail on right (or vice versa). |
276 CGRect masterRect, dividerRect, detailRect; |
269 CGRect masterRect, dividerRect, detailRect; |
277 if (masterFirst) { |
270 if (masterFirst) { |
278 if (!shouldShowMaster) { |
271 if (!shouldShowMaster) { |
279 // Move off-screen. |
272 // Move off-screen. |
280 newFrame.origin.x -= (_splitPosition + _splitWidth); |
273 newFrame.origin.x -= (_splitPosition + _splitWidth); |
281 } |
274 } |
282 |
275 |
283 newFrame.size.width = _splitPosition; |
276 newFrame.size.width = _splitPosition; |
284 masterRect = newFrame; |
277 masterRect = newFrame; |
285 |
278 |
286 newFrame.origin.x += newFrame.size.width; |
279 newFrame.origin.x += newFrame.size.width; |
287 newFrame.size.width = _splitWidth; |
280 newFrame.size.width = _splitWidth; |
288 dividerRect = newFrame; |
281 dividerRect = newFrame; |
289 |
282 |
290 newFrame.origin.x += newFrame.size.width; |
283 newFrame.origin.x += newFrame.size.width; |
291 newFrame.size.width = width - newFrame.origin.x; |
284 newFrame.size.width = width - newFrame.origin.x; |
292 detailRect = newFrame; |
285 detailRect = newFrame; |
293 |
286 |
294 } else { |
287 } else { |
295 if (!shouldShowMaster) { |
288 if (!shouldShowMaster) { |
296 // Move off-screen. |
289 // Move off-screen. |
297 newFrame.size.width += (_splitPosition + _splitWidth); |
290 newFrame.size.width += (_splitPosition + _splitWidth); |
298 } |
291 } |
299 |
292 |
300 newFrame.size.width -= (_splitPosition + _splitWidth); |
293 newFrame.size.width -= (_splitPosition + _splitWidth); |
301 detailRect = newFrame; |
294 detailRect = newFrame; |
302 |
295 |
303 newFrame.origin.x += newFrame.size.width; |
296 newFrame.origin.x += newFrame.size.width; |
304 newFrame.size.width = _splitWidth; |
297 newFrame.size.width = _splitWidth; |
305 dividerRect = newFrame; |
298 dividerRect = newFrame; |
306 |
299 |
307 newFrame.origin.x += newFrame.size.width; |
300 newFrame.origin.x += newFrame.size.width; |
308 newFrame.size.width = _splitPosition; |
301 newFrame.size.width = _splitPosition; |
309 masterRect = newFrame; |
302 masterRect = newFrame; |
310 } |
303 } |
311 |
304 |
312 // Position master. |
305 // Position master. |
313 controller = self.masterViewController; |
306 controller = self.masterViewController; |
314 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
307 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
315 theView = controller.view; |
308 theView = controller.view; |
316 if (theView) { |
309 if (theView) { |
317 theView.frame = masterRect; |
310 theView.frame = masterRect; |
318 if (!theView.superview) { |
311 if (!theView.superview) { |
319 [controller viewWillAppear:NO]; |
312 [controller viewWillAppear:NO]; |
320 [self.view addSubview:theView]; |
313 [self.view addSubview:theView]; |
321 [controller viewDidAppear:NO]; |
314 [controller viewDidAppear:NO]; |
322 } |
315 } |
323 } |
316 } |
324 } |
317 } |
325 |
318 |
326 // Position divider. |
319 // Position divider. |
327 theView = _dividerView; |
320 theView = _dividerView; |
328 theView.frame = dividerRect; |
321 theView.frame = dividerRect; |
329 if (!theView.superview) { |
322 if (!theView.superview) { |
330 [self.view addSubview:theView]; |
323 [self.view addSubview:theView]; |
331 } |
324 } |
332 |
325 |
333 // Position detail. |
326 // Position detail. |
334 controller = self.detailViewController; |
327 controller = self.detailViewController; |
335 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
328 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
336 theView = controller.view; |
329 theView = controller.view; |
337 if (theView) { |
330 if (theView) { |
338 theView.frame = detailRect; |
331 theView.frame = detailRect; |
339 if (!theView.superview) { |
332 if (!theView.superview) { |
340 [self.view insertSubview:theView aboveSubview:self.masterViewController.view]; |
333 [self.view insertSubview:theView aboveSubview:self.masterViewController.view]; |
341 } else { |
334 } else { |
342 [self.view bringSubviewToFront:theView]; |
335 [self.view bringSubviewToFront:theView]; |
343 } |
336 } |
344 } |
337 } |
345 } |
338 } |
346 |
339 |
347 } else { |
340 } else { |
348 // Master above, detail below (or vice versa). |
341 // Master above, detail below (or vice versa). |
349 CGRect masterRect, dividerRect, detailRect; |
342 CGRect masterRect, dividerRect, detailRect; |
350 if (masterFirst) { |
343 if (masterFirst) { |
351 if (!shouldShowMaster) { |
344 if (!shouldShowMaster) { |
352 // Move off-screen. |
345 // Move off-screen. |
353 newFrame.origin.y -= (_splitPosition + _splitWidth); |
346 newFrame.origin.y -= (_splitPosition + _splitWidth); |
354 } |
347 } |
355 |
348 |
356 newFrame.size.height = _splitPosition; |
349 newFrame.size.height = _splitPosition; |
357 masterRect = newFrame; |
350 masterRect = newFrame; |
358 |
351 |
359 newFrame.origin.y += newFrame.size.height; |
352 newFrame.origin.y += newFrame.size.height; |
360 newFrame.size.height = _splitWidth; |
353 newFrame.size.height = _splitWidth; |
361 dividerRect = newFrame; |
354 dividerRect = newFrame; |
362 |
355 |
363 newFrame.origin.y += newFrame.size.height; |
356 newFrame.origin.y += newFrame.size.height; |
364 newFrame.size.height = height - newFrame.origin.y; |
357 newFrame.size.height = height - newFrame.origin.y; |
365 detailRect = newFrame; |
358 detailRect = newFrame; |
366 |
359 |
367 } else { |
360 } else { |
368 if (!shouldShowMaster) { |
361 if (!shouldShowMaster) { |
369 // Move off-screen. |
362 // Move off-screen. |
370 newFrame.size.height += (_splitPosition + _splitWidth); |
363 newFrame.size.height += (_splitPosition + _splitWidth); |
371 } |
364 } |
372 |
365 |
373 newFrame.size.height -= (_splitPosition + _splitWidth); |
366 newFrame.size.height -= (_splitPosition + _splitWidth); |
374 detailRect = newFrame; |
367 detailRect = newFrame; |
375 |
368 |
376 newFrame.origin.y += newFrame.size.height; |
369 newFrame.origin.y += newFrame.size.height; |
377 newFrame.size.height = _splitWidth; |
370 newFrame.size.height = _splitWidth; |
378 dividerRect = newFrame; |
371 dividerRect = newFrame; |
379 |
372 |
380 newFrame.origin.y += newFrame.size.height; |
373 newFrame.origin.y += newFrame.size.height; |
381 newFrame.size.height = _splitPosition; |
374 newFrame.size.height = _splitPosition; |
382 masterRect = newFrame; |
375 masterRect = newFrame; |
383 } |
376 } |
384 |
377 |
385 // Position master. |
378 // Position master. |
386 controller = self.masterViewController; |
379 controller = self.masterViewController; |
387 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
380 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
388 theView = controller.view; |
381 theView = controller.view; |
389 if (theView) { |
382 if (theView) { |
390 theView.frame = masterRect; |
383 theView.frame = masterRect; |
391 if (!theView.superview) { |
384 if (!theView.superview) { |
392 [controller viewWillAppear:NO]; |
385 [controller viewWillAppear:NO]; |
393 [self.view addSubview:theView]; |
386 [self.view addSubview:theView]; |
394 [controller viewDidAppear:NO]; |
387 [controller viewDidAppear:NO]; |
395 } |
388 } |
396 } |
389 } |
397 } |
390 } |
398 |
391 |
399 // Position divider. |
392 // Position divider. |
400 theView = _dividerView; |
393 theView = _dividerView; |
401 theView.frame = dividerRect; |
394 theView.frame = dividerRect; |
402 if (!theView.superview) { |
395 if (!theView.superview) { |
403 [self.view addSubview:theView]; |
396 [self.view addSubview:theView]; |
404 } |
397 } |
405 |
398 |
406 // Position detail. |
399 // Position detail. |
407 controller = self.detailViewController; |
400 controller = self.detailViewController; |
408 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
401 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
409 theView = controller.view; |
402 theView = controller.view; |
410 if (theView) { |
403 if (theView) { |
411 theView.frame = detailRect; |
404 theView.frame = detailRect; |
412 if (!theView.superview) { |
405 if (!theView.superview) { |
413 [self.view insertSubview:theView aboveSubview:self.masterViewController.view]; |
406 [self.view insertSubview:theView aboveSubview:self.masterViewController.view]; |
414 } else { |
407 } else { |
415 [self.view bringSubviewToFront:theView]; |
408 [self.view bringSubviewToFront:theView]; |
416 } |
409 } |
417 } |
410 } |
418 } |
411 } |
419 } |
412 } |
420 |
413 |
421 // Create corner views if necessary. |
414 // Create corner views if necessary. |
422 MGSplitCornersView *leadingCorners; // top/left of screen in vertical/horizontal split. |
415 MGSplitCornersView *leadingCorners = nil; // top/left of screen in vertical/horizontal split. |
423 MGSplitCornersView *trailingCorners; // bottom/right of screen in vertical/horizontal split. |
416 MGSplitCornersView *trailingCorners = nil; // bottom/right of screen in vertical/horizontal split. |
424 if (!_cornerViews) { |
417 if (!_cornerViews) { |
425 CGRect cornerRect = CGRectMake(0, 0, 10, 10); // arbitrary, will be resized below. |
418 CGRect cornerRect = CGRectMake(0, 0, 10, 10); // arbitrary, will be resized below. |
426 leadingCorners = [[MGSplitCornersView alloc] initWithFrame:cornerRect]; |
419 leadingCorners = [[MGSplitCornersView alloc] initWithFrame:cornerRect]; |
427 leadingCorners.splitViewController = self; |
420 leadingCorners.splitViewController = self; |
428 leadingCorners.cornerBackgroundColor = MG_DEFAULT_CORNER_COLOR; |
421 leadingCorners.cornerBackgroundColor = MG_DEFAULT_CORNER_COLOR; |
429 leadingCorners.cornerRadius = MG_DEFAULT_CORNER_RADIUS; |
422 leadingCorners.cornerRadius = NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_7_0 ? 0 : MG_DEFAULT_CORNER_RADIUS; |
430 trailingCorners = [[MGSplitCornersView alloc] initWithFrame:cornerRect]; |
423 trailingCorners = [[MGSplitCornersView alloc] initWithFrame:cornerRect]; |
431 trailingCorners.splitViewController = self; |
424 trailingCorners.splitViewController = self; |
432 trailingCorners.cornerBackgroundColor = MG_DEFAULT_CORNER_COLOR; |
425 trailingCorners.cornerBackgroundColor = MG_DEFAULT_CORNER_COLOR; |
433 trailingCorners.cornerRadius = MG_DEFAULT_CORNER_RADIUS; |
426 trailingCorners.cornerRadius = NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_7_0 ? 0 : MG_DEFAULT_CORNER_RADIUS; |
434 _cornerViews = [[NSArray alloc] initWithObjects:leadingCorners, trailingCorners, nil]; |
427 _cornerViews = [[NSArray alloc] initWithObjects:leadingCorners, trailingCorners, nil]; |
435 [leadingCorners release]; |
428 |
436 [trailingCorners release]; |
429 } else if ([_cornerViews count] == 2) { |
437 |
430 leadingCorners = [_cornerViews objectAtIndex:0]; |
438 } else if ([_cornerViews count] == 2) { |
431 trailingCorners = [_cornerViews objectAtIndex:1]; |
439 leadingCorners = [_cornerViews objectAtIndex:0]; |
432 } |
440 trailingCorners = [_cornerViews objectAtIndex:1]; |
433 |
441 } |
434 // Configure and layout the corner-views. |
442 |
435 leadingCorners.cornersPosition = (_vertical) ? MGCornersPositionLeadingVertical : MGCornersPositionLeadingHorizontal; |
443 // Configure and layout the corner-views. |
436 trailingCorners.cornersPosition = (_vertical) ? MGCornersPositionTrailingVertical : MGCornersPositionTrailingHorizontal; |
444 leadingCorners.cornersPosition = (_vertical) ? MGCornersPositionLeadingVertical : MGCornersPositionLeadingHorizontal; |
437 leadingCorners.autoresizingMask = (_vertical) ? UIViewAutoresizingFlexibleBottomMargin : UIViewAutoresizingFlexibleRightMargin; |
445 trailingCorners.cornersPosition = (_vertical) ? MGCornersPositionTrailingVertical : MGCornersPositionTrailingHorizontal; |
438 trailingCorners.autoresizingMask = (_vertical) ? UIViewAutoresizingFlexibleTopMargin : UIViewAutoresizingFlexibleLeftMargin; |
446 leadingCorners.autoresizingMask = (_vertical) ? UIViewAutoresizingFlexibleBottomMargin : UIViewAutoresizingFlexibleRightMargin; |
439 |
447 trailingCorners.autoresizingMask = (_vertical) ? UIViewAutoresizingFlexibleTopMargin : UIViewAutoresizingFlexibleLeftMargin; |
440 float x, y, cornersWidth, cornersHeight; |
448 |
441 CGRect leadingRect, trailingRect; |
449 float x, y, cornersWidth, cornersHeight; |
442 float radius = leadingCorners.cornerRadius; |
450 CGRect leadingRect, trailingRect; |
443 if (_vertical) { // left/right split |
451 float radius = leadingCorners.cornerRadius; |
444 cornersWidth = (radius * 2.f) + _splitWidth; |
452 if (_vertical) { // left/right split |
445 cornersHeight = radius; |
453 cornersWidth = (radius * 2.0) + _splitWidth; |
446 x = ((shouldShowMaster) ? ((masterFirst) ? _splitPosition : width - (_splitPosition + _splitWidth)) : (0 - _splitWidth)) - radius; |
454 cornersHeight = radius; |
447 y = 0; |
455 x = ((shouldShowMaster) ? ((masterFirst) ? _splitPosition : width - (_splitPosition + _splitWidth)) : (0 - _splitWidth)) - radius; |
448 leadingRect = CGRectMake(x, y, cornersWidth, cornersHeight); // top corners |
456 y = 0; |
449 trailingRect = CGRectMake(x, (height - cornersHeight), cornersWidth, cornersHeight); // bottom corners |
457 leadingRect = CGRectMake(x, y, cornersWidth, cornersHeight); // top corners |
450 |
458 trailingRect = CGRectMake(x, (height - cornersHeight), cornersWidth, cornersHeight); // bottom corners |
451 } else { // top/bottom split |
459 |
452 x = 0; |
460 } else { // top/bottom split |
453 y = ((shouldShowMaster) ? ((masterFirst) ? _splitPosition : height - (_splitPosition + _splitWidth)) : (0 - _splitWidth)) - radius; |
461 x = 0; |
454 cornersWidth = radius; |
462 y = ((shouldShowMaster) ? ((masterFirst) ? _splitPosition : height - (_splitPosition + _splitWidth)) : (0 - _splitWidth)) - radius; |
455 cornersHeight = (radius * 2.f) + _splitWidth; |
463 cornersWidth = radius; |
456 leadingRect = CGRectMake(x, y, cornersWidth, cornersHeight); // left corners |
464 cornersHeight = (radius * 2.0) + _splitWidth; |
457 trailingRect = CGRectMake((width - cornersWidth), y, cornersWidth, cornersHeight); // right corners |
465 leadingRect = CGRectMake(x, y, cornersWidth, cornersHeight); // left corners |
458 } |
466 trailingRect = CGRectMake((width - cornersWidth), y, cornersWidth, cornersHeight); // right corners |
459 |
467 } |
460 leadingCorners.frame = leadingRect; |
468 |
461 trailingCorners.frame = trailingRect; |
469 leadingCorners.frame = leadingRect; |
462 |
470 trailingCorners.frame = trailingRect; |
463 // Ensure corners are visible and frontmost. |
471 |
464 if (!leadingCorners.superview) { |
472 // Ensure corners are visible and frontmost. |
465 [self.view insertSubview:leadingCorners aboveSubview:self.detailViewController.view]; |
473 if (!leadingCorners.superview) { |
466 [self.view insertSubview:trailingCorners aboveSubview:self.detailViewController.view]; |
474 [self.view insertSubview:leadingCorners aboveSubview:self.detailViewController.view]; |
467 } else { |
475 [self.view insertSubview:trailingCorners aboveSubview:self.detailViewController.view]; |
468 [self.view bringSubviewToFront:leadingCorners]; |
476 } else { |
469 [self.view bringSubviewToFront:trailingCorners]; |
477 [self.view bringSubviewToFront:leadingCorners]; |
470 } |
478 [self.view bringSubviewToFront:trailingCorners]; |
|
479 } |
|
480 } |
471 } |
481 |
472 |
482 |
473 |
483 - (void)layoutSubviewsWithAnimation:(BOOL)animate |
474 - (void)layoutSubviewsWithAnimation:(BOOL)animate |
484 { |
475 { |
485 [self layoutSubviewsForInterfaceOrientation:self.interfaceOrientation withAnimation:animate]; |
476 [self layoutSubviewsForInterfaceOrientation:self.interfaceOrientation withAnimation:animate]; |
486 } |
477 } |
487 |
478 |
488 |
479 |
489 - (void)layoutSubviews |
480 - (void)layoutSubviews |
490 { |
481 { |
491 [self layoutSubviewsForInterfaceOrientation:self.interfaceOrientation withAnimation:YES]; |
482 [self layoutSubviewsForInterfaceOrientation:self.interfaceOrientation withAnimation:YES]; |
492 } |
483 } |
493 |
484 |
494 |
485 |
495 - (void)viewWillAppear:(BOOL)animated |
486 - (void)viewWillAppear:(BOOL)animated |
496 { |
487 { |
497 [super viewWillAppear:animated]; |
488 [super viewWillAppear:animated]; |
498 |
489 |
499 if ([self isShowingMaster]) { |
490 if ([self isShowingMaster]) { |
500 [self.masterViewController viewWillAppear:animated]; |
491 [self.masterViewController viewWillAppear:animated]; |
501 } |
492 } |
502 [self.detailViewController viewWillAppear:animated]; |
493 [self.detailViewController viewWillAppear:animated]; |
503 |
494 |
504 _reconfigurePopup = YES; |
495 _reconfigurePopup = YES; |
505 [self layoutSubviews]; |
|
506 } |
496 } |
507 |
497 |
508 |
498 |
509 - (void)viewDidAppear:(BOOL)animated |
499 - (void)viewDidAppear:(BOOL)animated |
510 { |
500 { |
511 [super viewDidAppear:animated]; |
501 [super viewDidAppear:animated]; |
512 |
502 |
513 if ([self isShowingMaster]) { |
503 if ([self isShowingMaster]) { |
514 [self.masterViewController viewDidAppear:animated]; |
504 [self.masterViewController viewDidAppear:animated]; |
515 } |
505 } |
516 [self.detailViewController viewDidAppear:animated]; |
506 [self.detailViewController viewDidAppear:animated]; |
|
507 [self layoutSubviews]; |
517 } |
508 } |
518 |
509 |
519 |
510 |
520 - (void)viewWillDisappear:(BOOL)animated |
511 - (void)viewWillDisappear:(BOOL)animated |
521 { |
512 { |
522 [super viewWillDisappear:animated]; |
513 [super viewWillDisappear:animated]; |
523 |
514 |
524 if ([self isShowingMaster]) { |
515 if ([self isShowingMaster]) { |
525 [self.masterViewController viewWillDisappear:animated]; |
516 [self.masterViewController viewWillDisappear:animated]; |
526 } |
517 } |
527 [self.detailViewController viewWillDisappear:animated]; |
518 [self.detailViewController viewWillDisappear:animated]; |
528 } |
519 } |
529 |
520 |
530 |
521 |
531 - (void)viewDidDisappear:(BOOL)animated |
522 - (void)viewDidDisappear:(BOOL)animated |
532 { |
523 { |
533 [super viewDidDisappear:animated]; |
524 [super viewDidDisappear:animated]; |
534 |
525 |
535 if ([self isShowingMaster]) { |
526 if ([self isShowingMaster]) { |
536 [self.masterViewController viewDidDisappear:animated]; |
527 [self.masterViewController viewDidDisappear:animated]; |
537 } |
528 } |
538 [self.detailViewController viewDidDisappear:animated]; |
529 [self.detailViewController viewDidDisappear:animated]; |
539 } |
530 } |
540 |
531 |
541 |
532 |
542 #pragma mark - |
533 #pragma mark - |
543 #pragma mark Popover handling |
534 #pragma mark Popover handling |
544 |
535 |
545 |
536 |
546 - (void)reconfigureForMasterInPopover:(BOOL)inPopover |
537 - (void)reconfigureForMasterInPopover:(BOOL)inPopover |
547 { |
538 { |
548 _reconfigurePopup = NO; |
539 _reconfigurePopup = NO; |
549 |
540 |
550 if ((inPopover && _hiddenPopoverController) || (!inPopover && !_hiddenPopoverController) || !self.masterViewController) { |
541 if ((inPopover && _hiddenPopoverController) || (!inPopover && !_hiddenPopoverController) || !self.masterViewController) { |
551 // Nothing to do. |
542 // Nothing to do. |
552 return; |
543 return; |
553 } |
544 } |
554 |
545 |
555 if (inPopover && !_hiddenPopoverController && !_barButtonItem) { |
546 if (inPopover && !_hiddenPopoverController && !_barButtonItem) { |
556 // Create and configure popover for our masterViewController. |
547 // Create and configure popover for our masterViewController. |
557 [_hiddenPopoverController release]; |
548 _hiddenPopoverController = nil; |
558 _hiddenPopoverController = nil; |
549 [self.masterViewController viewWillDisappear:NO]; |
559 [self.masterViewController viewWillDisappear:NO]; |
550 _hiddenPopoverController = [[UIPopoverController alloc] initWithContentViewController:self.masterViewController]; |
560 _hiddenPopoverController = [[UIPopoverController alloc] initWithContentViewController:self.masterViewController]; |
551 [self.masterViewController viewDidDisappear:NO]; |
561 [self.masterViewController viewDidDisappear:NO]; |
552 |
562 |
553 // Create and configure _barButtonItem. |
563 // Create and configure _barButtonItem. |
554 _barButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Master", nil) |
564 _barButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Master", nil) |
555 style:UIBarButtonItemStyleBordered |
565 style:UIBarButtonItemStyleBordered |
556 target:self |
566 target:self |
557 action:(self.togglesMasterPopover ? @selector(toggleMasterPopover:) : @selector(showMasterPopover:))]; |
567 action:@selector(showMasterPopover:)]; |
558 |
568 |
559 // Inform delegate of this state of affairs. |
569 // Inform delegate of this state of affairs. |
560 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willHideViewController:withBarButtonItem:forPopoverController:)]) { |
570 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willHideViewController:withBarButtonItem:forPopoverController:)]) { |
561 [(NSObject <MGSplitViewControllerDelegate> *)_delegate splitViewController:self |
571 [(NSObject <MGSplitViewControllerDelegate> *)_delegate splitViewController:self |
562 willHideViewController:self.masterViewController |
572 willHideViewController:self.masterViewController |
563 withBarButtonItem:_barButtonItem |
573 withBarButtonItem:_barButtonItem |
564 forPopoverController:_hiddenPopoverController]; |
574 forPopoverController:_hiddenPopoverController]; |
565 } |
|
566 |
|
567 } else if (!inPopover && _hiddenPopoverController && _barButtonItem) { |
|
568 // I know this looks strange, but it fixes a bizarre issue with UIPopoverController leaving masterViewController's views in disarray. |
|
569 // It does also break stuff on iOS8, so we disable it. |
|
570 if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) { |
|
571 [_hiddenPopoverController presentPopoverFromRect:CGRectZero inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO]; |
575 } |
572 } |
576 |
573 |
577 } else if (!inPopover && _hiddenPopoverController && _barButtonItem) { |
574 // Remove master from popover and destroy popover, if it exists. |
578 // I know this looks strange, but it fixes a bizarre issue with UIPopoverController leaving masterViewController's views in disarray. |
575 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
579 [_hiddenPopoverController presentPopoverFromRect:CGRectZero inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO]; |
576 _hiddenPopoverController = nil; |
580 |
577 |
581 // Remove master from popover and destroy popover, if it exists. |
578 // Inform delegate that the _barButtonItem will become invalid. |
582 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
579 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willShowViewController:invalidatingBarButtonItem:)]) { |
583 [_hiddenPopoverController release]; |
580 [(NSObject <MGSplitViewControllerDelegate> *)_delegate splitViewController:self |
584 _hiddenPopoverController = nil; |
581 willShowViewController:self.masterViewController |
585 |
582 invalidatingBarButtonItem:_barButtonItem]; |
586 // Inform delegate that the _barButtonItem will become invalid. |
583 } |
587 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willShowViewController:invalidatingBarButtonItem:)]) { |
584 |
588 [(NSObject <MGSplitViewControllerDelegate> *)_delegate splitViewController:self |
585 // Destroy _barButtonItem. |
589 willShowViewController:self.masterViewController |
586 _barButtonItem = nil; |
590 invalidatingBarButtonItem:_barButtonItem]; |
587 |
591 } |
588 // Move master view. |
592 |
589 UIView *masterView = self.masterViewController.view; |
593 // Destroy _barButtonItem. |
590 if (masterView && masterView.superview != self.view) { |
594 [_barButtonItem release]; |
591 [masterView removeFromSuperview]; |
595 _barButtonItem = nil; |
592 } |
596 |
593 } |
597 // Move master view. |
|
598 UIView *masterView = self.masterViewController.view; |
|
599 if (masterView && masterView.superview != self.view) { |
|
600 [masterView removeFromSuperview]; |
|
601 } |
|
602 } |
|
603 } |
594 } |
604 |
595 |
605 |
596 |
606 - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController |
597 - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController |
607 { |
598 { |
608 [self reconfigureForMasterInPopover:NO]; |
599 [self reconfigureForMasterInPopover:NO]; |
609 } |
600 } |
610 |
601 |
611 |
602 |
612 - (void)notePopoverDismissed |
603 - (void)notePopoverDismissed |
613 { |
604 { |
614 [self popoverControllerDidDismissPopover:_hiddenPopoverController]; |
605 [self popoverControllerDidDismissPopover:_hiddenPopoverController]; |
615 } |
606 } |
616 |
607 |
617 |
608 |
618 #pragma mark - |
609 #pragma mark - |
619 #pragma mark Animations |
610 #pragma mark Animations |
620 |
611 |
621 |
612 |
622 - (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context |
613 - (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context |
623 { |
614 { |
624 if (([animationID isEqualToString:MG_ANIMATION_CHANGE_SPLIT_ORIENTATION] || |
615 if (([animationID isEqualToString:MG_ANIMATION_CHANGE_SPLIT_ORIENTATION] || |
625 [animationID isEqualToString:MG_ANIMATION_CHANGE_SUBVIEWS_ORDER]) |
616 [animationID isEqualToString:MG_ANIMATION_CHANGE_SUBVIEWS_ORDER]) |
626 && _cornerViews) { |
617 && _cornerViews) { |
627 for (UIView *corner in _cornerViews) { |
618 for (UIView *corner in _cornerViews) { |
628 corner.hidden = NO; |
619 corner.hidden = NO; |
629 } |
620 } |
630 _dividerView.hidden = NO; |
621 _dividerView.hidden = NO; |
631 } |
622 } |
632 } |
623 } |
633 |
624 |
634 |
625 |
635 #pragma mark - |
626 #pragma mark - |
636 #pragma mark IB Actions |
627 #pragma mark IB Actions |
637 |
628 |
638 |
629 |
639 - (IBAction)toggleSplitOrientation:(id)sender |
630 - (IBAction)toggleSplitOrientation:(id)sender |
640 { |
631 { |
641 BOOL showingMaster = [self isShowingMaster]; |
632 BOOL showingMaster = [self isShowingMaster]; |
642 if (showingMaster) { |
633 if (showingMaster) { |
643 if (_cornerViews) { |
634 if (_cornerViews) { |
644 for (UIView *corner in _cornerViews) { |
635 for (UIView *corner in _cornerViews) { |
645 corner.hidden = YES; |
636 corner.hidden = YES; |
646 } |
637 } |
647 _dividerView.hidden = YES; |
638 _dividerView.hidden = YES; |
648 } |
639 } |
649 [UIView beginAnimations:MG_ANIMATION_CHANGE_SPLIT_ORIENTATION context:nil]; |
640 [UIView beginAnimations:MG_ANIMATION_CHANGE_SPLIT_ORIENTATION context:nil]; |
650 [UIView setAnimationDelegate:self]; |
641 [UIView setAnimationDelegate:self]; |
651 [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; |
642 [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; |
652 } |
643 } |
653 self.vertical = (!self.vertical); |
644 self.vertical = (!self.vertical); |
654 if (showingMaster) { |
645 if (showingMaster) { |
655 [UIView commitAnimations]; |
646 [UIView commitAnimations]; |
656 } |
647 } |
657 } |
648 } |
658 |
649 |
659 |
650 |
660 - (IBAction)toggleMasterBeforeDetail:(id)sender |
651 - (IBAction)toggleMasterBeforeDetail:(id)sender |
661 { |
652 { |
662 BOOL showingMaster = [self isShowingMaster]; |
653 BOOL showingMaster = [self isShowingMaster]; |
663 if (showingMaster) { |
654 if (showingMaster) { |
664 if (_cornerViews) { |
655 if (_cornerViews) { |
665 for (UIView *corner in _cornerViews) { |
656 for (UIView *corner in _cornerViews) { |
666 corner.hidden = YES; |
657 corner.hidden = YES; |
667 } |
658 } |
668 _dividerView.hidden = YES; |
659 _dividerView.hidden = YES; |
669 } |
660 } |
670 [UIView beginAnimations:MG_ANIMATION_CHANGE_SUBVIEWS_ORDER context:nil]; |
661 [UIView beginAnimations:MG_ANIMATION_CHANGE_SUBVIEWS_ORDER context:nil]; |
671 [UIView setAnimationDelegate:self]; |
662 [UIView setAnimationDelegate:self]; |
672 [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; |
663 [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; |
673 } |
664 } |
674 self.masterBeforeDetail = (!self.masterBeforeDetail); |
665 self.masterBeforeDetail = (!self.masterBeforeDetail); |
675 if (showingMaster) { |
666 if (showingMaster) { |
676 [UIView commitAnimations]; |
667 [UIView commitAnimations]; |
677 } |
668 } |
678 } |
669 } |
679 |
670 |
680 |
671 |
681 - (IBAction)toggleMasterView:(id)sender |
672 - (IBAction)toggleMasterView:(id)sender |
682 { |
673 { |
683 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
674 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
684 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
675 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
685 } |
676 } |
686 |
677 |
687 if (![self isShowingMaster]) { |
678 if (![self isShowingMaster]) { |
688 // We're about to show the master view. Ensure it's in place off-screen to be animated in. |
679 // We're about to show the master view. Ensure it's in place off-screen to be animated in. |
689 _reconfigurePopup = YES; |
680 _reconfigurePopup = YES; |
690 [self reconfigureForMasterInPopover:NO]; |
681 [self reconfigureForMasterInPopover:NO]; |
691 [self layoutSubviews]; |
682 [self layoutSubviews]; |
692 } |
683 } |
693 |
684 |
694 // This action functions on the current primary orientation; it is independent of the other primary orientation. |
685 // This action functions on the current primary orientation; it is independent of the other primary orientation. |
695 [UIView beginAnimations:@"toggleMaster" context:nil]; |
686 [UIView beginAnimations:@"toggleMaster" context:nil]; |
696 if (self.isLandscape) { |
687 if (self.isLandscape) { |
697 self.showsMasterInLandscape = !_showsMasterInLandscape; |
688 self.showsMasterInLandscape = !_showsMasterInLandscape; |
698 } else { |
689 } else { |
699 self.showsMasterInPortrait = !_showsMasterInPortrait; |
690 self.showsMasterInPortrait = !_showsMasterInPortrait; |
700 } |
691 } |
701 [UIView commitAnimations]; |
692 [UIView commitAnimations]; |
702 } |
693 } |
703 |
694 |
704 |
695 |
705 - (IBAction)showMasterPopover:(id) sender |
696 - (void) setTogglesMasterPopover:(BOOL)flag { |
706 { |
697 |
707 if (_hiddenPopoverController && !(_hiddenPopoverController.popoverVisible)) { |
698 togglesMasterPopover = flag; |
708 // Inform delegate. |
699 |
709 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:popoverController:willPresentViewController:)]) { |
700 if (!_barButtonItem) |
710 [(NSObject <MGSplitViewControllerDelegate> *)_delegate splitViewController:self |
701 return; |
711 popoverController:_hiddenPopoverController |
702 |
712 willPresentViewController:self.masterViewController]; |
703 _barButtonItem.action = flag ? @selector(toggleMasterPopover:) : @selector(showMasterPopover:); |
713 } |
704 |
714 |
705 } |
715 // Show popover. |
706 |
716 [_hiddenPopoverController presentPopoverFromBarButtonItem:_barButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; |
707 - (IBAction)toggleMasterPopover:(id)sender |
717 } |
708 { |
|
709 |
|
710 if (!_hiddenPopoverController) |
|
711 return; |
|
712 |
|
713 if (_hiddenPopoverController.popoverVisible) { |
|
714 |
|
715 [self hideMasterPopover:sender]; |
|
716 |
|
717 } else { |
|
718 |
|
719 [self showMasterPopover:sender]; |
|
720 |
|
721 } |
|
722 |
|
723 } |
|
724 |
|
725 |
|
726 - (IBAction)showMasterPopover:(id)sender |
|
727 { |
|
728 if (_hiddenPopoverController && !(_hiddenPopoverController.popoverVisible)) { |
|
729 // Inform delegate. |
|
730 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:popoverController:willPresentViewController:)]) { |
|
731 [(NSObject <MGSplitViewControllerDelegate> *)_delegate splitViewController:self |
|
732 popoverController:_hiddenPopoverController |
|
733 willPresentViewController:self.masterViewController]; |
|
734 } |
|
735 |
|
736 // Show popover. |
|
737 [_hiddenPopoverController presentPopoverFromBarButtonItem:(sender ? sender : _barButtonItem) permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; |
|
738 } |
|
739 } |
|
740 |
|
741 |
|
742 - (IBAction)hideMasterPopover:(id)sender |
|
743 { |
|
744 |
|
745 if(_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
|
746 |
|
747 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:popoverController:willDismissViewController:)]) { |
|
748 |
|
749 [(NSObject <MGSplitViewControllerDelegate> *)_delegate splitViewController:self popoverController:_hiddenPopoverController willDismissViewController:self.masterViewController]; |
|
750 |
|
751 } |
|
752 |
|
753 [_hiddenPopoverController dismissPopoverAnimated:YES]; |
|
754 |
|
755 } |
|
756 |
718 } |
757 } |
719 |
758 |
720 |
759 |
721 #pragma mark - |
760 #pragma mark - |
722 #pragma mark Accessors and properties |
761 #pragma mark Accessors and properties |
723 |
762 |
724 |
763 |
725 - (id)delegate |
764 - (id)delegate |
726 { |
765 { |
727 return _delegate; |
766 return _delegate; |
728 } |
767 } |
729 |
768 |
730 |
769 |
731 - (void)setDelegate:(id <MGSplitViewControllerDelegate>)newDelegate |
770 - (void)setDelegate:(id <MGSplitViewControllerDelegate>)newDelegate |
732 { |
771 { |
733 if (newDelegate != _delegate && |
772 if (newDelegate != _delegate && |
734 (!newDelegate || [(NSObject *)newDelegate conformsToProtocol:@protocol(MGSplitViewControllerDelegate)])) { |
773 (!newDelegate || [(NSObject *)newDelegate conformsToProtocol:@protocol(MGSplitViewControllerDelegate)])) { |
735 _delegate = newDelegate; |
774 _delegate = newDelegate; |
736 } |
775 } |
737 } |
776 } |
738 |
777 |
739 |
778 |
740 - (BOOL)showsMasterInPortrait |
779 - (BOOL)showsMasterInPortrait |
741 { |
780 { |
742 return _showsMasterInPortrait; |
781 return _showsMasterInPortrait; |
743 } |
782 } |
744 |
783 |
745 |
784 |
746 - (void)setShowsMasterInPortrait:(BOOL)flag |
785 - (void)setShowsMasterInPortrait:(BOOL)flag |
747 { |
786 { |
748 if (flag != _showsMasterInPortrait) { |
787 if (flag != _showsMasterInPortrait) { |
749 _showsMasterInPortrait = flag; |
788 _showsMasterInPortrait = flag; |
750 |
789 |
751 if (![self isLandscape]) { // i.e. if this will cause a visual change. |
790 if (![self isLandscape]) { // i.e. if this will cause a visual change. |
752 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
791 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
753 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
792 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
754 } |
793 } |
755 |
794 |
756 // Rearrange views. |
795 // Rearrange views. |
757 _reconfigurePopup = YES; |
796 _reconfigurePopup = YES; |
758 [self layoutSubviews]; |
797 [self layoutSubviews]; |
759 } |
798 } |
760 } |
799 } |
761 } |
800 } |
762 |
801 |
763 |
802 |
764 - (BOOL)showsMasterInLandscape |
803 - (BOOL)showsMasterInLandscape |
765 { |
804 { |
766 return _showsMasterInLandscape; |
805 return _showsMasterInLandscape; |
767 } |
806 } |
768 |
807 |
769 |
808 |
770 - (void)setShowsMasterInLandscape:(BOOL)flag |
809 - (void)setShowsMasterInLandscape:(BOOL)flag |
771 { |
810 { |
772 if (flag != _showsMasterInLandscape) { |
811 if (flag != _showsMasterInLandscape) { |
773 _showsMasterInLandscape = flag; |
812 _showsMasterInLandscape = flag; |
774 |
813 |
775 if ([self isLandscape]) { // i.e. if this will cause a visual change. |
814 if ([self isLandscape]) { // i.e. if this will cause a visual change. |
776 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
815 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
777 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
816 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
778 } |
817 } |
779 |
818 |
780 // Rearrange views. |
819 // Rearrange views. |
781 _reconfigurePopup = YES; |
820 _reconfigurePopup = YES; |
782 [self layoutSubviews]; |
821 [self layoutSubviews]; |
783 } |
822 } |
784 } |
823 } |
785 } |
824 } |
786 |
825 |
787 |
826 |
788 - (BOOL)isVertical |
827 - (BOOL)isVertical |
789 { |
828 { |
790 return _vertical; |
829 return _vertical; |
791 } |
830 } |
792 |
831 |
793 |
832 |
794 - (void)setVertical:(BOOL)flag |
833 - (void)setVertical:(BOOL)flag |
795 { |
834 { |
796 if (flag != _vertical) { |
835 if (flag != _vertical) { |
797 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
836 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
798 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
837 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
799 } |
838 } |
800 |
839 |
801 _vertical = flag; |
840 _vertical = flag; |
802 |
841 |
803 // Inform delegate. |
842 // Inform delegate. |
804 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willChangeSplitOrientationToVertical:)]) { |
843 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willChangeSplitOrientationToVertical:)]) { |
805 [_delegate splitViewController:self willChangeSplitOrientationToVertical:_vertical]; |
844 [_delegate splitViewController:self willChangeSplitOrientationToVertical:_vertical]; |
806 } |
845 } |
807 |
846 |
808 [self layoutSubviews]; |
847 [self layoutSubviews]; |
809 } |
848 } |
810 } |
849 } |
811 |
850 |
812 |
851 |
813 - (BOOL)isMasterBeforeDetail |
852 - (BOOL)isMasterBeforeDetail |
814 { |
853 { |
815 return _masterBeforeDetail; |
854 return _masterBeforeDetail; |
816 } |
855 } |
817 |
856 |
818 |
857 |
819 - (void)setMasterBeforeDetail:(BOOL)flag |
858 - (void)setMasterBeforeDetail:(BOOL)flag |
820 { |
859 { |
821 if (flag != _masterBeforeDetail) { |
860 if (flag != _masterBeforeDetail) { |
822 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
861 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
823 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
862 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
824 } |
863 } |
825 |
864 |
826 _masterBeforeDetail = flag; |
865 _masterBeforeDetail = flag; |
827 |
866 |
828 if ([self isShowingMaster]) { |
867 if ([self isShowingMaster]) { |
829 [self layoutSubviews]; |
868 [self layoutSubviews]; |
830 } |
869 } |
831 } |
870 } |
832 } |
871 } |
833 |
872 |
834 |
873 |
835 - (float)splitPosition |
874 - (float)splitPosition |
836 { |
875 { |
837 return _splitPosition; |
876 return _splitPosition; |
838 } |
877 } |
839 |
878 |
840 |
879 |
841 - (void)setSplitPosition:(float)posn |
880 - (void)setSplitPosition:(float)posn |
842 { |
881 { |
843 // Check to see if delegate wishes to constrain the position. |
882 // Check to see if delegate wishes to constrain the position. |
844 float newPosn = posn; |
883 float newPosn = posn; |
845 BOOL constrained = NO; |
884 BOOL constrained = NO; |
846 CGSize fullSize = [self splitViewSizeForOrientation:self.interfaceOrientation]; |
885 CGSize fullSize = [self splitViewSizeForOrientation:self.interfaceOrientation]; |
847 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:constrainSplitPosition:splitViewSize:)]) { |
886 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:constrainSplitPosition:splitViewSize:)]) { |
848 newPosn = [_delegate splitViewController:self constrainSplitPosition:newPosn splitViewSize:fullSize]; |
887 newPosn = [_delegate splitViewController:self constrainSplitPosition:newPosn splitViewSize:fullSize]; |
849 constrained = YES; // implicitly trust delegate's response. |
888 constrained = YES; // implicitly trust delegate's response. |
850 |
889 |
851 } else { |
890 } else { |
852 // Apply default constraints if delegate doesn't wish to participate. |
891 // Apply default constraints if delegate doesn't wish to participate. |
853 float minPos = MG_MIN_VIEW_WIDTH; |
892 float minPos = MG_MIN_VIEW_WIDTH; |
854 float maxPos = ((_vertical) ? fullSize.width : fullSize.height) - (MG_MIN_VIEW_WIDTH + _splitWidth); |
893 float maxPos = (float) (((_vertical) ? fullSize.width : fullSize.height) - (MG_MIN_VIEW_WIDTH + _splitWidth)); |
855 constrained = (newPosn != _splitPosition && newPosn >= minPos && newPosn <= maxPos); |
894 constrained = (newPosn != _splitPosition && newPosn >= minPos && newPosn <= maxPos); |
856 } |
895 } |
857 |
896 |
858 if (constrained) { |
897 if (constrained) { |
859 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
898 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
860 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
899 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
861 } |
900 } |
862 |
901 |
863 _splitPosition = newPosn; |
902 _splitPosition = newPosn; |
864 |
903 |
865 // Inform delegate. |
904 // Inform delegate. |
866 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willMoveSplitToPosition:)]) { |
905 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willMoveSplitToPosition:)]) { |
867 [_delegate splitViewController:self willMoveSplitToPosition:_splitPosition]; |
906 [_delegate splitViewController:self willMoveSplitToPosition:_splitPosition]; |
868 } |
907 } |
869 |
908 |
870 if ([self isShowingMaster]) { |
909 if ([self isShowingMaster]) { |
871 [self layoutSubviews]; |
910 [self layoutSubviews]; |
872 } |
911 } |
873 } |
912 } |
874 } |
913 } |
875 |
914 |
876 |
915 |
877 - (void)setSplitPosition:(float)posn animated:(BOOL)animate |
916 - (void)setSplitPosition:(float)posn animated:(BOOL)animate |
878 { |
917 { |
879 BOOL shouldAnimate = (animate && [self isShowingMaster]); |
918 BOOL shouldAnimate = (animate && [self isShowingMaster]); |
880 if (shouldAnimate) { |
919 if (shouldAnimate) { |
881 [UIView beginAnimations:@"SplitPosition" context:nil]; |
920 [UIView beginAnimations:@"SplitPosition" context:nil]; |
882 } |
921 } |
883 [self setSplitPosition:posn]; |
922 [self setSplitPosition:posn]; |
884 if (shouldAnimate) { |
923 if (shouldAnimate) { |
885 [UIView commitAnimations]; |
924 [UIView commitAnimations]; |
886 } |
925 } |
887 } |
926 } |
888 |
927 |
889 |
928 |
890 - (float)splitWidth |
929 - (float)splitWidth |
891 { |
930 { |
892 return _splitWidth; |
931 return _splitWidth; |
893 } |
932 } |
894 |
933 |
895 |
934 |
896 - (void)setSplitWidth:(float)width |
935 - (void)setSplitWidth:(float)width |
897 { |
936 { |
898 if (width != _splitWidth && width >= 0) { |
937 if (width != _splitWidth && width >= 0) { |
899 _splitWidth = width; |
938 _splitWidth = width; |
900 if ([self isShowingMaster]) { |
939 if ([self isShowingMaster]) { |
901 [self layoutSubviews]; |
940 [self layoutSubviews]; |
902 } |
941 } |
903 } |
942 } |
904 } |
943 } |
905 |
944 |
906 |
945 |
907 - (NSArray *)viewControllers |
946 - (NSArray *)viewControllers |
908 { |
947 { |
909 return [[_viewControllers copy] autorelease]; |
948 return [_viewControllers copy]; |
910 } |
949 } |
911 |
950 |
912 |
951 |
913 - (void)setViewControllers:(NSArray *)controllers |
952 - (void)setViewControllers:(NSArray *)controllers |
914 { |
953 { |
915 if (controllers != _viewControllers) { |
954 if (controllers != _viewControllers) { |
916 for (UIViewController *controller in _viewControllers) { |
955 for (UIViewController *controller in _viewControllers) { |
917 if ([controller isKindOfClass:[UIViewController class]]) { |
956 if ([controller isKindOfClass:[UIViewController class]]) { |
918 [controller.view removeFromSuperview]; |
957 [controller.view removeFromSuperview]; |
919 } |
958 } |
920 } |
959 } |
921 [_viewControllers release]; |
960 _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; |
922 _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; |
961 if (controllers && [controllers count] >= 2) { |
923 if (controllers && [controllers count] >= 2) { |
962 self.masterViewController = [controllers objectAtIndex:0]; |
924 self.masterViewController = [controllers objectAtIndex:0]; |
963 self.detailViewController = [controllers objectAtIndex:1]; |
925 self.detailViewController = [controllers objectAtIndex:1]; |
964 } else { |
926 } else { |
965 NSLog(@"Error: %@ requires 2 view-controllers. (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); |
927 NSLog(@"Error: %@ requires 2 view-controllers. (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); |
966 } |
928 } |
967 |
929 |
968 [self layoutSubviews]; |
930 [self layoutSubviews]; |
969 } |
931 } |
|
932 } |
970 } |
933 |
971 |
934 |
972 |
935 - (UIViewController *)masterViewController |
973 - (UIViewController *)masterViewController |
936 { |
974 { |
937 if (_viewControllers && [_viewControllers count] > 0) { |
975 if (_viewControllers && [_viewControllers count] > 0) { |
938 NSObject *controller = [_viewControllers objectAtIndex:0]; |
976 UIViewController *controller = (UIViewController *)[_viewControllers objectAtIndex:0]; |
939 if ([controller isKindOfClass:[UIViewController class]]) { |
977 if ([controller isKindOfClass:[UIViewController class]]) { |
940 return [[controller retain] autorelease]; |
978 return controller; |
941 } |
979 } |
942 } |
980 } |
943 |
981 |
944 return nil; |
982 return nil; |
945 } |
983 } |
946 |
984 |
947 |
985 |
948 - (void)setMasterViewController:(UIViewController *)master |
986 - (void)setMasterViewController:(UIViewController *)master |
949 { |
987 { |
950 if (!_viewControllers) { |
988 if (!_viewControllers) { |
951 _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; |
989 _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; |
952 } |
990 } |
953 |
991 |
954 NSObject *newMaster = master; |
992 NSObject *newMaster = master; |
955 if (!newMaster) { |
993 if (!newMaster) { |
956 newMaster = [NSNull null]; |
994 newMaster = [NSNull null]; |
957 } |
995 } |
958 |
996 |
959 BOOL changed = YES; |
997 BOOL changed = YES; |
960 if ([_viewControllers count] > 0) { |
998 if ([_viewControllers count] > 0) { |
961 if ([_viewControllers objectAtIndex:0] == newMaster) { |
999 if ([_viewControllers objectAtIndex:0] == newMaster) { |
962 changed = NO; |
1000 changed = NO; |
963 } else { |
1001 } else { |
964 [_viewControllers replaceObjectAtIndex:0 withObject:newMaster]; |
1002 [_viewControllers replaceObjectAtIndex:0 withObject:newMaster]; |
965 } |
1003 } |
966 |
1004 |
967 } else { |
1005 } else { |
968 [_viewControllers addObject:newMaster]; |
1006 [_viewControllers addObject:newMaster]; |
969 } |
1007 } |
970 |
1008 |
971 if (changed) { |
1009 if (changed) { |
972 [self layoutSubviews]; |
1010 [self layoutSubviews]; |
973 } |
1011 } |
974 } |
1012 } |
975 |
1013 |
976 |
1014 |
977 - (UIViewController *)detailViewController |
1015 - (UIViewController *)detailViewController |
978 { |
1016 { |
979 if (_viewControllers && [_viewControllers count] > 1) { |
1017 if (_viewControllers && [_viewControllers count] > 1) { |
980 NSObject *controller = [_viewControllers objectAtIndex:1]; |
1018 UIViewController *controller = (UIViewController *)[_viewControllers objectAtIndex:1]; |
981 if ([controller isKindOfClass:[UIViewController class]]) { |
1019 if ([controller isKindOfClass:[UIViewController class]]) { |
982 return [[controller retain] autorelease]; |
1020 return controller; |
983 } |
1021 } |
984 } |
1022 } |
985 |
1023 |
986 return nil; |
1024 return nil; |
987 } |
1025 } |
988 |
1026 |
989 |
1027 |
990 - (void)setDetailViewController:(UIViewController *)detail |
1028 - (void)setDetailViewController:(UIViewController *)detail |
991 { |
1029 { |
992 if (!_viewControllers) { |
1030 if (!_viewControllers) { |
993 _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; |
1031 _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; |
994 [_viewControllers addObject:[NSNull null]]; |
1032 [_viewControllers addObject:[NSNull null]]; |
995 } |
1033 } |
996 |
1034 |
997 BOOL changed = YES; |
1035 BOOL changed = YES; |
998 if ([_viewControllers count] > 1) { |
1036 if ([_viewControllers count] > 1) { |
999 if ([_viewControllers objectAtIndex:1] == detail) { |
1037 if ([_viewControllers objectAtIndex:1] == detail) { |
1000 changed = NO; |
1038 changed = NO; |
1001 } else { |
1039 } else { |
1002 [_viewControllers replaceObjectAtIndex:1 withObject:detail]; |
1040 [_viewControllers replaceObjectAtIndex:1 withObject:detail]; |
1003 } |
1041 } |
1004 |
1042 |
1005 } else { |
1043 } else { |
1006 [_viewControllers addObject:detail]; |
1044 [_viewControllers addObject:detail]; |
1007 } |
1045 } |
1008 |
1046 |
1009 if (changed) { |
1047 if (changed) { |
1010 [self layoutSubviews]; |
1048 [self layoutSubviews]; |
1011 } |
1049 } |
1012 } |
1050 } |
1013 |
1051 |
1014 |
1052 |
1015 - (MGSplitDividerView *)dividerView |
1053 - (MGSplitDividerView *)dividerView |
1016 { |
1054 { |
1017 return [[_dividerView retain] autorelease]; |
1055 return _dividerView; |
1018 } |
1056 } |
1019 |
1057 |
1020 |
1058 |
1021 - (void)setDividerView:(MGSplitDividerView *)divider |
1059 - (void)setDividerView:(MGSplitDividerView *)divider |
1022 { |
1060 { |
1023 if (divider != _dividerView) { |
1061 if (divider != _dividerView) { |
1024 [_dividerView removeFromSuperview]; |
1062 [_dividerView removeFromSuperview]; |
1025 [_dividerView release]; |
1063 _dividerView = divider; |
1026 _dividerView = [divider retain]; |
1064 _dividerView.splitViewController = self; |
1027 _dividerView.splitViewController = self; |
1065 _dividerView.backgroundColor = MG_DEFAULT_CORNER_COLOR; |
1028 _dividerView.backgroundColor = MG_DEFAULT_CORNER_COLOR; |
1066 if ([self isShowingMaster]) { |
1029 if ([self isShowingMaster]) { |
1067 [self layoutSubviews]; |
1030 [self layoutSubviews]; |
1068 } |
1031 } |
1069 } |
1032 } |
|
1033 } |
1070 } |
1034 |
1071 |
1035 |
1072 |
1036 - (BOOL)allowsDraggingDivider |
1073 - (BOOL)allowsDraggingDivider |
1037 { |
1074 { |
1038 if (_dividerView) { |
1075 if (_dividerView) { |
1039 return _dividerView.allowsDragging; |
1076 return _dividerView.allowsDragging; |
1040 } |
1077 } |
1041 |
1078 |
1042 return NO; |
1079 return NO; |
1043 } |
1080 } |
1044 |
1081 |
1045 |
1082 |
1046 - (void)setAllowsDraggingDivider:(BOOL)flag |
1083 - (void)setAllowsDraggingDivider:(BOOL)flag |
1047 { |
1084 { |
1048 if (self.allowsDraggingDivider != flag && _dividerView) { |
1085 if (self.allowsDraggingDivider != flag && _dividerView) { |
1049 _dividerView.allowsDragging = flag; |
1086 _dividerView.allowsDragging = flag; |
1050 } |
1087 } |
1051 } |
1088 } |
1052 |
1089 |
1053 |
1090 |
1054 - (MGSplitViewDividerStyle)dividerStyle |
1091 - (MGSplitViewDividerStyle)dividerStyle |
1055 { |
1092 { |
1056 return _dividerStyle; |
1093 return _dividerStyle; |
1057 } |
1094 } |
1058 |
1095 |
1059 |
1096 |
1060 - (void)setDividerStyle:(MGSplitViewDividerStyle)newStyle |
1097 - (void)setDividerStyle:(MGSplitViewDividerStyle)newStyle |
1061 { |
1098 { |
1062 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
1099 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
1063 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
1100 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
1064 } |
1101 } |
1065 |
1102 |
1066 // We don't check to see if newStyle equals _dividerStyle, because it's a meta-setting. |
1103 // We don't check to see if newStyle equals _dividerStyle, because it's a meta-setting. |
1067 // Aspects could have been changed since it was set. |
1104 // Aspects could have been changed since it was set. |
1068 _dividerStyle = newStyle; |
1105 _dividerStyle = newStyle; |
1069 |
1106 |
1070 // Reconfigure general appearance and behaviour. |
1107 // Reconfigure general appearance and behaviour. |
1071 float cornerRadius; |
1108 float cornerRadius = 0.0f; |
1072 if (_dividerStyle == MGSplitViewDividerStyleThin) { |
1109 if (_dividerStyle == MGSplitViewDividerStyleThin) { |
1073 cornerRadius = MG_DEFAULT_CORNER_RADIUS; |
1110 cornerRadius = NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_7_0 ? 0 : MG_DEFAULT_CORNER_RADIUS; |
1074 _splitWidth = MG_DEFAULT_SPLIT_WIDTH; |
1111 _splitWidth = MG_DEFAULT_SPLIT_WIDTH; |
1075 self.allowsDraggingDivider = NO; |
1112 self.allowsDraggingDivider = NO; |
1076 |
1113 |
1077 } else if (_dividerStyle == MGSplitViewDividerStylePaneSplitter) { |
1114 } else if (_dividerStyle == MGSplitViewDividerStylePaneSplitter) { |
1078 cornerRadius = MG_PANESPLITTER_CORNER_RADIUS; |
1115 cornerRadius = MG_PANESPLITTER_CORNER_RADIUS; |
1079 _splitWidth = MG_PANESPLITTER_SPLIT_WIDTH; |
1116 _splitWidth = MG_PANESPLITTER_SPLIT_WIDTH; |
1080 self.allowsDraggingDivider = YES; |
1117 self.allowsDraggingDivider = YES; |
1081 } |
1118 } |
1082 |
1119 |
1083 // Update divider and corners. |
1120 // Update divider and corners. |
1084 [_dividerView setNeedsDisplay]; |
1121 [_dividerView setNeedsDisplay]; |
1085 if (_cornerViews) { |
1122 if (_cornerViews) { |
1086 for (MGSplitCornersView *corner in _cornerViews) { |
1123 for (MGSplitCornersView *corner in _cornerViews) { |
1087 corner.cornerRadius = cornerRadius; |
1124 corner.cornerRadius = cornerRadius; |
1088 } |
1125 } |
1089 } |
1126 } |
1090 |
1127 |
1091 // Layout all views. |
1128 // Layout all views. |
1092 [self layoutSubviews]; |
1129 [self layoutSubviews]; |
1093 } |
1130 } |
1094 |
1131 |
1095 |
1132 |
1096 - (void)setDividerStyle:(MGSplitViewDividerStyle)newStyle animated:(BOOL)animate |
1133 - (void)setDividerStyle:(MGSplitViewDividerStyle)newStyle animated:(BOOL)animate |
1097 { |
1134 { |
1098 BOOL shouldAnimate = (animate && [self isShowingMaster]); |
1135 BOOL shouldAnimate = (animate && [self isShowingMaster]); |
1099 if (shouldAnimate) { |
1136 if (shouldAnimate) { |
1100 [UIView beginAnimations:@"DividerStyle" context:nil]; |
1137 [UIView beginAnimations:@"DividerStyle" context:nil]; |
1101 } |
1138 } |
1102 [self setDividerStyle:newStyle]; |
1139 [self setDividerStyle:newStyle]; |
1103 if (shouldAnimate) { |
1140 if (shouldAnimate) { |
1104 [UIView commitAnimations]; |
1141 [UIView commitAnimations]; |
1105 } |
1142 } |
1106 } |
1143 } |
1107 |
1144 |
1108 |
1145 |
1109 - (NSArray *)cornerViews |
1146 - (NSArray *)cornerViews |
1110 { |
1147 { |
1111 if (_cornerViews) { |
1148 if (_cornerViews) { |
1112 return [[_cornerViews retain] autorelease]; |
1149 return _cornerViews; |
1113 } |
1150 } |
1114 |
1151 |
1115 return nil; |
1152 return nil; |
1116 } |
1153 } |
1117 |
1154 |
1118 |
1155 |
1119 @synthesize showsMasterInPortrait; |
1156 @synthesize showsMasterInPortrait; |
1120 @synthesize showsMasterInLandscape; |
1157 @synthesize showsMasterInLandscape; |
1121 @synthesize vertical; |
1158 @synthesize vertical; |
1122 @synthesize delegate; |
1159 @synthesize delegate; |
1123 @synthesize viewControllers; |
1160 @synthesize viewControllers = _viewControllers; |
1124 @synthesize masterViewController; |
1161 @synthesize masterViewController; |
1125 @synthesize detailViewController; |
1162 @synthesize detailViewController; |
1126 @synthesize dividerView; |
1163 @synthesize dividerView = _dividerView; |
1127 @synthesize splitPosition; |
1164 @synthesize splitPosition; |
1128 @synthesize splitWidth; |
1165 @synthesize splitWidth; |
1129 @synthesize allowsDraggingDivider; |
1166 @synthesize allowsDraggingDivider; |
1130 @synthesize dividerStyle; |
1167 @synthesize dividerStyle; |
1131 |
1168 |
|
1169 @synthesize togglesMasterPopover; |
1132 |
1170 |
1133 @end |
1171 @end |