Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(292)

Unified Diff: ash/common/system/tray/tray_details_view.cc

Issue 2453133002: [ash-md] Makes Wi-Fi header row sticky when network list is scrolled (Closed)
Patch Set: [ash-md] Makes Wi-Fi header row sticky when network list is scrolled (nits) Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ash/common/system/tray/tray_constants.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ash/common/system/tray/tray_details_view.cc
diff --git a/ash/common/system/tray/tray_details_view.cc b/ash/common/system/tray/tray_details_view.cc
index 70ff14fd6b4feb2838251819af30b34515ef2cf2..08e686ba57abe5762741928bbcdca2b1806e22b6 100644
--- a/ash/common/system/tray/tray_details_view.cc
+++ b/ash/common/system/tray/tray_details_view.cc
@@ -16,10 +16,160 @@
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/separator.h"
#include "ui/views/layout/box_layout.h"
+#include "ui/views/view_targeter.h"
+#include "ui/views/view_targeter_delegate.h"
namespace ash {
namespace {
+const int kHeaderRowSeparatorThickness = 1;
+const SkColor kHeaderRowSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F);
+
+// A view that is used as ScrollView contents. It supports designating some of
+// the children as sticky header rows. The sticky header rows are not scrolled
+// above the top of the visible viewport until the next one "pushes" it up and
+// are painted above other children. To indicate that a child is a sticky header
+// row use set_id(kHeaderRowId).
+class ScrollContentsView : public views::View,
+ public views::ViewTargeterDelegate {
+ public:
+ ScrollContentsView() {
+ SetEventTargeter(base::MakeUnique<views::ViewTargeter>(this));
+ SetLayoutManager(
+ new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
+ }
+ ~ScrollContentsView() override {}
+
+ protected:
+ // views::View:
+ void OnBoundsChanged(const gfx::Rect& previous_bounds) override {
+ PositionHeaderRows();
+ }
+
+ void PaintChildren(const ui::PaintContext& context) override {
+ for (int i = 0; i < child_count(); ++i) {
+ if (child_at(i)->id() != kHeaderRowId && !child_at(i)->layer())
+ child_at(i)->Paint(context);
+ }
+ // Paint header rows above other children in Z-order.
+ for (auto& header : headers_) {
+ if (!header.view()->layer())
+ header.view()->Paint(context);
+ }
+ }
+
+ void Layout() override {
+ views::View::Layout();
+ headers_.clear();
+ for (int i = 0; i < child_count(); ++i) {
+ views::View* view = child_at(i);
+ if (view->id() == kHeaderRowId)
+ headers_.push_back(Header(view));
+ }
+ PositionHeaderRows();
+ }
+
+ void ViewHierarchyChanged(
+ const ViewHierarchyChangedDetails& details) override {
+ if (!details.is_add && details.parent == this) {
+ headers_.erase(std::remove_if(headers_.begin(), headers_.end(),
+ [details](const Header& header) {
+ return header.view() == details.child;
+ }),
+ headers_.end());
sadrul 2016/11/04 15:03:03 There should only be one header that matches the c
varkha 2016/11/04 18:18:49 Done.
varkha 2016/11/07 03:27:45 Looked into this some more. While you are right th
+ }
+ }
+
+ View* TargetForRect(View* root, const gfx::Rect& rect) override {
sadrul 2016/11/04 15:03:03 // views::ViewTargeterDelegate:
varkha 2016/11/04 18:18:49 Done.
+ // Give header rows first dibs on events.
+ for (auto& header : headers_) {
+ views::View* view = header.view();
+ gfx::Rect local_to_header = rect;
+ local_to_header.Offset(-view->x(), -view->y());
+ if (ViewTargeterDelegate::DoesIntersectRect(view, local_to_header))
+ return ViewTargeterDelegate::TargetForRect(view, local_to_header);
+ }
+ return ViewTargeterDelegate::TargetForRect(root, rect);
+ }
+
+ private:
+ // A structure that keeps the original offset of each header between the
+ // calls to Layout() to allow keeping track of which view should be sticky.
+ class Header {
+ public:
+ Header(views::View* header)
sadrul 2016/11/04 15:03:03 explicit
varkha 2016/11/04 18:18:49 Done.
+ : view_(header), offset_(header->y()), sticky_(true) {
+ DecorateAsSticky(false);
+ }
+
+ // Sets decorations on a header row to indicate whether it is |sticky|.
+ void DecorateAsSticky(bool sticky) {
+ if (sticky_ == sticky)
+ return;
+ sticky_ = sticky;
+ if (sticky) {
+ view_->SetBorder(views::Border::CreateSolidSidedBorder(
+ 0, 0, kHeaderRowSeparatorThickness, 0, kHeaderRowSeparatorColor));
+ } else {
+ view_->SetBorder(views::Border::CreateSolidSidedBorder(
+ kHeaderRowSeparatorThickness, 0, 0, 0, kHeaderRowSeparatorColor));
+ }
+ }
+
+ const views::View* view() const { return view_; }
+ views::View* view() {
+ return const_cast<views::View*>(const_cast<const Header*>(this)->view());
Evan Stade 2016/11/04 15:53:46 p.s. this seems crazily verbose instead of just 'r
varkha 2016/11/04 18:18:49 Done.
+ }
+ int offset() const { return offset_; }
+
+ private:
+ // A header View that can be decorated as sticky.
+ views::View* view_;
+
+ // Offset from the top of ScrollContentsView to |view|'s original vertical
+ // position.
+ int offset_;
+
+ // True if the header is decorated as sticky with a shadow below.
+ bool sticky_;
sadrul 2016/11/04 15:03:03 DISALLOW_COPY_AND_ASSIGN
varkha 2016/11/04 18:18:49 This structure is used in a value array so I think
Evan Stade 2016/11/04 19:18:45 So use emplace_back instead of push_back?
varkha 2016/11/07 03:27:45 I will use emplace_back() but that still relies on
+ };
+
+ // Adjusts y-position of header rows allowing one or two rows to stick to the
+ // top of the visible viewport.
+ void PositionHeaderRows() {
+ const int scroll_offset = -y();
+ auto previous_header = headers_.rend();
+ for (auto header = headers_.rbegin(); header != headers_.rend(); ++header) {
sadrul 2016/11/04 15:03:03 for (auto& header : base::Reversed(headers_)) {
varkha 2016/11/04 18:18:49 Done.
+ if (header->offset() >= scroll_offset) {
+ header->DecorateAsSticky(false);
+ previous_header = header;
+ continue;
+ }
+ views::View* header_view = header->view();
+ if (previous_header != headers_.rend() &&
+ previous_header->view()->y() <
+ scroll_offset + header_view->height()) {
+ // Lower header displacing the header above.
+ header_view->SetY(previous_header->view()->y() - header_view->height());
+ header->DecorateAsSticky(false);
+ previous_header->DecorateAsSticky(false);
+ } else {
+ // A header becomes sticky.
+ header_view->SetY(scroll_offset);
+ header->DecorateAsSticky(true);
+ header_view->Layout();
+ header_view->SchedulePaint();
+ }
+ break;
+ }
+ }
+
+ // Header child views that stick to the top of visible viewport when scrolled.
+ std::vector<Header> headers_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScrollContentsView);
+};
+
// Constants for the title row in material design.
const int kTitleRowVerticalPadding = 4;
const int kTitleRowSeparatorBorderHeight = 1;
@@ -65,8 +215,6 @@ class TitleRowSeparatorLayout : public views::LayoutManager {
}
};
-} // namespace
-
class ScrollSeparator : public views::View {
public:
ScrollSeparator() {}
@@ -74,7 +222,7 @@ class ScrollSeparator : public views::View {
~ScrollSeparator() override {}
private:
- // Overriden from views::View.
+ // views::View:
void OnPaint(gfx::Canvas* canvas) override {
canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor);
}
@@ -85,6 +233,8 @@ class ScrollSeparator : public views::View {
DISALLOW_COPY_AND_ASSIGN(ScrollSeparator);
};
+} // namespace
+
class ScrollBorder : public views::Border {
public:
ScrollBorder() {}
@@ -93,7 +243,7 @@ class ScrollBorder : public views::Border {
void set_visible(bool visible) { visible_ = visible; }
private:
- // Overridden from views::Border.
+ // views::Border:
void Paint(const views::View& view, gfx::Canvas* canvas) override {
if (!visible_)
return;
@@ -105,7 +255,7 @@ class ScrollBorder : public views::Border {
gfx::Size GetMinimumSize() const override { return gfx::Size(0, 1); }
- bool visible_;
+ bool visible_ = false;
DISALLOW_COPY_AND_ASSIGN(ScrollBorder);
};
@@ -161,7 +311,7 @@ void TrayDetailsView::CreateTitleRow(int string_id) {
title_row_separator_->SetLayoutManager(new TitleRowSeparatorLayout);
views::Separator* separator =
new views::Separator(views::Separator::HORIZONTAL);
- separator->SetColor(ash::kTitleRowSeparatorBorderColor);
+ separator->SetColor(kTitleRowSeparatorBorderColor);
separator->SetPreferredSize(kTitleRowSeparatorBorderHeight);
separator->SetBorder(views::Border::CreateEmptyBorder(
kTitleRowSeparatorHeight - kTitleRowSeparatorBorderHeight, 0, 0, 0));
@@ -181,9 +331,7 @@ void TrayDetailsView::CreateTitleRow(int string_id) {
void TrayDetailsView::CreateScrollableList() {
DCHECK(!scroller_);
- scroll_content_ = new views::View;
- scroll_content_->SetLayoutManager(
- new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
+ scroll_content_ = new ScrollContentsView();
scroller_ = new FixedSizedScrollView;
scroller_->SetContentsView(scroll_content_);
« no previous file with comments | « ash/common/system/tray/tray_constants.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698