scroll_view_gradient_helper.cc 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // Copyright 2021 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/controls/scroll_view_gradient_helper.h"
  5. #include <memory>
  6. #include "ash/controls/gradient_layer_delegate.h"
  7. #include "base/bind.h"
  8. #include "base/check.h"
  9. #include "base/check_op.h"
  10. #include "base/logging.h"
  11. #include "ui/compositor/layer.h"
  12. #include "ui/gfx/geometry/rect.h"
  13. namespace ash {
  14. ScrollViewGradientHelper::ScrollViewGradientHelper(
  15. views::ScrollView* scroll_view,
  16. int gradient_height)
  17. : scroll_view_(scroll_view), gradient_height_(gradient_height) {
  18. DCHECK(scroll_view_);
  19. DCHECK(scroll_view_->layer());
  20. on_contents_scrolled_subscription_ =
  21. scroll_view_->AddContentsScrolledCallback(
  22. base::BindRepeating(&ScrollViewGradientHelper::UpdateGradientZone,
  23. base::Unretained(this)));
  24. on_contents_scroll_ended_subscription_ =
  25. scroll_view_->AddContentsScrollEndedCallback(
  26. base::BindRepeating(&ScrollViewGradientHelper::UpdateGradientZone,
  27. base::Unretained(this)));
  28. scroll_view_->SetPreferredViewportMargins(
  29. gfx::Insets::VH(gradient_height_, 0));
  30. }
  31. ScrollViewGradientHelper::~ScrollViewGradientHelper() {
  32. RemoveMaskLayer();
  33. scroll_view_->SetPreferredViewportMargins(gfx::Insets());
  34. }
  35. void ScrollViewGradientHelper::UpdateGradientZone() {
  36. DCHECK(scroll_view_->contents());
  37. const gfx::Rect visible_rect = scroll_view_->GetVisibleRect();
  38. // Show the top gradient if the scroll view is not scrolled to the top.
  39. const bool show_top_gradient = visible_rect.y() > 0;
  40. // Show the bottom gradient if the scroll view is not scrolled to the bottom.
  41. const bool show_bottom_gradient =
  42. visible_rect.bottom() < scroll_view_->contents()->bounds().bottom();
  43. const gfx::Rect scroll_view_bounds = scroll_view_->bounds();
  44. gfx::Rect top_gradient_bounds;
  45. if (show_top_gradient) {
  46. top_gradient_bounds =
  47. gfx::Rect(0, 0, scroll_view_bounds.width(), gradient_height_);
  48. }
  49. gfx::Rect bottom_gradient_bounds;
  50. if (show_bottom_gradient) {
  51. bottom_gradient_bounds =
  52. gfx::Rect(0, scroll_view_bounds.height() - gradient_height_,
  53. scroll_view_bounds.width(), gradient_height_);
  54. }
  55. // If no gradient is needed, remove the mask layer.
  56. if (top_gradient_bounds.IsEmpty() && bottom_gradient_bounds.IsEmpty()) {
  57. RemoveMaskLayer();
  58. return;
  59. }
  60. // If a gradient is needed, lazily create the GradientLayerDelegate.
  61. if (!gradient_layer_) {
  62. DVLOG(1) << "Adding gradient mask layer";
  63. // Animate showing the gradient to avoid a visual "pop" at the end of the
  64. // clamshell launcher open animation.
  65. gradient_layer_ =
  66. std::make_unique<GradientLayerDelegate>(/*animate_in=*/true);
  67. scroll_view_->layer()->SetMaskLayer(gradient_layer_->layer());
  68. }
  69. // If bounds didn't change, there's nothing to update.
  70. if (top_gradient_bounds == gradient_layer_->start_fade_zone_bounds() &&
  71. bottom_gradient_bounds == gradient_layer_->end_fade_zone_bounds()) {
  72. return;
  73. }
  74. // Update the fade in / fade out zones.
  75. gradient_layer_->set_start_fade_zone(
  76. {top_gradient_bounds, /*fade_in=*/true, /*is_horizontal=*/false});
  77. gradient_layer_->set_end_fade_zone(
  78. {bottom_gradient_bounds, /*fade_in=*/false, /*is_horizontal=*/false});
  79. gradient_layer_->layer()->SetBounds(scroll_view_->layer()->bounds());
  80. scroll_view_->SchedulePaint();
  81. }
  82. void ScrollViewGradientHelper::RemoveMaskLayer() {
  83. if (!gradient_layer_)
  84. return;
  85. DVLOG(1) << "Removing gradient mask layer";
  86. scroll_view_->layer()->SetMaskLayer(nullptr);
  87. gradient_layer_.reset();
  88. }
  89. } // namespace ash