Skip to content

Commit ef9f918

Browse files
committed
[Catalog][Carousel] Add uncontained carousel demo to catalog
PiperOrigin-RevId: 559221323
1 parent b6f6eb5 commit ef9f918

File tree

4 files changed

+274
-0
lines changed

4 files changed

+274
-0
lines changed

catalog/java/io/material/catalog/carousel/CarouselFragment.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ public Fragment createFragment() {
7878
public Fragment createFragment() {
7979
return new FullScreenStrategyDemoFragment();
8080
}
81+
},
82+
new Demo(R.string.cat_carousel_uncontained_demo_title) {
83+
@Override
84+
public Fragment createFragment() {
85+
return new UncontainedCarouselDemoFragment();
86+
}
8187
});
8288
}
8389

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Copyright 2023 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.material.catalog.carousel;
18+
19+
import io.material.catalog.R;
20+
21+
import android.os.Bundle;
22+
import androidx.recyclerview.widget.RecyclerView;
23+
import android.view.LayoutInflater;
24+
import android.view.View;
25+
import android.view.ViewGroup;
26+
import android.widget.AutoCompleteTextView;
27+
import androidx.annotation.NonNull;
28+
import androidx.annotation.Nullable;
29+
import com.google.android.material.carousel.CarouselLayoutManager;
30+
import com.google.android.material.carousel.CarouselSnapHelper;
31+
import com.google.android.material.carousel.UncontainedCarouselStrategy;
32+
import com.google.android.material.divider.MaterialDividerItemDecoration;
33+
import com.google.android.material.materialswitch.MaterialSwitch;
34+
import com.google.android.material.slider.Slider;
35+
import com.google.android.material.slider.Slider.OnSliderTouchListener;
36+
import io.material.catalog.feature.DemoFragment;
37+
38+
/** A fragment that displays the uncontained variant of the Carousel. */
39+
public class UncontainedCarouselDemoFragment extends DemoFragment {
40+
41+
private MaterialDividerItemDecoration horizontalDivider;
42+
43+
@NonNull
44+
@Override
45+
public View onCreateDemoView(
46+
@NonNull LayoutInflater layoutInflater,
47+
@Nullable ViewGroup viewGroup,
48+
@Nullable Bundle bundle) {
49+
return layoutInflater.inflate(
50+
R.layout.cat_carousel_uncontained_fragment, viewGroup, false /* attachToRoot */);
51+
}
52+
53+
@Override
54+
@SuppressWarnings("RestrictTo")
55+
public void onViewCreated(@NonNull View view, @Nullable Bundle bundle) {
56+
super.onViewCreated(view, bundle);
57+
58+
horizontalDivider =
59+
new MaterialDividerItemDecoration(
60+
requireContext(), MaterialDividerItemDecoration.HORIZONTAL);
61+
62+
MaterialSwitch debugSwitch = view.findViewById(R.id.debug_switch);
63+
MaterialSwitch drawDividers = view.findViewById(R.id.draw_dividers_switch);
64+
MaterialSwitch snapSwitch = view.findViewById(R.id.snap_switch);
65+
AutoCompleteTextView itemCountDropdown = view.findViewById(R.id.item_count_dropdown);
66+
Slider positionSlider = view.findViewById(R.id.position_slider);
67+
68+
RecyclerView uncontainedRecyclerView =
69+
view.findViewById(R.id.uncontained_carousel_recycler_view);
70+
CarouselLayoutManager uncontainedCarouselLayoutManager =
71+
new CarouselLayoutManager(new UncontainedCarouselStrategy());
72+
uncontainedCarouselLayoutManager.setDebuggingEnabled(
73+
uncontainedRecyclerView, debugSwitch.isChecked());
74+
uncontainedRecyclerView.setLayoutManager(uncontainedCarouselLayoutManager);
75+
uncontainedRecyclerView.setNestedScrollingEnabled(false);
76+
77+
debugSwitch.setOnCheckedChangeListener(
78+
(buttonView, isChecked) -> {
79+
uncontainedRecyclerView.setBackgroundResource(
80+
isChecked ? R.drawable.dashed_outline_rectangle : 0);
81+
uncontainedCarouselLayoutManager.setDebuggingEnabled(
82+
uncontainedRecyclerView, isChecked);
83+
});
84+
85+
drawDividers.setOnCheckedChangeListener(
86+
(buttonView, isChecked) -> {
87+
if (isChecked) {
88+
uncontainedRecyclerView.addItemDecoration(horizontalDivider);
89+
} else {
90+
uncontainedRecyclerView.removeItemDecoration(horizontalDivider);
91+
}
92+
});
93+
94+
CarouselSnapHelper snapHelper = new CarouselSnapHelper();
95+
snapSwitch.setOnCheckedChangeListener(
96+
(buttonView, isChecked) -> {
97+
if (isChecked) {
98+
snapHelper.attachToRecyclerView(uncontainedRecyclerView);
99+
} else {
100+
snapHelper.attachToRecyclerView(null);
101+
}
102+
});
103+
104+
CarouselAdapter adapter =
105+
new CarouselAdapter(
106+
(item, position) -> uncontainedRecyclerView.scrollToPosition(position),
107+
R.layout.cat_carousel_item_narrow);
108+
109+
itemCountDropdown.setOnItemClickListener(
110+
(parent, view1, position, id) ->
111+
adapter.submitList(
112+
CarouselData.createItems().subList(0, position),
113+
updateSliderRange(positionSlider, adapter)));
114+
115+
positionSlider.addOnSliderTouchListener(
116+
new OnSliderTouchListener() {
117+
@Override
118+
public void onStartTrackingTouch(@NonNull Slider slider) {}
119+
120+
@Override
121+
public void onStopTrackingTouch(@NonNull Slider slider) {
122+
uncontainedRecyclerView.smoothScrollToPosition(((int) slider.getValue()) - 1);
123+
}
124+
});
125+
126+
uncontainedRecyclerView.setAdapter(adapter);
127+
adapter.submitList(CarouselData.createItems(), updateSliderRange(positionSlider, adapter));
128+
}
129+
130+
private static Runnable updateSliderRange(Slider slider, CarouselAdapter adapter) {
131+
return () -> {
132+
if (adapter.getItemCount() <= 1) {
133+
slider.setEnabled(false);
134+
return;
135+
}
136+
137+
slider.setValueFrom(1);
138+
slider.setValue(1);
139+
slider.setValueTo(adapter.getItemCount());
140+
slider.setEnabled(true);
141+
};
142+
}
143+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright 2023 The Android Open Source Project
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
https://www.apache.org/licenses/LICENSE-2.0
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS,
10+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the License for the specific language governing permissions and
12+
limitations under the License.
13+
-->
14+
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
15+
xmlns:app="http://schemas.android.com/apk/res-auto"
16+
android:layout_width="match_parent"
17+
android:layout_height="match_parent">
18+
<LinearLayout
19+
android:id="@+id/container"
20+
android:layout_height="wrap_content"
21+
android:layout_width="match_parent"
22+
android:orientation="vertical">
23+
24+
<TextView
25+
android:id="@+id/uncontained_title_text_view"
26+
android:layout_width="wrap_content"
27+
android:layout_height="wrap_content"
28+
android:layout_marginHorizontal="16dp"
29+
android:layout_marginVertical="4dp"
30+
android:text="@string/cat_carousel_uncontained_title"
31+
android:textAppearance="?attr/textAppearanceTitleMedium" />
32+
33+
<TextView
34+
android:id="@+id/uncontained_desc_text_view"
35+
android:layout_width="wrap_content"
36+
android:layout_height="wrap_content"
37+
android:layout_marginHorizontal="16dp"
38+
android:layout_marginVertical="4dp"
39+
android:text="@string/cat_carousel_uncontained_desc"
40+
android:textAppearance="?attr/textAppearanceBodyMedium" />
41+
42+
<com.google.android.material.materialswitch.MaterialSwitch
43+
android:id="@+id/debug_switch"
44+
android:layout_width="match_parent"
45+
android:layout_height="wrap_content"
46+
android:checked="false"
47+
android:layout_marginHorizontal="16dp"
48+
android:layout_marginVertical="8dp"
49+
android:textAppearance="?attr/textAppearanceBodyLarge"
50+
android:text="@string/cat_carousel_debug_mode_label"/>
51+
52+
<com.google.android.material.materialswitch.MaterialSwitch
53+
android:id="@+id/draw_dividers_switch"
54+
android:layout_width="match_parent"
55+
android:layout_height="wrap_content"
56+
android:checked="false"
57+
android:layout_marginHorizontal="16dp"
58+
android:layout_marginVertical="8dp"
59+
android:textAppearance="?attr/textAppearanceBodyLarge"
60+
android:text="@string/cat_carousel_draw_dividers_label"/>
61+
62+
<com.google.android.material.materialswitch.MaterialSwitch
63+
android:id="@+id/snap_switch"
64+
android:layout_width="match_parent"
65+
android:layout_height="wrap_content"
66+
android:checked="false"
67+
android:layout_marginHorizontal="16dp"
68+
android:layout_marginVertical="8dp"
69+
android:textAppearance="?attr/textAppearanceBodyLarge"
70+
android:contentDescription="@string/cat_carousel_snap_switch_description"
71+
android:text="@string/cat_carousel_enable_snap_label"/>
72+
73+
<com.google.android.material.textfield.TextInputLayout
74+
style="?attr/textInputFilledExposedDropdownMenuStyle"
75+
android:layout_width="match_parent"
76+
android:layout_height="wrap_content"
77+
android:layout_gravity="center_vertical"
78+
android:layout_marginHorizontal="16dp"
79+
android:layout_marginVertical="8dp"
80+
app:helperTextEnabled="false">
81+
82+
<AutoCompleteTextView
83+
android:id="@+id/item_count_dropdown"
84+
android:layout_width="match_parent"
85+
android:layout_height="wrap_content"
86+
android:inputType="none"
87+
android:hint="@string/cat_carousel_adapter_item_count_hint_label"
88+
app:simpleItems="@array/cat_carousel_adapter_count_content"/>
89+
90+
</com.google.android.material.textfield.TextInputLayout>
91+
92+
<TextView
93+
android:id="@+id/position_slider_label"
94+
android:layout_width="wrap_content"
95+
android:layout_height="wrap_content"
96+
android:layout_marginHorizontal="16dp"
97+
android:layout_marginTop="16dp"
98+
android:labelFor="@id/position_slider"
99+
android:text="@string/cat_carousel_position_slider_label"
100+
android:textAppearance="?attr/textAppearanceBodyLarge"/>
101+
102+
<com.google.android.material.slider.Slider
103+
android:id="@+id/position_slider"
104+
android:layout_width="match_parent"
105+
android:layout_height="wrap_content"
106+
android:layout_marginHorizontal="16dp"
107+
android:layout_marginBottom="8dp"
108+
android:contentDescription="@string/cat_carousel_position_slider_content_description"
109+
android:stepSize="1.0"/>
110+
111+
<androidx.recyclerview.widget.RecyclerView
112+
android:id="@+id/uncontained_carousel_recycler_view"
113+
android:layout_width="match_parent"
114+
android:layout_height="196dp"
115+
android:layout_marginHorizontal="16dp"
116+
android:layout_marginVertical="16dp"
117+
android:clipChildren="false"
118+
android:clipToPadding="false" />
119+
120+
</LinearLayout>
121+
</androidx.core.widget.NestedScrollView>

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
<string name="cat_carousel_multi_browse_demo_title" translatable="false">Multi-browse Carousel</string>
5353
<string name="cat_carousel_hero_demo_title" description="Name of the hero variant demo. [CHAR_LIMIT=NONE]">Hero Carousel</string>
5454
<string name="cat_carousel_fullscreen_demo_title" translatable="false">Fullscreen Carousel</string>
55+
<string name="cat_carousel_uncontained_demo_title" description="Name of the uncontained variant demo. [CHAR_LIMIT=NONE]">Uncontained Carousel</string>
5556

5657
<string name="cat_carousel_multi_browse_title" translatable="false">Multi-browse</string>
5758
<string name="cat_carousel_multi_browse_desc" translatable="false">Multi-browse carousels allow quick browsing of many small items, like a photo thumbnail gallery.</string>
@@ -62,6 +63,9 @@
6263
<string name="cat_carousel_fullscreen_title" description="Title of the fullscreen variant demo. [CHAR_LIMIT=NONE]">Fullscreen</string>
6364
<string name="cat_carousel_fullscreen_desc" description="Title of the fullscreen variant demo. [CHAR_LIMIT=NONE]">Fullscreen carousels allow browsing with a focus on one item at a time.</string>
6465

66+
<string name="cat_carousel_uncontained_title" description="Title of the uncontained variant demo. [CHAR_LIMIT=NONE]">Uncontained</string>
67+
<string name="cat_carousel_uncontained_desc" description="Title of the uncontained variant demo. [CHAR_LIMIT=NONE]">Uncontained carousels show items at their original sizes, with items getting smaller as they reach the edges of the screen and are cut off in the direction they scroll.</string>
68+
6569
<string name="cat_carousel_image_1_content_desc" translatable="false">A daisy at sunset</string>
6670
<string name="cat_carousel_image_2_content_desc" translatable="false">Portrait of a person with hair covering their face</string>
6771
<string name="cat_carousel_image_3_content_desc" translatable="false">Fungus on a tree</string>

0 commit comments

Comments
 (0)