Skip to content

Commit

Permalink
[Tab Scrolling] Animate the active tab into view.
Browse files Browse the repository at this point in the history
This groups the scroll animation with the same container used by tabstrip
to animate tabs.

The current animation time for scrolling is kept the same as tabs.

Bug: 1174227
Change-Id: I33ad309350a74b6645d880bb3ac2652be510861a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2705979
Commit-Queue: Charlene Yan <cyan@chromium.org>
Reviewed-by: Taylor Bergquist <tbergquist@chromium.org>
Cr-Commit-Position: refs/heads/master@{#858385}
  • Loading branch information
Charlene Yan authored and Chromium LUCI CQ committed Feb 27, 2021
1 parent c58beb8 commit 6d12096
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 8 deletions.
72 changes: 64 additions & 8 deletions chrome/browser/ui/views/tabs/tab_strip.cc
Expand Up @@ -32,6 +32,7 @@
#include "base/scoped_observation.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
Expand Down Expand Up @@ -248,6 +249,48 @@ int GetStackableTabWidth() {
(ui::TouchUiController::Get()->touch_ui() ? 136 : 102);
}

// Helper class that manages the tab scrolling animation.
class TabScrollingAnimation : public gfx::LinearAnimation,
public gfx::AnimationDelegate {
public:
explicit TabScrollingAnimation(
TabStrip* tab_strip,
gfx::AnimationContainer* bounds_animator_container,
base::TimeDelta duration,
const gfx::Rect start_visible_rect,
const gfx::Rect end_visible_rect)
: gfx::LinearAnimation(duration,
gfx::LinearAnimation::kDefaultFrameRate,
this),
tab_strip_(tab_strip),
start_visible_rect_(start_visible_rect),
end_visible_rect_(end_visible_rect) {
SetContainer(bounds_animator_container);
}
TabScrollingAnimation(const TabScrollingAnimation&) = delete;
TabScrollingAnimation& operator=(const TabScrollingAnimation&) = delete;
~TabScrollingAnimation() override = default;

void AnimateToState(double state) override {
gfx::Rect intermediary_rect(
start_visible_rect_.x() +
(end_visible_rect_.x() - start_visible_rect_.x()) * state,
start_visible_rect_.y(), start_visible_rect_.width(),
start_visible_rect_.height());

tab_strip_->ScrollRectToVisible(intermediary_rect);
}

void AnimationEnded(const gfx::Animation* animation) override {
tab_strip_->ScrollRectToVisible(end_visible_rect_);
}

private:
TabStrip* const tab_strip_;
const gfx::Rect start_visible_rect_;
const gfx::Rect end_visible_rect_;
};

} // namespace

///////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -1349,26 +1392,37 @@ void TabStrip::ScrollTabToVisible(int model_index) {
return;
}

if (tab_scrolling_animation_)
tab_scrolling_animation_->Stop();

gfx::Rect visible_content_rect = scroll_container->GetVisibleRect();
Tab* active_tab = tab_at(model_index);
gfx::Rect active_tab_ideal_bounds = ideal_bounds(model_index);

if ((active_tab->x() >= visible_content_rect.x()) &&
(active_tab->bounds().right() <= visible_content_rect.right())) {
if ((active_tab_ideal_bounds.x() >= visible_content_rect.x()) &&
(active_tab_ideal_bounds.right() <= visible_content_rect.right())) {
return;
}

bool scroll_left = active_tab->x() < visible_content_rect.x();
bool scroll_left = active_tab_ideal_bounds.x() < visible_content_rect.x();
if (scroll_left) {
gfx::Rect new_visible(active_tab->x(), visible_content_rect.y(),
gfx::Rect new_visible(active_tab_ideal_bounds.x(), visible_content_rect.y(),
visible_content_rect.width(),
visible_content_rect.height());
ScrollRectToVisible(new_visible);
tab_scrolling_animation_ = std::make_unique<TabScrollingAnimation>(
this, bounds_animator_.container(),
bounds_animator_.GetAnimationDuration(), visible_content_rect,
new_visible);
tab_scrolling_animation_->Start();
} else {
gfx::Rect new_visible(
active_tab->bounds().right() - visible_content_rect.width(),
active_tab_ideal_bounds.right() - visible_content_rect.width(),
visible_content_rect.y(), visible_content_rect.width(),
visible_content_rect.height());
ScrollRectToVisible(new_visible);
tab_scrolling_animation_ = std::make_unique<TabScrollingAnimation>(
this, bounds_animator_.container(),
bounds_animator_.GetAnimationDuration(), visible_content_rect,
new_visible);
tab_scrolling_animation_->Start();
}
}

Expand Down Expand Up @@ -2758,6 +2812,8 @@ void TabStrip::CompleteAnimationAndLayout() {
last_layout_size_ = size();

bounds_animator_.Cancel();
if (tab_scrolling_animation_)
tab_scrolling_animation_->SetCurrentValue(1);

SwapLayoutIfNecessary();
if (touch_layout_)
Expand Down
3 changes: 3 additions & 0 deletions chrome/browser/ui/views/tabs/tab_strip.h
Expand Up @@ -666,6 +666,9 @@ class TabStrip : public views::View,
// Responsible for animating tabs in response to model changes.
views::BoundsAnimator bounds_animator_{this};

// Responsible for animating the scroll of the tab strip.
std::unique_ptr<gfx::LinearAnimation> tab_scrolling_animation_;

// If this value is defined, it is used as the width to lay out tabs
// (instead of GetAvailableWidthForTabStrip()). It is defined when closing
// tabs with the mouse, and is used to control which tab will end up under the
Expand Down

0 comments on commit 6d12096

Please sign in to comment.