OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // ====== New Architecture ===== | 5 // ====== New Architecture ===== |
6 // = This code is only used in the new iOS Chrome architecture. = | 6 // = This code is only used in the new iOS Chrome architecture. = |
7 // ============================================================================ | 7 // ============================================================================ |
8 | 8 |
9 #import "ios/clean/chrome/browser/ui/tab/tab_container_view_controller.h" | 9 #import "ios/clean/chrome/browser/ui/tab/tab_container_view_controller.h" |
10 | 10 |
11 #import "base/mac/foundation_util.h" | |
12 #import "ios/clean/chrome/browser/ui/ui_types.h" | 11 #import "ios/clean/chrome/browser/ui/ui_types.h" |
13 | 12 |
14 #if !defined(__has_feature) || !__has_feature(objc_arc) | 13 #if !defined(__has_feature) || !__has_feature(objc_arc) |
15 #error "This file requires ARC support." | 14 #error "This file requires ARC support." |
16 #endif | 15 #endif |
17 | 16 |
18 namespace { | 17 namespace { |
19 CGFloat kToolbarHeight = 44.0; | 18 CGFloat kToolbarHeight = 44.0f; |
19 CGFloat kTabStripHeight = 200.0f; | |
20 } | 20 } |
21 | 21 |
22 @interface TabContainerViewController () | 22 @interface TabContainerViewController () |
23 | 23 |
24 // Whichever view controller is at the top of the screen. This view controller | 24 // Container views for child view controllers. The child view controller's |
25 // controls the status bar. | 25 // view is added as a subview that fills it's container view via autoresizing. |
26 @property(nonatomic, weak) UIViewController* topmostViewController; | 26 @property(nonatomic, strong) UIView* tabStripView; |
27 @property(nonatomic, strong) UIView* toolbarView; | |
28 @property(nonatomic, strong) UIView* contentView; | |
27 | 29 |
28 @property(nonatomic, strong) Constraints* contentConstraintsWithToolbar; | 30 // Height constraints for tabStripView and toolbarView. |
29 @property(nonatomic, strong) Constraints* contentConstraintsWithoutToolbar; | 31 @property(nonatomic, strong) NSLayoutConstraint* tabStripHeightConstraint; |
30 @property(nonatomic, strong) Constraints* toolbarConstraints; | 32 @property(nonatomic, strong) NSLayoutConstraint* toolbarHeightConstraint; |
31 | 33 |
32 // Cache for forwarding methods to child view controllers. | 34 // Cache for forwarding methods to child view controllers. |
33 @property(nonatomic, assign) SEL actionToForward; | 35 @property(nonatomic, assign) SEL actionToForward; |
34 @property(nonatomic, weak) UIResponder* forwardingTarget; | 36 @property(nonatomic, weak) UIResponder* forwardingTarget; |
35 | 37 |
36 // Contained view controller utility methods. | 38 // Abstract base method for subclasses to implement. |
37 - (void)removeChildViewController:(UIViewController*)viewController; | 39 - (Constraints*)layoutSpecificConstraints; |
38 | |
39 // Called after a new content view controller is set, but before | |
40 // |-didMoveToParentViewController:| is called on that view controller. | |
41 - (void)didAddContentViewController; | |
42 | |
43 // Called after a new toolbar view controller is set, but before | |
44 // |-didMoveToParentViewController:| is called on that view controller. | |
45 - (void)didAddToolbarViewController; | |
46 | |
47 // Methods to populate the constraint properties. | |
48 - (void)updateContentConstraintsWithToolbar; | |
49 - (void)updateContentConstraintsWithoutToolbar; | |
50 - (void)updateToolbarConstraints; | |
51 | 40 |
52 @end | 41 @end |
53 | 42 |
54 @implementation TabContainerViewController | 43 @implementation TabContainerViewController |
55 | 44 |
56 @synthesize contentViewController = _contentViewController; | 45 @synthesize contentViewController = _contentViewController; |
57 @synthesize toolbarViewController = _toolbarViewController; | 46 @synthesize toolbarViewController = _toolbarViewController; |
58 @synthesize topmostViewController = _topmostViewController; | 47 @synthesize tabStripViewController = _tabStripViewController; |
59 @synthesize contentConstraintsWithToolbar = _contentConstraintsWithToolbar; | 48 @synthesize tabStripView = _tabStripView; |
60 @synthesize contentConstraintsWithoutToolbar = | 49 @synthesize toolbarView = _toolbarView; |
61 _contentConstraintsWithoutToolbar; | 50 @synthesize contentView = _contentView; |
62 @synthesize toolbarConstraints = _toolbarConstraints; | 51 @synthesize tabStripHeightConstraint = _tabStripHeightConstraint; |
52 @synthesize toolbarHeightConstraint = _toolbarHeightConstraint; | |
63 @synthesize actionToForward = _actionToForward; | 53 @synthesize actionToForward = _actionToForward; |
64 @synthesize forwardingTarget = _forwardingTarget; | 54 @synthesize forwardingTarget = _forwardingTarget; |
65 | 55 |
56 #pragma mark - UIViewController | |
57 | |
58 - (void)viewDidLoad { | |
59 [super viewDidLoad]; | |
60 self.tabStripView = [[UIView alloc] init]; | |
61 self.toolbarView = [[UIView alloc] init]; | |
62 self.contentView = [[UIView alloc] init]; | |
63 [self.view addSubview:self.tabStripView]; | |
64 [self.view addSubview:self.toolbarView]; | |
65 [self.view addSubview:self.contentView]; | |
66 self.tabStripView.translatesAutoresizingMaskIntoConstraints = NO; | |
67 self.toolbarView.translatesAutoresizingMaskIntoConstraints = NO; | |
68 self.contentView.translatesAutoresizingMaskIntoConstraints = NO; | |
69 self.view.backgroundColor = [UIColor blackColor]; | |
70 self.tabStripView.backgroundColor = [UIColor blackColor]; | |
71 self.toolbarView.backgroundColor = [UIColor blackColor]; | |
72 self.contentView.backgroundColor = [UIColor blackColor]; | |
73 | |
74 [self addChildViewController:self.tabStripViewController | |
75 toSubview:self.tabStripView]; | |
76 [self addChildViewController:self.toolbarViewController | |
77 toSubview:self.toolbarView]; | |
78 [self addChildViewController:self.contentViewController | |
79 toSubview:self.contentView]; | |
80 | |
81 self.tabStripHeightConstraint = | |
82 [self.tabStripView.heightAnchor constraintEqualToConstant:0.0f]; | |
83 self.toolbarHeightConstraint = | |
84 [self.toolbarView.heightAnchor constraintEqualToConstant:0.0f]; | |
85 if (self.toolbarViewController) { | |
86 self.toolbarHeightConstraint.constant = kToolbarHeight; | |
87 } | |
88 | |
89 [NSLayoutConstraint activateConstraints:[self commonConstraints]]; | |
90 [NSLayoutConstraint activateConstraints:[self layoutSpecificConstraints]]; | |
91 } | |
92 | |
66 #pragma mark - Public properties | 93 #pragma mark - Public properties |
67 | 94 |
68 - (void)setContentViewController:(UIViewController*)contentViewController { | 95 - (void)setContentViewController:(UIViewController*)contentViewController { |
69 if (self.contentViewController == contentViewController) | 96 if (self.contentViewController == contentViewController) |
70 return; | 97 return; |
71 | 98 if ([self isViewLoaded]) { |
72 // Remove the current content view controller, if any. | 99 [self removeChildViewController:self.contentViewController]; |
73 [NSLayoutConstraint | 100 [self addChildViewController:contentViewController |
74 deactivateConstraints:self.contentConstraintsWithoutToolbar]; | 101 toSubview:self.contentView]; |
75 [NSLayoutConstraint deactivateConstraints:self.contentConstraintsWithToolbar]; | 102 } |
76 [self removeChildViewController:self.contentViewController]; | |
77 | |
78 // Add the new content view controller. | |
79 [self addChildViewController:contentViewController]; | |
80 contentViewController.view.translatesAutoresizingMaskIntoConstraints = NO; | |
81 [self.view addSubview:contentViewController.view]; | |
82 _contentViewController = contentViewController; | 103 _contentViewController = contentViewController; |
83 [self didAddContentViewController]; | |
84 [self.view setNeedsUpdateConstraints]; | |
85 [self.contentViewController didMoveToParentViewController:self]; | |
86 } | 104 } |
87 | 105 |
88 - (void)setToolbarViewController:(UIViewController*)toolbarViewController { | 106 - (void)setToolbarViewController:(UIViewController*)toolbarViewController { |
89 if (self.toolbarViewController == toolbarViewController) | 107 if (self.toolbarViewController == toolbarViewController) |
90 return; | 108 return; |
91 | 109 if ([self isViewLoaded]) { |
92 // Remove the current toolbar view controller, if any. | 110 [self removeChildViewController:self.toolbarViewController]; |
93 [NSLayoutConstraint deactivateConstraints:self.toolbarConstraints]; | 111 [self addChildViewController:toolbarViewController |
94 [NSLayoutConstraint deactivateConstraints:self.contentConstraintsWithToolbar]; | 112 toSubview:self.toolbarView]; |
95 [self removeChildViewController:self.toolbarViewController]; | 113 } |
96 | |
97 // Add the new toolbar view controller. | |
98 [self addChildViewController:toolbarViewController]; | |
99 toolbarViewController.view.translatesAutoresizingMaskIntoConstraints = NO; | |
100 [self.view addSubview:toolbarViewController.view]; | |
101 _toolbarViewController = toolbarViewController; | 114 _toolbarViewController = toolbarViewController; |
102 [self didAddToolbarViewController]; | |
103 [self.view setNeedsUpdateConstraints]; | |
104 [self.toolbarViewController didMoveToParentViewController:self]; | |
105 } | 115 } |
106 | 116 |
107 #pragma mark - UIViewController | 117 - (void)setTabStripViewController:(UIViewController*)tabStripViewController { |
108 | 118 if (self.tabStripViewController == tabStripViewController) |
109 - (void)updateViewConstraints { | 119 return; |
110 if (self.toolbarViewController) { | 120 if ([self isViewLoaded]) { |
111 [NSLayoutConstraint activateConstraints:self.toolbarConstraints]; | 121 [self removeChildViewController:self.tabStripViewController]; |
112 [NSLayoutConstraint activateConstraints:self.contentConstraintsWithToolbar]; | 122 [self addChildViewController:tabStripViewController |
113 } else { | 123 toSubview:self.tabStripView]; |
114 [NSLayoutConstraint | |
115 activateConstraints:self.contentConstraintsWithoutToolbar]; | |
116 } | 124 } |
117 [super updateViewConstraints]; | 125 _tabStripViewController = tabStripViewController; |
118 } | 126 } |
119 | 127 |
120 - (UIViewController*)childViewControllerForStatusBarHidden { | 128 #pragma mark - ChildViewController helper methods |
121 return self.topmostViewController; | 129 |
130 - (void)addChildViewController:(UIViewController*)viewController | |
131 toSubview:(UIView*)subview { | |
132 if (!viewController || !subview) { | |
133 return; | |
134 } | |
135 [self addChildViewController:viewController]; | |
136 viewController.view.translatesAutoresizingMaskIntoConstraints = YES; | |
137 viewController.view.autoresizingMask = | |
138 UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; | |
139 viewController.view.frame = subview.bounds; | |
140 [subview addSubview:viewController.view]; | |
141 [viewController didMoveToParentViewController:self]; | |
122 } | 142 } |
123 | 143 |
124 - (UIViewController*)childViewControllerForStatusBarStyle { | 144 - (void)removeChildViewController:(UIViewController*)viewController { |
125 return self.topmostViewController; | 145 if (viewController.parentViewController != self) |
146 return; | |
147 [viewController willMoveToParentViewController:nil]; | |
148 [viewController.view removeFromSuperview]; | |
149 [viewController removeFromParentViewController]; | |
126 } | 150 } |
127 | 151 |
128 #pragma mark - MenuPresentationDelegate | 152 #pragma mark - MenuPresentationDelegate |
129 | 153 |
130 - (CGRect)frameForMenuPresentation:(UIPresentationController*)presentation { | 154 - (CGRect)frameForMenuPresentation:(UIPresentationController*)presentation { |
131 CGSize menuSize = presentation.presentedView.frame.size; | 155 CGSize menuSize = presentation.presentedView.frame.size; |
132 CGRect menuRect; | 156 CGRect menuRect; |
133 menuRect.size = menuSize; | 157 menuRect.size = menuSize; |
134 | 158 |
135 CGRect menuOriginRect = [self rectForZoomWithKey:@"" inView:self.view]; | 159 CGRect menuOriginRect = [self rectForZoomWithKey:@"" inView:self.view]; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
192 | 216 |
193 #pragma mark - NSObject method forwarding | 217 #pragma mark - NSObject method forwarding |
194 | 218 |
195 - (id)forwardingTargetForSelector:(SEL)aSelector { | 219 - (id)forwardingTargetForSelector:(SEL)aSelector { |
196 if (aSelector == self.actionToForward) { | 220 if (aSelector == self.actionToForward) { |
197 return self.forwardingTarget; | 221 return self.forwardingTarget; |
198 } | 222 } |
199 return nil; | 223 return nil; |
200 } | 224 } |
201 | 225 |
226 #pragma mark - TabStripActions | |
227 | |
228 - (void)toggleTabStrip:(id)sender { | |
229 self.tabStripHeightConstraint.constant = | |
230 self.tabStripHeightConstraint.constant > 0.0f ? 0.0f : kTabStripHeight; | |
231 } | |
232 | |
202 #pragma mark - Private methods | 233 #pragma mark - Private methods |
203 | 234 |
204 - (void)removeChildViewController:(UIViewController*)viewController { | 235 - (Constraints*)commonConstraints { |
edchin
2017/02/16 16:12:05
The benefit of DRY is lost to lack of full compreh
| |
205 if (viewController.parentViewController != self) | 236 return @[ |
206 return; | 237 [self.tabStripView.topAnchor |
207 [viewController willMoveToParentViewController:nil]; | 238 constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor], |
208 [viewController.view removeFromSuperview]; | 239 [self.tabStripView.leadingAnchor |
209 [viewController removeFromParentViewController]; | 240 constraintEqualToAnchor:self.view.leadingAnchor], |
241 [self.tabStripView.trailingAnchor | |
242 constraintEqualToAnchor:self.view.trailingAnchor], | |
243 self.tabStripHeightConstraint, | |
244 [self.toolbarView.leadingAnchor | |
245 constraintEqualToAnchor:self.view.leadingAnchor], | |
246 [self.toolbarView.trailingAnchor | |
247 constraintEqualToAnchor:self.view.trailingAnchor], | |
248 self.toolbarHeightConstraint, | |
249 [self.contentView.leadingAnchor | |
250 constraintEqualToAnchor:self.view.leadingAnchor], | |
251 [self.contentView.trailingAnchor | |
252 constraintEqualToAnchor:self.view.trailingAnchor], | |
253 ]; | |
210 } | 254 } |
211 | 255 |
212 - (void)didAddContentViewController { | 256 #pragma mark - Abstract methods to be overriden by subclass |
213 if (self.toolbarViewController) { | |
214 [self updateContentConstraintsWithToolbar]; | |
215 } else { | |
216 self.topmostViewController = self.contentViewController; | |
217 [self updateContentConstraintsWithoutToolbar]; | |
218 } | |
219 } | |
220 | 257 |
221 - (void)didAddToolbarViewController { | 258 - (Constraints*)layoutSpecificConstraints { |
222 [self updateToolbarConstraints]; | 259 [NSException |
223 // If there's already a content view controller, update the constraints for | 260 raise:NSInternalInconsistencyException |
edchin
2017/02/16 16:12:05
I'm not a fan of abstract base classes because the
marq (ping after 24h)
2017/02/17 12:16:58
You're correct in a strict sense, but UIKit includ
edchin
2017/02/17 19:48:09
Acknowledged.
| |
224 // that, too. | 261 format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]; |
225 if (self.contentViewController) { | 262 return nil; |
226 [self updateContentConstraintsWithToolbar]; | |
227 } | |
228 } | |
229 | |
230 - (void)updateContentConstraintsWithToolbar { | |
231 // Template method for subclasses to implement; | |
232 } | |
233 | |
234 - (void)updateToolbarConstraints { | |
235 // Template method for subclasses to implement; | |
236 } | |
237 | |
238 - (void)updateContentConstraintsWithoutToolbar { | |
239 UIView* contentView = self.contentViewController.view; | |
240 self.contentConstraintsWithoutToolbar = @[ | |
241 [contentView.topAnchor constraintEqualToAnchor:self.view.topAnchor], | |
242 [contentView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], | |
243 [contentView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], | |
244 [contentView.trailingAnchor | |
245 constraintEqualToAnchor:self.view.trailingAnchor], | |
246 ]; | |
247 } | 263 } |
248 | 264 |
249 @end | 265 @end |
250 | 266 |
251 @implementation TopToolbarTabViewController | 267 @implementation TopToolbarTabViewController |
252 | 268 |
253 - (void)didAddContentViewController { | 269 // Override with constraints that place the toolbar on top. |
254 [super didAddContentViewController]; | 270 - (Constraints*)layoutSpecificConstraints { |
255 if (!self.toolbarViewController) { | 271 return @[ |
256 self.topmostViewController = self.contentViewController; | 272 [self.toolbarView.topAnchor |
257 } | 273 constraintEqualToAnchor:self.tabStripView.bottomAnchor], |
258 } | 274 [self.contentView.topAnchor |
259 | 275 constraintEqualToAnchor:self.toolbarView.bottomAnchor], |
260 - (void)didAddToolbarViewController { | 276 [self.contentView.bottomAnchor |
261 [super didAddToolbarViewController]; | 277 constraintEqualToAnchor:self.bottomLayoutGuide.topAnchor], |
262 self.topmostViewController = self.toolbarViewController; | |
263 } | |
264 | |
265 - (void)updateContentConstraintsWithToolbar { | |
266 UIView* contentView = self.contentViewController.view; | |
267 self.contentConstraintsWithToolbar = @[ | |
268 [contentView.topAnchor | |
269 constraintEqualToAnchor:self.toolbarViewController.view.bottomAnchor], | |
270 [contentView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], | |
271 [contentView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], | |
272 [contentView.trailingAnchor | |
273 constraintEqualToAnchor:self.view.trailingAnchor], | |
274 ]; | 278 ]; |
275 } | 279 } |
276 | 280 |
277 - (void)updateToolbarConstraints { | |
278 // HACK: This background is added so the status bar portion of the view is not | |
279 // transparent. This needs to be implemented properly for the top toolbar | |
280 // case. | |
281 self.view.backgroundColor = [UIColor lightGrayColor]; | |
282 UIView* toolbarView = self.toolbarViewController.view; | |
283 self.toolbarConstraints = @[ | |
284 [toolbarView.topAnchor constraintEqualToAnchor:self.view.topAnchor | |
285 constant:20.0], | |
286 [toolbarView.heightAnchor constraintEqualToConstant:kToolbarHeight], | |
287 [toolbarView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], | |
288 [toolbarView.trailingAnchor | |
289 constraintEqualToAnchor:self.view.trailingAnchor], | |
290 ]; | |
291 } | |
292 | |
293 @end | 281 @end |
294 | 282 |
295 @implementation BottomToolbarTabViewController | 283 @implementation BottomToolbarTabViewController |
296 | 284 |
297 - (void)didAddContentViewController { | 285 // Override with constraints that place the toolbar on bottom. |
298 [super didAddContentViewController]; | 286 - (Constraints*)layoutSpecificConstraints { |
299 self.topmostViewController = self.contentViewController; | 287 return @[ |
300 } | 288 [self.contentView.topAnchor |
301 | 289 constraintEqualToAnchor:self.tabStripView.bottomAnchor], |
302 // Note that this class doesn't override -didAddToolbarViewController; in the | 290 [self.toolbarView.topAnchor |
303 // case where there is a toolbar view controller set but not a content view | 291 constraintEqualToAnchor:self.contentView.bottomAnchor], |
304 // controller, functionally there is no topmost view controller, so no | 292 [self.toolbarView.bottomAnchor |
305 // additional action needs to be taken. | 293 constraintEqualToAnchor:self.bottomLayoutGuide.topAnchor], |
306 | |
307 - (void)updateContentConstraintsWithToolbar { | |
308 UIView* contentView = self.contentViewController.view; | |
309 self.contentConstraintsWithToolbar = @[ | |
310 [contentView.topAnchor constraintEqualToAnchor:self.view.topAnchor], | |
311 [contentView.bottomAnchor | |
312 constraintEqualToAnchor:self.toolbarViewController.view.topAnchor], | |
313 [contentView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], | |
314 [contentView.trailingAnchor | |
315 constraintEqualToAnchor:self.view.trailingAnchor], | |
316 ]; | 294 ]; |
317 } | 295 } |
318 | 296 |
319 - (void)updateToolbarConstraints { | |
320 UIView* toolbarView = self.toolbarViewController.view; | |
321 self.toolbarConstraints = @[ | |
322 [toolbarView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], | |
323 [toolbarView.heightAnchor constraintEqualToConstant:kToolbarHeight], | |
324 [toolbarView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], | |
325 [toolbarView.trailingAnchor | |
326 constraintEqualToAnchor:self.view.trailingAnchor], | |
327 ]; | |
328 } | |
329 | |
330 @end | 297 @end |
OLD | NEW |