Skip to content

Commit

Permalink
[Carousel] Prevent scrolling if there's less items than focal keylines
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 625466841
  • Loading branch information
imhappi committed Apr 17, 2024
1 parent 9393b97 commit 8c541e6
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,10 @@ private static KeylineRange getSurroundingKeylineRange(
keylines.get(startMinDistanceIndex), keylines.get(endMinDistanceIndex));
}

private KeylineState getKeylineStartingState(KeylineStateList keylineStateList) {
return isLayoutRtl() ? keylineStateList.getEndState() : keylineStateList.getStartState();
}

/**
* Update the current keyline state by shifting it in response to any change in scroll offset.
*
Expand All @@ -794,8 +798,7 @@ private void updateCurrentKeylineStateForScrollOffset(
if (maxScroll <= minScroll) {
// We don't have enough items in the list to scroll and we should use the keyline state
// that aligns items to the start of the container.
this.currentKeylineState =
isLayoutRtl() ? keylineStateList.getEndState() : keylineStateList.getStartState();
this.currentKeylineState = getKeylineStartingState(keylineStateList);
} else {
this.currentKeylineState =
keylineStateList.getShiftedState(scrollOffset, minScroll, maxScroll);
Expand Down Expand Up @@ -1454,6 +1457,12 @@ private int scrollBy(int distance, Recycler recycler, State state) {
recalculateKeylineStateList(recycler);
}

// If the number of items is equal or less than the number of focal items, we should not be able
// to scroll.
if (getItemCount() <= getKeylineStartingState(keylineStateList).getTotalVisibleFocalItems()) {
return 0;
}

// Calculate how much the carousel should scroll and update the scroll offset.
int scrolledBy = calculateShouldScrollBy(distance, scrollOffset, minScroll, maxScroll);
scrollOffset += scrolledBy;
Expand Down
11 changes: 11 additions & 0 deletions lib/java/com/google/android/material/carousel/KeylineState.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
final class KeylineState {

private final float itemSize;
private int totalVisibleFocalItems;
private final List<Keyline> keylines;
private final int firstFocalKeylineIndex;
private final int lastFocalKeylineIndex;
Expand All @@ -65,6 +66,11 @@ private KeylineState(
this.keylines = Collections.unmodifiableList(keylines);
this.firstFocalKeylineIndex = firstFocalKeylineIndex;
this.lastFocalKeylineIndex = lastFocalKeylineIndex;
for (int i = firstFocalKeylineIndex; i <= lastFocalKeylineIndex; i++) {
if (keylines.get(i).cutoff == 0) {
this.totalVisibleFocalItems += 1;
}
}
}

/**
Expand All @@ -81,6 +87,11 @@ List<Keyline> getKeylines() {
return keylines;
}

/** Returns the number of focal items in the keyline state. */
int getTotalVisibleFocalItems() {
return totalVisibleFocalItems;
}

/** Returns the first focal keyline in the list. */
Keyline getFirstFocalKeyline() {
return keylines.get(firstFocalKeylineIndex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,18 @@ public void testRequestChildRectangleOnScreen_doesntScrollIfChildIsFocal() throw
assertThat(layoutManager.scrollOffset).isEqualTo(0);
}

@Test
public void testSingleItem_shouldNotScrollWithPadding() throws Throwable {
recyclerView.setPadding(50, 0, 50, 0);
recyclerView.setClipToPadding(false);
setAdapterItems(recyclerView, layoutManager, adapter, createDataSetWithSize(1));
int originalLeft = recyclerView.getChildAt(0).getLeft();

scrollHorizontallyBy(recyclerView, layoutManager, 100);

assertThat(recyclerView.getChildAt(0).getLeft()).isEqualTo(originalLeft);
}

/**
* Assigns explicit sizes to fixtures being used to construct the testing environment.
*
Expand Down

0 comments on commit 8c541e6

Please sign in to comment.