OLD | NEW |
(Empty) | |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "ios/chrome/browser/ui/ntp/new_tab_page_bar.h" |
| 6 |
| 7 #import <QuartzCore/QuartzCore.h> |
| 8 #include <cmath> |
| 9 |
| 10 #include "base/logging.h" |
| 11 #include "base/mac/objc_property_releaser.h" |
| 12 #include "base/mac/scoped_nsobject.h" |
| 13 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h" |
| 14 #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_button.h" |
| 15 #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h" |
| 16 #import "ios/chrome/browser/ui/rtl_geometry.h" |
| 17 #include "ios/chrome/browser/ui/ui_util.h" |
| 18 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
| 19 #import "ui/gfx/ios/NSString+CrStringDrawing.h" |
| 20 #include "ui/gfx/scoped_ui_graphics_push_context_ios.h" |
| 21 |
| 22 namespace { |
| 23 |
| 24 const CGFloat kBarHeight = 48.0f; |
| 25 |
| 26 const CGFloat kRegularLayoutButtonWidth = 168; |
| 27 |
| 28 const int kOverlayViewColor = 0x5A7EF5; |
| 29 const int kOverlayColorWidth = 98; |
| 30 const int kNumberOfTabsIncognito = 2; |
| 31 |
| 32 } // anonymous namespace |
| 33 |
| 34 @interface NewTabPageBar () { |
| 35 base::scoped_nsobject<UIImageView> shadow_; |
| 36 } |
| 37 |
| 38 @property(nonatomic, readwrite, retain) NSArray* buttons; |
| 39 @property(nonatomic, readwrite, retain) UIButton* popupButton; |
| 40 |
| 41 - (void)setup; |
| 42 - (void)calculateButtonWidth; |
| 43 - (void)setupButton:(UIButton*)button; |
| 44 - (BOOL)useIconsInButtons; |
| 45 - (BOOL)showOverlay; |
| 46 @end |
| 47 |
| 48 @implementation NewTabPageBar { |
| 49 // Tabbar buttons. |
| 50 NSArray* buttons_; // UIButton |
| 51 NSArray* items_; // NewTabPageBarItem |
| 52 // Which button is currently selected. |
| 53 NSUInteger selectedIndex_; |
| 54 // Popup button helper, for iPhone labels. |
| 55 UIButton* popupButton_; |
| 56 // Don't allow tabbar animations on startup, only after first tap. |
| 57 BOOL canAnimate_; |
| 58 id<NewTabPageBarDelegate> delegate_; // weak |
| 59 // Logo view, used to center the tab buttons. |
| 60 base::scoped_nsobject<UIImageView> logoView_; |
| 61 // Overlay view, used to highlight the selected button. |
| 62 base::scoped_nsobject<UIImageView> overlayView_; |
| 63 // Overlay view, used to highlight the selected button. |
| 64 base::scoped_nsobject<UIView> overlayColorView_; |
| 65 // Width of a button. |
| 66 CGFloat buttonWidth_; |
| 67 // Percentage overlay sits over tab bar buttons. |
| 68 CGFloat overlayPercentage_; |
| 69 |
| 70 base::mac::ObjCPropertyReleaser propertyReleaser_NewTabPageBar_; |
| 71 } |
| 72 |
| 73 @synthesize items = items_; |
| 74 @synthesize selectedIndex = selectedIndex_; |
| 75 @synthesize popupButton = popupButton_; |
| 76 @synthesize buttons = buttons_; |
| 77 @synthesize delegate = delegate_; |
| 78 @synthesize overlayPercentage = overlayPercentage_; |
| 79 |
| 80 - (id)initWithFrame:(CGRect)frame { |
| 81 self = [super initWithFrame:frame]; |
| 82 if (self) { |
| 83 [self setup]; |
| 84 } |
| 85 return self; |
| 86 } |
| 87 |
| 88 - (id)initWithCoder:(NSCoder*)aDecoder { |
| 89 self = [super initWithCoder:aDecoder]; |
| 90 if (self) { |
| 91 [self setup]; |
| 92 } |
| 93 return self; |
| 94 } |
| 95 |
| 96 - (void)setup { |
| 97 propertyReleaser_NewTabPageBar_.Init(self, [NewTabPageBar class]); |
| 98 self.selectedIndex = NSNotFound; |
| 99 canAnimate_ = NO; |
| 100 self.autoresizingMask = |
| 101 UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin; |
| 102 self.autoresizesSubviews = YES; |
| 103 self.backgroundColor = [UIColor clearColor]; |
| 104 |
| 105 if ([self showOverlay]) { |
| 106 overlayView_.reset( |
| 107 [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, buttonWidth_, 2)]); |
| 108 |
| 109 // Center |overlayColorView_| inside |overlayView_|. |
| 110 CGFloat colorX = AlignValueToPixel((buttonWidth_ - kOverlayColorWidth) / 2); |
| 111 overlayColorView_.reset([[UIView alloc] |
| 112 initWithFrame:CGRectMake(colorX, 0, kOverlayColorWidth, 2)]); |
| 113 [overlayColorView_ |
| 114 setBackgroundColor:UIColorFromRGB(kOverlayViewColor, 1.0)]; |
| 115 [overlayColorView_ layer].cornerRadius = 1.0; |
| 116 [overlayColorView_ |
| 117 setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | |
| 118 UIViewAutoresizingFlexibleRightMargin]; |
| 119 [overlayView_ addSubview:overlayColorView_]; |
| 120 [self addSubview:overlayView_]; |
| 121 } |
| 122 |
| 123 // Make the drop shadow. |
| 124 UIImage* shadowImage = [UIImage imageNamed:@"ntp_bottom_bar_shadow"]; |
| 125 shadow_.reset([[UIImageView alloc] initWithImage:shadowImage]); |
| 126 // Shadow is positioned directly above the new tab page bar. |
| 127 [shadow_ |
| 128 setFrame:CGRectMake(0, -shadowImage.size.height, self.bounds.size.width, |
| 129 shadowImage.size.height)]; |
| 130 [shadow_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; |
| 131 [self addSubview:shadow_]; |
| 132 |
| 133 self.contentMode = UIViewContentModeRedraw; |
| 134 } |
| 135 |
| 136 - (void)layoutSubviews { |
| 137 [super layoutSubviews]; |
| 138 |
| 139 // |buttonWidth_| changes with the screen orientation when the NTP button bar |
| 140 // is enabled. |
| 141 [self calculateButtonWidth]; |
| 142 |
| 143 CGFloat logoWidth = logoView_.get().image.size.width; |
| 144 CGFloat padding = [self useIconsInButtons] ? logoWidth : 0; |
| 145 CGFloat buttonPadding = floor((CGRectGetWidth(self.bounds) - padding - |
| 146 (buttonWidth_ * self.buttons.count) / 2) + |
| 147 padding); |
| 148 |
| 149 for (NSUInteger i = 0; i < self.buttons.count; ++i) { |
| 150 NewTabPageBarButton* button = [self.buttons objectAtIndex:i]; |
| 151 LayoutRect layout = LayoutRectMake( |
| 152 buttonPadding + (i * buttonWidth_), CGRectGetWidth(self.bounds), 0, |
| 153 buttonWidth_, CGRectGetHeight(self.bounds)); |
| 154 button.frame = LayoutRectGetRect(layout); |
| 155 [button |
| 156 setContentToDisplay:[self useIconsInButtons] |
| 157 ? new_tab_page_bar_button::ContentType::IMAGE |
| 158 : new_tab_page_bar_button::ContentType::TEXT]; |
| 159 } |
| 160 |
| 161 // Position overlay image over percentage of tab bar button(s). |
| 162 CGRect frame = [overlayView_ frame]; |
| 163 frame.origin.x = floor( |
| 164 buttonWidth_ * self.buttons.count * overlayPercentage_ + buttonPadding); |
| 165 frame.size.width = buttonWidth_; |
| 166 DCHECK(!std::isnan(frame.origin.x)); |
| 167 DCHECK(!std::isnan(frame.size.width)); |
| 168 [overlayView_ setFrame:frame]; |
| 169 } |
| 170 |
| 171 - (CGSize)sizeThatFits:(CGSize)size { |
| 172 return CGSizeMake(size.width, kBarHeight); |
| 173 } |
| 174 |
| 175 - (void)calculateButtonWidth { |
| 176 if ([self useIconsInButtons]) { |
| 177 if ([items_ count] > 0) { |
| 178 buttonWidth_ = self.bounds.size.width / [items_ count]; |
| 179 } else { |
| 180 // In incognito on phones, there are no items shown. |
| 181 buttonWidth_ = 0; |
| 182 } |
| 183 return; |
| 184 } |
| 185 |
| 186 buttonWidth_ = kRegularLayoutButtonWidth; |
| 187 } |
| 188 |
| 189 // When setting a new set of items on the tab bar, the buttons need to be |
| 190 // regenerated and the old buttons need to be removed. |
| 191 - (void)setItems:(NSArray*)newItems { |
| 192 if (newItems == items_) |
| 193 return; |
| 194 |
| 195 [items_ autorelease]; |
| 196 items_ = [newItems retain]; |
| 197 // Remove all the existing buttons from the view. |
| 198 for (UIButton* button in self.buttons) { |
| 199 [button removeFromSuperview]; |
| 200 } |
| 201 |
| 202 // Create a set of new buttons. |
| 203 [self calculateButtonWidth]; |
| 204 if (newItems.count) { |
| 205 NSMutableArray* newButtons = [NSMutableArray array]; |
| 206 for (NSUInteger i = 0; i < newItems.count; ++i) { |
| 207 NewTabPageBarItem* item = [newItems objectAtIndex:i]; |
| 208 NewTabPageBarButton* button = [NewTabPageBarButton buttonWithItem:item]; |
| 209 button.frame = CGRectIntegral(CGRectMake( |
| 210 i * buttonWidth_, 0, buttonWidth_, self.bounds.size.height)); |
| 211 [self setupButton:button]; |
| 212 [self addSubview:button]; |
| 213 [newButtons addObject:button]; |
| 214 } |
| 215 self.buttons = newButtons; |
| 216 } else { |
| 217 self.buttons = nil; |
| 218 } |
| 219 [self setNeedsLayout]; |
| 220 } |
| 221 |
| 222 - (void)setOverlayPercentage:(CGFloat)overlayPercentage { |
| 223 DCHECK(!std::isnan(overlayPercentage)); |
| 224 overlayPercentage_ = overlayPercentage; |
| 225 [self setNeedsLayout]; |
| 226 } |
| 227 |
| 228 - (void)setupButton:(UIButton*)button { |
| 229 // Old NTP tab bar buttons have a non-standard control event for firing |
| 230 // actions. Because they are tied to a scrollView that reacts immediately, |
| 231 // and on phone there is a tooltip that fires on touchdown that needs to |
| 232 // display while on the new tab, the control event for -buttonDidTap is touch |
| 233 // down. On phone with dialogs enabled, treat the NTP buttons as normal |
| 234 // buttons, where the standard is to fire an action on touch up inside. |
| 235 if ([self showOverlay]) { |
| 236 [button addTarget:self |
| 237 action:@selector(buttonDidTap:) |
| 238 forControlEvents:UIControlEventTouchDown]; |
| 239 } else { |
| 240 [button addTarget:self |
| 241 action:@selector(buttonDidTap:) |
| 242 forControlEvents:UIControlEventTouchUpInside]; |
| 243 } |
| 244 } |
| 245 |
| 246 - (void)setSelectedIndex:(NSUInteger)newIndex { |
| 247 // When not showing the overlay, the Bookmarks and Recent Tabs are displayed |
| 248 // in modal view controllers, so the tab bar buttons should not be selected. |
| 249 if (![self showOverlay]) |
| 250 return; |
| 251 if (newIndex != self.selectedIndex) { |
| 252 if (newIndex < self.items.count) { |
| 253 for (NSUInteger i = 0; i < self.buttons.count; ++i) { |
| 254 UIButton* button = [self.buttons objectAtIndex:i]; |
| 255 button.selected = (i == newIndex); |
| 256 } |
| 257 } |
| 258 selectedIndex_ = newIndex; |
| 259 } |
| 260 } |
| 261 |
| 262 - (void)buttonDidTap:(UIButton*)button { |
| 263 canAnimate_ = YES; |
| 264 NSUInteger buttonIndex = [self.buttons indexOfObject:button]; |
| 265 if (buttonIndex != NSNotFound) { |
| 266 self.selectedIndex = buttonIndex; |
| 267 [delegate_ newTabBarItemDidChange:[self.items objectAtIndex:buttonIndex] |
| 268 changePanel:YES]; |
| 269 } |
| 270 } |
| 271 |
| 272 - (void)setShadowAlpha:(CGFloat)alpha { |
| 273 CGFloat currentAlpha = [shadow_ alpha]; |
| 274 CGFloat diff = std::abs(alpha - currentAlpha); |
| 275 if (diff >= 1) { |
| 276 [UIView animateWithDuration:0.3 |
| 277 animations:^{ |
| 278 [shadow_ setAlpha:alpha]; |
| 279 }]; |
| 280 } else { |
| 281 [shadow_ setAlpha:alpha]; |
| 282 } |
| 283 } |
| 284 |
| 285 - (void)updateColorsForScrollView:(UIScrollView*)scrollView { |
| 286 if (![self showOverlay]) { |
| 287 return; |
| 288 } |
| 289 |
| 290 UIColor* backgroundViewColorBookmarks = [UIColor whiteColor]; |
| 291 CGFloat viewWidth = self.bounds.size.width; |
| 292 CGFloat progress = LeadingContentOffsetForScrollView(scrollView) / viewWidth; |
| 293 progress = fminf(progress, 1.0f); |
| 294 progress = fmaxf(progress, 0.0f); |
| 295 |
| 296 if ([self.items count] == kNumberOfTabsIncognito) { |
| 297 UIColor* overlayViewColor = UIColorFromRGB(kOverlayViewColor, 1.0); |
| 298 UIColor* overlayViewColorIncognito = [UIColor whiteColor]; |
| 299 UIColor* updatedOverlayColor = InterpolateFromColorToColor( |
| 300 overlayViewColor, overlayViewColorIncognito, progress); |
| 301 [overlayColorView_ setBackgroundColor:updatedOverlayColor]; |
| 302 |
| 303 UIColor* backgroundViewColorIncognito = |
| 304 [UIColor colorWithWhite:34 / 255.0 alpha:1.0]; |
| 305 UIColor* backgroundColor = InterpolateFromColorToColor( |
| 306 backgroundViewColorBookmarks, backgroundViewColorIncognito, progress); |
| 307 self.backgroundColor = backgroundColor; |
| 308 scrollView.backgroundColor = backgroundColor; |
| 309 |
| 310 for (NewTabPageBarButton* button in self.buttons) { |
| 311 [button useIncognitoColorScheme:progress]; |
| 312 } |
| 313 } else { |
| 314 UIColor* backgroundColor = backgroundViewColorBookmarks; |
| 315 self.backgroundColor = backgroundViewColorBookmarks; |
| 316 scrollView.backgroundColor = backgroundColor; |
| 317 } |
| 318 } |
| 319 |
| 320 - (BOOL)useIconsInButtons { |
| 321 return !IsIPadIdiom() || IsCompactTablet(); |
| 322 } |
| 323 |
| 324 - (BOOL)showOverlay { |
| 325 // The bar buttons launch modal dialogs on tap on iPhone. Don't show overlay |
| 326 // in this case. |
| 327 return IsIPadIdiom(); |
| 328 } |
| 329 |
| 330 @end |
OLD | NEW |