apps_grid_row_change_animator.cc 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright 2022 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. #include "ash/app_list/apps_grid_row_change_animator.h"
  5. #include <utility>
  6. #include "ash/app_list/views/apps_grid_view.h"
  7. #include "base/auto_reset.h"
  8. #include "base/time/time.h"
  9. #include "ui/compositor/layer.h"
  10. #include "ui/gfx/geometry/transform_util.h"
  11. #include "ui/views/animation/bounds_animator.h"
  12. namespace ash {
  13. AppsGridRowChangeAnimator::AppsGridRowChangeAnimator(
  14. AppsGridView* apps_grid_view)
  15. : apps_grid_view_(apps_grid_view) {}
  16. AppsGridRowChangeAnimator::~AppsGridRowChangeAnimator() = default;
  17. void AppsGridRowChangeAnimator::AnimateBetweenRows(AppListItemView* view,
  18. const gfx::Rect& current,
  19. const gfx::Rect& target) {
  20. base::AutoReset<bool> auto_reset(&setting_up_animation_, true);
  21. // The direction used to calculate the offset for animating the item view into
  22. // and the layer copy out of the grid.
  23. const int dir = current.y() < target.y() ? 1 : -1;
  24. int offset =
  25. apps_grid_view_->GetTotalTileSize(apps_grid_view_->GetSelectedPage())
  26. .width();
  27. // The transform for moving the layer copy out and off screen.
  28. gfx::Transform layer_copy_transform;
  29. // The bounds where `view` will begin animating to `target`.
  30. gfx::RectF target_in;
  31. // The layer copy of the view which is animating between rows.
  32. std::unique_ptr<ui::Layer> row_change_layer;
  33. if (row_change_layers_.count(view)) {
  34. row_change_layer = std::move(row_change_layers_[view]);
  35. row_change_layers_.erase(view);
  36. // Reverse existing row change animation, by swapping the positions of the
  37. // mid-animation layer copy and `view`. Then animate each to the correct
  38. // target.
  39. // Calculate 'target_in' so that 'view' can start its animation in the place
  40. // of the layer copy.
  41. gfx::RectF layer_copy_bounds = gfx::RectF(row_change_layer->bounds());
  42. row_change_layer->transform().TransformRect(&layer_copy_bounds);
  43. target_in = gfx::RectF(apps_grid_view_->items_container_->GetMirroredRect(
  44. gfx::ToRoundedRect(layer_copy_bounds)));
  45. // Calculate the current bounds of `view` including its layer transform.
  46. gfx::RectF current_bounds_in_animation =
  47. gfx::RectF(view->GetMirroredBounds());
  48. view->layer()->transform().TransformRect(&current_bounds_in_animation);
  49. // Set the bounds of the layer copy to the current bounds of'view'.
  50. row_change_layer->SetBounds(
  51. gfx::ToRoundedRect(current_bounds_in_animation));
  52. row_change_layer->SetTransform(gfx::Transform());
  53. // Calculate where offscreen the layer copy will animate to.
  54. gfx::Rect current_out =
  55. apps_grid_view_->bounds_animator_->GetTargetBounds(view);
  56. current_out.Offset(dir * offset, 0);
  57. // Calculate the transform to move the layer copy off screen. Do not mirror
  58. // `current_bounds_in_animation` because it has already been mirrored.
  59. layer_copy_transform = gfx::TransformBetweenRects(
  60. gfx::RectF(current_bounds_in_animation),
  61. gfx::RectF(
  62. apps_grid_view_->items_container_->GetMirroredRect(current_out)));
  63. // Swap the opacity of the layer copy and the item view.
  64. const float layer_copy_opacity = row_change_layer->opacity();
  65. row_change_layer->SetOpacity(view->layer()->opacity());
  66. view->layer()->SetOpacity(layer_copy_opacity);
  67. } else {
  68. // Create the row change animation for this view. `view` will animate from
  69. // offscreen into the 'target' location, while a layer copy of 'view' will
  70. // animate from the original `view` bounds to offscreen.
  71. view->EnsureLayer();
  72. row_change_layer = view->RecreateLayer();
  73. // Calculate where offscreen the layer copy will animate to.
  74. gfx::Rect current_out = current;
  75. current_out.Offset(dir * offset, 0);
  76. // Calculate the transform to move the layer copy off screen.
  77. layer_copy_transform = gfx::TransformBetweenRects(
  78. gfx::RectF(apps_grid_view_->items_container_->GetMirroredRect(current)),
  79. gfx::RectF(
  80. apps_grid_view_->items_container_->GetMirroredRect(current_out)));
  81. view->layer()->SetOpacity(0.0f);
  82. // Calculate offscreen position to begin animating `view` from.
  83. target_in = gfx::RectF(target);
  84. target_in.Offset(-dir * offset, 0);
  85. }
  86. // Fade out and animate out the copied layer. Fade in the real item view.
  87. views::AnimationBuilder()
  88. .SetPreemptionStrategy(
  89. ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
  90. .Once()
  91. .SetDuration(base::Milliseconds(300))
  92. .SetTransform(row_change_layer.get(), layer_copy_transform,
  93. gfx::Tween::ACCEL_40_DECEL_100_3)
  94. .SetOpacity(row_change_layer.get(), 0.0f,
  95. gfx::Tween::ACCEL_40_DECEL_100_3)
  96. .SetOpacity(view->layer(), 1.0f, gfx::Tween::ACCEL_40_DECEL_100_3);
  97. // Stop animating to reset the bounds and transform of `view` before starting
  98. // the next animation.
  99. apps_grid_view_->bounds_animator_->StopAnimatingView(view);
  100. // Bounds animate the real item view to the target position.
  101. view->SetBoundsRect(gfx::ToRoundedRect(target_in));
  102. apps_grid_view_->bounds_animator_->AnimateViewTo(view, target);
  103. row_change_layers_[view] = std::move(row_change_layer);
  104. }
  105. void AppsGridRowChangeAnimator::OnBoundsAnimatorDone() {
  106. if (setting_up_animation_)
  107. return;
  108. // Erase row change layers for any item views which are not currently
  109. // animating.
  110. for (auto it = row_change_layers_.begin(); it != row_change_layers_.end();) {
  111. if (!apps_grid_view_->bounds_animator_->IsAnimating(it->first))
  112. it = row_change_layers_.erase(it);
  113. else
  114. it++;
  115. }
  116. }
  117. void AppsGridRowChangeAnimator::CancelAnimation(views::View* view) {
  118. row_change_layers_.erase(view);
  119. }
  120. bool AppsGridRowChangeAnimator::IsAnimating() const {
  121. return !row_change_layers_.empty() || setting_up_animation_;
  122. }
  123. } // namespace ash