| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/chrome/browser/ui/ntp/new_tab_page_view.h" |
| |
| #include "base/logging.h" |
| #import "ios/chrome/browser/ui/ntp/new_tab_page_bar.h" |
| #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h" |
| #import "ios/chrome/browser/ui/rtl_geometry.h" |
| #include "ios/chrome/browser/ui/ui_util.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| @implementation NewTabPageView |
| |
| @synthesize scrollView = scrollView_; |
| @synthesize tabBar = tabBar_; |
| |
| - (instancetype)initWithFrame:(CGRect)frame |
| andScrollView:(UIScrollView*)scrollView |
| andTabBar:(NewTabPageBar*)tabBar { |
| self = [super initWithFrame:frame]; |
| if (self) { |
| [self addSubview:scrollView]; |
| [self addSubview:tabBar]; |
| scrollView_ = scrollView; |
| tabBar_ = tabBar; |
| } |
| return self; |
| } |
| |
| - (instancetype)initWithFrame:(CGRect)frame { |
| NOTREACHED(); |
| return nil; |
| } |
| |
| - (instancetype)initWithCoder:(NSCoder*)aDecoder { |
| NOTREACHED(); |
| return nil; |
| } |
| |
| - (void)setFrame:(CGRect)frame { |
| // When transitioning the iPhone xib to an iPad idiom, the setFrame call below |
| // can sometimes fire a scrollViewDidScroll event which changes the |
| // selectedIndex underneath us. Save the selected index and remove the |
| // delegate so scrollViewDidScroll isn't called. Then fix the scrollView |
| // offset after updating the frame. |
| NSUInteger selectedIndex = self.tabBar.selectedIndex; |
| id<UIScrollViewDelegate> delegate = self.scrollView.delegate; |
| self.scrollView.delegate = nil; |
| [super setFrame:frame]; |
| self.scrollView.delegate = delegate; |
| |
| // Set the scrollView content size. |
| [self updateScrollViewContentSize]; |
| |
| // Set the frame of the laid out NTP panels on iPad. |
| if (IsIPadIdiom()) { |
| NSUInteger index = 0; |
| CGFloat selectedItemXOffset = 0; |
| for (NewTabPageBarItem* item in self.tabBar.items) { |
| item.view.frame = [self panelFrameForItemAtIndex:index]; |
| if (index == selectedIndex) |
| selectedItemXOffset = CGRectGetMinX(item.view.frame); |
| index++; |
| } |
| |
| // Ensure the selected NTP panel is lined up correctly when the frame |
| // changes. |
| CGPoint point = CGPointMake(selectedItemXOffset, 0); |
| [self.scrollView setContentOffset:point animated:NO]; |
| } |
| |
| // This should never be needed in autolayout. |
| if (self.translatesAutoresizingMaskIntoConstraints) { |
| // Trigger a layout. The |-layoutIfNeeded| call is required because |
| // sometimes |-layoutSubviews| is not successfully triggered when |
| // |-setNeedsLayout| is called after frame changes due to autoresizing |
| // masks. |
| [self setNeedsLayout]; |
| [self layoutIfNeeded]; |
| } |
| } |
| |
| - (void)layoutSubviews { |
| [super layoutSubviews]; |
| |
| self.tabBar.hidden = !self.tabBar.items.count; |
| if (self.tabBar.hidden) { |
| self.scrollView.frame = self.bounds; |
| } else { |
| CGSize barSize = [self.tabBar sizeThatFits:self.bounds.size]; |
| self.tabBar.frame = CGRectMake(CGRectGetMinX(self.bounds), |
| CGRectGetMaxY(self.bounds) - barSize.height, |
| barSize.width, barSize.height); |
| self.scrollView.frame = CGRectMake( |
| CGRectGetMinX(self.bounds), CGRectGetMinY(self.bounds), |
| CGRectGetWidth(self.bounds), CGRectGetMinY(self.tabBar.frame)); |
| } |
| |
| // When using a new_tab_page_view in autolayout -setFrame is never called, |
| // which means all the logic to keep the selected scroll index set is never |
| // called. Rather than refactor away all of this to support ios/clean, just |
| // make sure -setFrame is called when loaded in autolayout. |
| if (!self.translatesAutoresizingMaskIntoConstraints) { |
| [self setFrame:self.frame]; |
| } |
| } |
| |
| - (void)updateScrollViewContentSize { |
| CGSize contentSize = self.scrollView.bounds.size; |
| // On iPhone, NTP doesn't scroll horizontally, as alternate panels are shown |
| // modally. On iPad, panels are laid out side by side in the scroll view. |
| if (IsIPadIdiom()) { |
| contentSize.width *= self.tabBar.items.count; |
| } |
| self.scrollView.contentSize = contentSize; |
| } |
| |
| - (CGRect)panelFrameForItemAtIndex:(NSUInteger)index { |
| CGRect contentBounds = CGRectMake(0, 0, self.scrollView.contentSize.width, |
| self.scrollView.contentSize.height); |
| LayoutRect layout = |
| LayoutRectForRectInBoundingRect(self.scrollView.bounds, contentBounds); |
| layout.position.leading = layout.size.width * index; |
| return LayoutRectGetRect(layout); |
| } |
| |
| @end |