Skip to content

Commit 6166e73

Browse files
committed
[Carousel] Implemented smoothScrollToPosition
PiperOrigin-RevId: 509873609
1 parent 0ce6ae4 commit 6166e73

File tree

4 files changed

+86
-3
lines changed

4 files changed

+86
-3
lines changed

catalog/java/io/material/catalog/carousel/MultiBrowseDemoFragment.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import com.google.android.material.carousel.MultiBrowseCarouselStrategy;
3131
import com.google.android.material.divider.MaterialDividerItemDecoration;
3232
import com.google.android.material.materialswitch.MaterialSwitch;
33+
import com.google.android.material.slider.Slider;
34+
import com.google.android.material.slider.Slider.OnSliderTouchListener;
3335
import io.material.catalog.feature.DemoFragment;
3436

3537
/** A fragment that displays the multi-browse variants of the Carousel. */
@@ -60,6 +62,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle bundle) {
6062
MaterialSwitch forceCompactSwitch = view.findViewById(R.id.force_compact_arrangement_switch);
6163
MaterialSwitch drawDividers = view.findViewById(R.id.draw_dividers_switch);
6264
AutoCompleteTextView itemCountDropdown = view.findViewById(R.id.item_count_dropdown);
65+
Slider positionSlider = view.findViewById(R.id.position_slider);
6366

6467
// A start-aligned multi-browse carousel
6568
RecyclerView multiBrowseStartRecyclerView =
@@ -97,10 +100,38 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle bundle) {
97100
(item, position) -> multiBrowseStartRecyclerView.scrollToPosition(position));
98101

99102
itemCountDropdown.setOnItemClickListener(
100-
(parent, view1, position, id) ->
101-
adapter.submitList(CarouselData.createItems().subList(0, position)));
103+
(parent, view1, position, id) -> {
104+
adapter.submitList(
105+
CarouselData.createItems().subList(0, position),
106+
updateSliderRange(positionSlider, adapter));
107+
});
108+
109+
positionSlider.addOnSliderTouchListener(
110+
new OnSliderTouchListener() {
111+
@Override
112+
public void onStartTrackingTouch(@NonNull Slider slider) {}
113+
114+
@Override
115+
public void onStopTrackingTouch(@NonNull Slider slider) {
116+
multiBrowseStartRecyclerView.smoothScrollToPosition((int) slider.getValue() - 1);
117+
}
118+
});
102119

103120
multiBrowseStartRecyclerView.setAdapter(adapter);
104-
adapter.submitList(CarouselData.createItems());
121+
adapter.submitList(CarouselData.createItems(), updateSliderRange(positionSlider, adapter));
122+
}
123+
124+
private static Runnable updateSliderRange(Slider slider, CarouselAdapter adapter) {
125+
return () -> {
126+
if (adapter.getItemCount() == 0) {
127+
slider.setValueFrom(0);
128+
slider.setValueTo(0);
129+
return;
130+
}
131+
132+
slider.setValue(1);
133+
slider.setValueFrom(1);
134+
slider.setValueTo(adapter.getItemCount());
135+
};
105136
}
106137
}

catalog/java/io/material/catalog/carousel/res/layout/cat_carousel_multi_browse_fragment.xml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,25 @@
8888

8989
</com.google.android.material.textfield.TextInputLayout>
9090

91+
<TextView
92+
android:id="@+id/position_slider_label"
93+
android:layout_width="wrap_content"
94+
android:layout_height="wrap_content"
95+
android:layout_marginHorizontal="16dp"
96+
android:layout_marginTop="16dp"
97+
android:labelFor="@id/position_slider"
98+
android:text="@string/cat_carousel_position_slider_label"
99+
android:textAppearance="?attr/textAppearanceBodyLarge"/>
100+
101+
<com.google.android.material.slider.Slider
102+
android:id="@+id/position_slider"
103+
android:layout_width="match_parent"
104+
android:layout_height="wrap_content"
105+
android:layout_marginHorizontal="16dp"
106+
android:layout_marginBottom="8dp"
107+
android:contentDescription="@string/cat_carousel_position_slider_content_description"
108+
android:stepSize="1.0"/>
109+
91110
<androidx.recyclerview.widget.RecyclerView
92111
android:id="@+id/multi_browse_start_carousel_recycler_view"
93112
android:layout_width="match_parent"

catalog/java/io/material/catalog/carousel/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
<string name="cat_carousel_force_compact_arrangement_label" translatable="false">Force compact arrangement</string>
2121
<string name="cat_carousel_draw_dividers_label" translatable="false">Draw dividers</string>
2222
<string name="cat_carousel_adapter_item_count_hint_label" translatable="false">Item count</string>
23+
<string name="cat_carousel_position_slider_label" translatable="false">Scroll position</string>
24+
<string name="cat_carousel_position_slider_content_description" translatable="false">Scroll position slider</string>
2325

2426
<string-array name="cat_carousel_adapter_count_content" translatable="false">
2527
<item>0</item>

lib/java/com/google/android/material/carousel/CarouselLayoutManager.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
import android.graphics.Canvas;
2626
import android.graphics.Color;
2727
import android.graphics.Paint;
28+
import android.graphics.PointF;
2829
import android.graphics.Rect;
30+
import androidx.recyclerview.widget.LinearSmoothScroller;
2931
import androidx.recyclerview.widget.RecyclerView;
3032
import androidx.recyclerview.widget.RecyclerView.LayoutManager;
3133
import androidx.recyclerview.widget.RecyclerView.LayoutParams;
@@ -806,6 +808,35 @@ public void scrollToPosition(int position) {
806808
requestLayout();
807809
}
808810

811+
@Override
812+
public void smoothScrollToPosition(RecyclerView recyclerView, State state, int position) {
813+
LinearSmoothScroller linearSmoothScroller =
814+
new LinearSmoothScroller(recyclerView.getContext()) {
815+
@Nullable
816+
@Override
817+
public PointF computeScrollVectorForPosition(int targetPosition) {
818+
if (keylineStateList == null) {
819+
return null;
820+
}
821+
822+
float targetScrollOffset =
823+
getScrollOffsetForPosition(keylineStateList.getDefaultState(), targetPosition);
824+
return new PointF(targetScrollOffset - horizontalScrollOffset, 0F);
825+
}
826+
827+
@Override
828+
public int calculateDxToMakeVisible(View view, int snapPreference) {
829+
// Override dx calculations so the target view is brought all the way into the focal
830+
// range instead of just being made visible.
831+
float targetScrollOffset =
832+
getScrollOffsetForPosition(keylineStateList.getDefaultState(), getPosition(view));
833+
return (int) (horizontalScrollOffset - targetScrollOffset);
834+
}
835+
};
836+
linearSmoothScroller.setTargetPosition(position);
837+
startSmoothScroll(linearSmoothScroller);
838+
}
839+
809840
@Override
810841
public boolean canScrollHorizontally() {
811842
return true;

0 commit comments

Comments
 (0)