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

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java

Issue 2106753002: Refine snap scrolling on the Cards New Tab Page. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update comment. Created 4 years, 6 months 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
Index: chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
index bf63bf3b8b316c64e9a6a31c50b618ffea643fbc..2ef4889879f95248354d99dc97177b7201aa4420 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
@@ -32,10 +32,11 @@ public class NewTabPageRecyclerView extends RecyclerView {
private static final int MIN_BOTTOM_SPACING = 0;
/**
- * Position in the adapter of the item we snap the scroll at, when switching between above and
- * below the fold.
+ * Positions of key items in the RecyclerView.
*/
- private static final int SNAP_ITEM_ADAPTER_POSITION = 1;
+ private static final int ABOVE_THE_FOLD_ITEM_POSITION = 0;
+ private static final int ARTICLES_HEADER_ITEM_POSITION = 1;
+ private static final int PEEKING_CARD_ITEM_POSITION = 2;
private final GestureDetector mGestureDetector;
private final LinearLayoutManager mLayoutManager;
@@ -159,13 +160,13 @@ public class NewTabPageRecyclerView extends RecyclerView {
int firstVisiblePos = mLayoutManager.findFirstVisibleItemPosition();
// We have enough items to fill the view, since the snap point item is not even visible.
- if (firstVisiblePos > SNAP_ITEM_ADAPTER_POSITION) return MIN_BOTTOM_SPACING;
+ if (firstVisiblePos > ARTICLES_HEADER_ITEM_POSITION) return MIN_BOTTOM_SPACING;
// The spacing item is the last item, the last content item is directly above that.
int lastContentItemPosition = getAdapter().getItemCount() - 2;
ViewHolder lastContentItem = findViewHolderForAdapterPosition(lastContentItemPosition);
- ViewHolder snapItem = findViewHolderForAdapterPosition(SNAP_ITEM_ADAPTER_POSITION);
+ ViewHolder snapItem = findViewHolderForAdapterPosition(ARTICLES_HEADER_ITEM_POSITION);
int bottomSpacing = getHeight() - mToolbarHeight;
if (lastContentItem == null || snapItem == null) {
@@ -209,7 +210,7 @@ public class NewTabPageRecyclerView extends RecyclerView {
* @return The viewholder for the first card or null if no card is available.
*/
private CardViewHolder findFirstCard() {
- int firstCardIndex = 2; // 0 => above-the-fold, 1 => header, 2 => card
+ int firstCardIndex = PEEKING_CARD_ITEM_POSITION;
ViewHolder viewHolder = findViewHolderForAdapterPosition(firstCardIndex);
if (!(viewHolder instanceof CardViewHolder)) return null;
@@ -239,7 +240,7 @@ public class NewTabPageRecyclerView extends RecyclerView {
*/
private SnippetHeaderViewHolder findHeaderView() {
// Get the snippet header view. It is always at position 1
- ViewHolder viewHolder = findViewHolderForAdapterPosition(1);
+ ViewHolder viewHolder = findViewHolderForAdapterPosition(ARTICLES_HEADER_ITEM_POSITION);
if (!(viewHolder instanceof SnippetHeaderViewHolder)) return null;
return (SnippetHeaderViewHolder) viewHolder;
@@ -256,4 +257,68 @@ public class NewTabPageRecyclerView extends RecyclerView {
mCompensationHeight -= itemView.getHeight();
assert mCompensationHeight >= 0;
}
+
+ /**
+ * If the RecyclerView is currently scrolled to between regionStart and regionEnd, smooth scroll
+ * out of the region. flipPoint is the threshold used to decide which bound of the region to
+ * scroll to. It returns whether the view was scrolled.
+ */
+ private boolean scrollOutOfRegion(int regionStart, int flipPoint, int regionEnd) {
+ // This function is only called when we are using the RecyclerView.
+ final int currentScroll = computeVerticalScrollOffset();
+
+ if (currentScroll < regionStart || currentScroll > regionEnd) return false;
+
+ if (currentScroll < flipPoint) {
+ smoothScrollBy(0, regionStart - currentScroll);
+ } else {
+ smoothScrollBy(0, regionEnd - currentScroll);
+ }
+ return true;
+ }
+
+ /**
+ * If the RecyclerView is currently scrolled to between regionStart and regionEnd, smooth scroll
+ * out of the region to the nearest edge.
+ */
+ private boolean scrollOutOfRegion(int regionStart, int regionEnd) {
+ return scrollOutOfRegion(regionStart, (regionStart + regionEnd) / 2, regionEnd);
+ }
+
+ /**
+ * Snaps the scroll point of the RecyclerView to prevent the user from scrolling to midway
+ * through a transition and to allow peeking card behaviour.
+ */
+ public void snapScroll(View fakeBox, int parentScrollY, int parentHeight) {
+ // Snap scroll to prevent resting in the middle of the omnibox transition.
+ final int searchBoxTransitionLength = getResources()
+ .getDimensionPixelSize(R.dimen.ntp_search_box_transition_length);
+ if (scrollOutOfRegion(fakeBox.getTop() - searchBoxTransitionLength, fakeBox.getTop())) {
+ // The snap scrolling regions should never overlap.
+ return;
+ }
+
+ // Snap scroll to prevent resting in the middle of the peeking card transition
+ // and to allow the peeking card to peek a bit before snapping back.
+ if (findFirstCard() != null && isFirstItemVisible()) {
+ View peekingCard = findFirstCard().itemView;
+ final int peekingHeight = getResources().getDimensionPixelSize(
+ R.dimen.snippets_padding_and_peeking_card_height);
+
+ // |A + B| gives the offset of the peeking card relative to the Recycler View,
+ // so scrolling to this point would put the peeking card at the top of the
+ // screen.
+ // |A + B - C| will scroll us so that the peeking card is just off the bottom
+ // of the screen.
+ // Finally, we get |A + B - C + D| because the transition starts from the
+ // peeking card's resting point, which is |D| from the bottom of the screen.
+ int start = peekingCard.getTop() // A.
+ + parentScrollY // B.
+ - parentHeight // C.
+ + peekingHeight; // D.
+ scrollOutOfRegion(start,
+ start + peekingCard.getHeight() / 2,
+ start + peekingCard.getHeight() / 2);
+ }
+ }
}

Powered by Google App Engine
This is Rietveld 408576698