Skip to content

Commit 3c1a61c

Browse files
imhappipekingme
authored andcommitted
[Lists] Add styles for control elements in lists
PiperOrigin-RevId: 832010671
1 parent 69e9676 commit 3c1a61c

File tree

9 files changed

+225
-11
lines changed

9 files changed

+225
-11
lines changed

catalog/java/io/material/catalog/listitem/ListsMainDemoFragment.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
import io.material.catalog.R;
2020

21+
import static android.view.View.GONE;
22+
import static android.view.View.VISIBLE;
23+
2124
import android.content.Context;
2225
import android.graphics.Rect;
2326
import android.os.Bundle;
@@ -36,6 +39,7 @@
3639
import com.google.android.material.card.MaterialCardView;
3740
import com.google.android.material.checkbox.MaterialCheckBox;
3841
import com.google.android.material.listitem.ListItemViewHolder;
42+
import com.google.android.material.materialswitch.MaterialSwitch;
3943
import io.material.catalog.feature.DemoFragment;
4044
import java.util.ArrayList;
4145
import java.util.List;
@@ -129,26 +133,40 @@ public static class CustomItemViewHolder extends ListItemViewHolder {
129133
private final TextView textView;
130134
private final MaterialCardView cardView;
131135
private final MaterialCheckBox checkBox;
132-
136+
private final MaterialSwitch materialSwitch;
133137
private final ImageView leadingIcon;
134138
public CustomItemViewHolder(@NonNull View itemView) {
135139
super(itemView);
136140
textView = itemView.findViewById(R.id.cat_list_item_text);
137141
cardView = itemView.findViewById(R.id.cat_list_item_card_view);
138142
leadingIcon = itemView.findViewById(R.id.cat_list_item_start_icon);
139143
checkBox = itemView.findViewById(R.id.cat_list_item_checkbox);
144+
materialSwitch = itemView.findViewById(R.id.cat_list_item_switch);
140145
}
141146

142147
public void bind(@NonNull CustomListItemData data) {
143148
super.bind();
144149
textView.setText(data.text);
150+
leadingIcon.setSelected(data.checked);
151+
// We are arbitrarily showing 5 items with the switch and the rest with the checkbox to show
152+
// a more varied example.
153+
if (data.indexInSection < 5) {
154+
checkBox.setVisibility(GONE);
155+
materialSwitch.setVisibility(VISIBLE);
156+
materialSwitch.setChecked(data.checked);
157+
} else {
158+
checkBox.setVisibility(VISIBLE);
159+
materialSwitch.setVisibility(GONE);
160+
checkBox.setChecked(data.checked);
161+
}
145162
cardView.setChecked(data.checked);
146163
cardView.setOnClickListener(
147164
v -> {
148165
Toast.makeText(v.getContext(), R.string.mtrl_list_item_clicked, Toast.LENGTH_SHORT)
149166
.show();
150167
cardView.toggle();
151168
checkBox.setChecked(cardView.isChecked());
169+
materialSwitch.setChecked(cardView.isChecked());
152170
leadingIcon.setSelected(cardView.isChecked());
153171
data.checked = !data.checked;
154172
});

catalog/java/io/material/catalog/listitem/SegmentedListDemoFragment.java

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,30 @@
1818

1919
import io.material.catalog.R;
2020

21+
import static android.widget.Adapter.NO_SELECTION;
22+
2123
import android.os.Bundle;
2224
import androidx.recyclerview.widget.LinearLayoutManager;
2325
import androidx.recyclerview.widget.RecyclerView;
26+
import androidx.recyclerview.widget.RecyclerView.Adapter;
2427
import android.view.LayoutInflater;
2528
import android.view.View;
2629
import android.view.ViewGroup;
30+
import android.widget.ImageView;
31+
import android.widget.RadioButton;
32+
import android.widget.TextView;
33+
import android.widget.Toast;
2734
import androidx.annotation.NonNull;
2835
import androidx.annotation.Nullable;
36+
import com.google.android.material.card.MaterialCardView;
37+
import com.google.android.material.listitem.ListItemViewHolder;
2938
import java.util.ArrayList;
3039
import java.util.List;
3140

3241
/** A fragment that displays a segmented List demos for the Catalog app. */
3342
public class SegmentedListDemoFragment extends ListsMainDemoFragment {
3443

44+
private ListsAdapter adapter;
3545
@NonNull
3646
@Override
3747
public View onCreateDemoView(
@@ -52,17 +62,20 @@ public View onCreateDemoView(
5262
20));
5363
}
5464

55-
view.setAdapter(new ListsAdapter(data));
65+
adapter = new ListsAdapter(data);
66+
view.setAdapter(adapter);
5667
view.addItemDecoration(new MarginItemDecoration(getContext()));
5768

5869
return view;
5970
}
6071

6172
/** An Adapter that shows custom list items */
62-
public static class ListsAdapter extends ListsMainDemoFragment.ListsAdapter {
73+
public class ListsAdapter extends Adapter<CustomItemViewHolder> {
74+
private int selectedPosition = NO_SELECTION;
75+
private final List<CustomListItemData> items;
6376

6477
public ListsAdapter(@NonNull List<CustomListItemData> items) {
65-
super(items);
78+
this.items = items;
6679
}
6780

6881
@NonNull
@@ -77,5 +90,63 @@ public CustomItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int po
7790
/* attachToRoot= */ false);
7891
return new CustomItemViewHolder(item);
7992
}
93+
@Override
94+
public void onBindViewHolder(
95+
@NonNull CustomItemViewHolder viewHolder, int position) {
96+
CustomListItemData data = getItemAt(position);
97+
viewHolder.bind(data);
98+
}
99+
@Override
100+
public int getItemCount() {
101+
return items.size();
102+
}
103+
@NonNull
104+
public CustomListItemData getItemAt(int i) {
105+
return items.get(i);
106+
}
107+
/**
108+
* Set exclusive selected position.
109+
*/
110+
public void setSelectedPosition(int selectedPosition) {
111+
this.selectedPosition = selectedPosition;
112+
}
113+
/**
114+
* Return exclusive selected position.
115+
*/
116+
public int getSelectedPosition() {
117+
return selectedPosition;
118+
}
119+
}
120+
/** A ViewHolder that shows custom list items */
121+
public class CustomItemViewHolder extends ListItemViewHolder {
122+
private final TextView textView;
123+
private final MaterialCardView cardView;
124+
private final RadioButton radioButton;
125+
private final ImageView leadingIcon;
126+
public CustomItemViewHolder(@NonNull View itemView) {
127+
super(itemView);
128+
textView = itemView.findViewById(R.id.cat_list_item_text);
129+
cardView = itemView.findViewById(R.id.cat_list_item_card_view);
130+
leadingIcon = itemView.findViewById(R.id.cat_list_item_start_icon);
131+
radioButton = itemView.findViewById(R.id.cat_list_item_radio_button);
132+
}
133+
public void bind(@NonNull CustomListItemData data) {
134+
super.bind();
135+
textView.setText(data.text);
136+
cardView.setChecked(data.indexInSection == adapter.getSelectedPosition());
137+
radioButton.setChecked(cardView.isChecked());
138+
leadingIcon.setSelected(cardView.isChecked());
139+
cardView.setOnClickListener(
140+
v -> {
141+
int previouslySelectedPosition = adapter.getSelectedPosition();
142+
adapter.setSelectedPosition(data.indexInSection);
143+
Toast.makeText(v.getContext(), R.string.mtrl_list_item_clicked, Toast.LENGTH_SHORT)
144+
.show();
145+
adapter.notifyItemChanged(data.indexInSection);
146+
if (previouslySelectedPosition != NO_SELECTION) {
147+
adapter.notifyItemChanged(previouslySelectedPosition);
148+
}
149+
});
150+
}
80151
}
81152
}

catalog/java/io/material/catalog/listitem/res/layout/cat_list_item_segmented_viewholder.xml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,11 @@
6161
android:layout_width="wrap_content"
6262
android:text="@string/cat_list_item_supporting_text"/>
6363
</LinearLayout>
64-
<com.google.android.material.checkbox.MaterialCheckBox
65-
android:id="@+id/cat_list_item_checkbox"
64+
<com.google.android.material.radiobutton.MaterialRadioButton
65+
style="@style/Widget.Material3.RadioButton.ListItem"
66+
android:id="@+id/cat_list_item_radio_button"
6667
android:layout_width="wrap_content"
6768
android:layout_height="wrap_content"
68-
android:clickable="false"
69-
android:focusable="false"
70-
android:importantForAccessibility="no"
7169
android:layout_marginStart="12dp"/>
7270
</LinearLayout>
7371
</com.google.android.material.listitem.ListItemCardView>

catalog/java/io/material/catalog/listitem/res/layout/cat_list_item_viewholder.xml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,18 @@
5959
android:layout_width="wrap_content"
6060
android:text="@string/cat_list_item_supporting_text"/>
6161
</LinearLayout>
62+
<com.google.android.material.materialswitch.MaterialSwitch
63+
android:id="@+id/cat_list_item_switch"
64+
android:layout_width="wrap_content"
65+
android:layout_height="wrap_content"
66+
style="@style/Widget.Material3.Switch.ListItem"
67+
android:layout_marginStart="12dp"/>
6268
<com.google.android.material.checkbox.MaterialCheckBox
6369
android:id="@+id/cat_list_item_checkbox"
6470
android:layout_width="wrap_content"
6571
android:layout_height="wrap_content"
66-
android:clickable="false"
67-
android:focusable="false"
72+
style="@style/Widget.Material3.Checkbox.ListItem"
73+
android:visibility="gone"
6874
android:layout_marginStart="12dp"/>
6975
</LinearLayout>
7076
</com.google.android.material.listitem.ListItemCardView>

lib/java/com/google/android/material/listitem/res-public/values/public.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
<public name="Widget.Material3.TextView.ListItem.LabelText" type="style"/>
3636
<public name="Widget.Material3.TextView.ListItem.SupportingText" type="style"/>
3737
<public name="Widget.Material3.TextView.ListItem.TrailingSupportingText" type="style"/>
38+
<public name="Widget.Material3.Checkbox.ListItem" type="style"/>
39+
<public name="Widget.Material3.Switch.ListItem" type="style"/>
40+
<public name="Widget.Material3.RadioButton.ListItem" type="style"/>
3841

3942
<public name="listItemShapeAppearanceSingle" type="attr"/>
4043
<public name="listItemShapeAppearanceFirst" type="attr"/>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
~ Copyright (C) 2025 The Android Open Source Project
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ http://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
<selector xmlns:android="http://schemas.android.com/apk/res/android"
18+
xmlns:app="http://schemas.android.com/apk/res-auto">
19+
<!-- Disabled -->
20+
<item android:alpha="@dimen/m3_comp_checkbox_selected_disabled_container_opacity"
21+
android:color="@macro/m3_comp_checkbox_selected_disabled_container_color"
22+
android:state_enabled="false"/>
23+
<!-- Error -->
24+
<item android:color="@macro/m3_comp_checkbox_selected_error_container_color" app:state_error="true"/>
25+
<!-- Indeterminate -->
26+
<item android:color="@macro/m3_comp_checkbox_selected_container_color" app:state_indeterminate="true"/>
27+
<!-- Checked -->
28+
<item android:color="?attr/colorSecondary" android:state_checked="true"/>
29+
<!-- Unchecked -->
30+
<item android:color="@macro/m3_comp_checkbox_unselected_outline_color" android:state_checked="false"/>
31+
</selector>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
~ Copyright (C) 2025 The Android Open Source Project
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ http://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
<selector xmlns:android="http://schemas.android.com/apk/res/android">
18+
<!-- Disabled -->
19+
<item android:alpha="@dimen/m3_comp_radio_button_disabled_unselected_icon_opacity"
20+
android:color="@macro/m3_comp_radio_button_disabled_unselected_icon_color"
21+
android:state_enabled="false"/>
22+
<!-- Checked -->
23+
<item android:color="?attr/colorSecondary" android:state_checked="true"/>
24+
<!-- Unchecked -->
25+
<item android:color="@macro/m3_comp_radio_button_unselected_icon_color"
26+
android:state_checked="false"/>
27+
</selector>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
~ Copyright (C) 2025 The Android Open Source Project
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ http://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
<selector xmlns:android="http://schemas.android.com/apk/res/android">
18+
<!-- State Disabled, Unchecked -->
19+
<item
20+
android:alpha="@dimen/m3_comp_switch_disabled_track_opacity"
21+
android:color="@macro/m3_comp_switch_disabled_unselected_track_color"
22+
android:state_enabled="false" android:state_checked="false"/>
23+
<!-- State Disabled, Checked -->
24+
<item
25+
android:alpha="@dimen/m3_comp_switch_disabled_track_opacity"
26+
android:color="@macro/m3_comp_switch_disabled_selected_track_color"
27+
android:state_enabled="false" android:state_checked="true"/>
28+
<!-- State Checked -->
29+
<item
30+
android:color="?attr/colorSecondary"
31+
android:state_checked="true"/>
32+
<!-- State Unchecked -->
33+
<item
34+
android:color="@macro/m3_comp_switch_unselected_track_color"
35+
android:state_checked="false"/>
36+
</selector>

lib/java/com/google/android/material/listitem/res/values/styles.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,28 @@
106106
<item name="android:textAppearance">?attr/textAppearanceLabelSmall</item>
107107
</style>
108108

109+
<style name="Widget.Material3.Checkbox.ListItem" parent="Widget.Material3.CompoundButton.CheckBox">
110+
<item name="android:focusable">false</item>
111+
<item name="android:clickable">false</item>
112+
<item name="android:importantForAccessibility">no</item>
113+
<item name="android:background">@null</item>
114+
<item name="buttonTint">@color/m3_list_item_checkbox_button_tint_selector</item>
115+
</style>
116+
117+
<style name="Widget.Material3.Switch.ListItem" parent="Widget.Material3.CompoundButton.MaterialSwitch">
118+
<item name="android:focusable">false</item>
119+
<item name="android:clickable">false</item>
120+
<item name="android:importantForAccessibility">no</item>
121+
<item name="android:background">@null</item>
122+
<item name="trackTint">@color/m3_list_item_switch_track_tint_selector</item>
123+
</style>
124+
125+
<style name="Widget.Material3.RadioButton.ListItem" parent="Widget.Material3.CompoundButton.RadioButton">
126+
<item name="android:focusable">false</item>
127+
<item name="android:clickable">false</item>
128+
<item name="android:importantForAccessibility">no</item>
129+
<item name="android:background">@null</item>
130+
<item name="buttonTint">@color/m3_list_item_radio_button_tint_selector</item>
131+
</style>
132+
109133
</resources>

0 commit comments

Comments
 (0)