问题
How can I force a ChipGroup
to act like a RadioGroup
as in having at least one selected item always? Setting setSingleSelection(true)
also adds the possibility to have nothing selected if you click twice on a Chip
.
回答1:
A solution would be to preset a clicked chip and then toggling the clickable property of the chips:
chipGroup.setOnCheckedChangeListener((chipGroup, id) -> {
Chip chip = ((Chip) chipGroup.getChildAt(chipGroup.getCheckedChipId()));
if (chip != null) {
for (int i = 0; i < chipGroup.getChildCount(); ++i) {
chipGroup.getChildAt(i).setClickable(true);
}
chip.setClickable(false);
}
});
回答2:
There are two steps to achieve this
Step 1
We have this support built-in, just make sure to add app:singleSelection="true"
to your ChipGroup
, for example:
XML
<com.google.android.material.chip.ChipGroup
android:id="@+id/group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:singleSelection="true">
<com.google.android.material.chip.Chip
android:id="@+id/option_1"
style="@style/Widget.MaterialComponents.Chip.Choice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Option 1" />
<com.google.android.material.chip.Chip
android:id="@+id/option_2"
style="@style/Widget.MaterialComponents.Chip.Choice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Option 2" />
</com.google.android.material.chip.ChipGroup>
Code
// Kotlin
group.isSingleSelection = true
// Java
group.setSingleSelection(true);
Step 2
Now to support a radio group like functionality:
var lastCheckedId = View.NO_ID
chipGroup.setOnCheckedChangeListener { group, checkedId ->
if(checkedId == View.NO_ID) {
// User tried to uncheck, make sure to keep the chip checked
group.check(lastCheckedId)
return@setOnCheckedChangeListener
}
lastCheckedId = checkedId
// New selection happened, do your logic here.
(...)
}
From the docs:
ChipGroup also supports a multiple-exclusion scope for a set of chips. When you set the app:singleSelection attribute, checking one chip that belongs to a chip group unchecks any previously checked chip within the same group. The behavior mirrors that of RadioGroup.
回答3:
Brief modification of @adriennoir 's answer (in Kotlin). Thanks for the help!
Note that getChildAt()
takes an index.
for (i in 0 until group.childCount) {
val chip = group.getChildAt(i)
chip.isClickable = chip.id != group.checkedChipId
}
Here's my larger `setOnCheckedChangeListener, for context:
intervalChipGroup.setOnCheckedChangeListener { group, checkedId ->
for (i in 0 until group.childCount) {
val chip = group.getChildAt(i)
chip.isClickable = chip.id != group.checkedChipId
}
when (checkedId) {
R.id.intervalWeek -> {
view.findViewById<Chip>(R.id.intervalWeek).chipStrokeWidth = 1F
view.findViewById<Chip>(R.id.intervalMonth).chipStrokeWidth = 0F
view.findViewById<Chip>(R.id.intervalYear).chipStrokeWidth = 0F
currentIntervalSelected = weekInterval
populateGraph(weekInterval)
}
R.id.intervalMonth -> {
view.findViewById<Chip>(R.id.intervalWeek).chipStrokeWidth = 0F
view.findViewById<Chip>(R.id.intervalMonth).chipStrokeWidth = 1F
view.findViewById<Chip>(R.id.intervalYear).chipStrokeWidth = 0F
currentIntervalSelected = monthInterval
populateGraph(monthInterval)
}
R.id.intervalYear -> {
view.findViewById<Chip>(R.id.intervalWeek).chipStrokeWidth = 0F
view.findViewById<Chip>(R.id.intervalMonth).chipStrokeWidth = 0F
view.findViewById<Chip>(R.id.intervalYear).chipStrokeWidth = 1F
currentIntervalSelected = yearInterval
populateGraph(yearInterval)
}
}
}
回答4:
Most of the answers are great and really helpful for me. Another slight modification to @adriennoir and @Todd DeLand, to prevent unchecking already checked chip in a setSingleSelection(true)
ChipGroup, here's my solution:
for (i in 0 until chipGroup.childCount) {
val chip = chipGroup.getChildAt(i) as Chip
chip.isCheckable = chip.id != chipGroup.checkedChipId
chip.isChecked = chip.id == chipGroup.checkedChipId
}
For me, I just need to prevent the same checked Chip to be unchecked without making it non-clickable. This way, the user can still click the checked chip and see the fancy ripple effect and nothing will happen.
回答5:
This is how I did it:
var previousSelection: Int = default_selection_id
chipGroup.setOnCheckedChangeListener { chipGroup, id ->
if (id == -1) //nothing is selected.
chipGroup.check(previousSelection)
else
previousSelection = id
回答6:
This is my working solution
mChipGroup.setOnCheckedChangeListener((group, checkedId) -> {
for (int i = 0; i < mChipGroup.getChildCount(); i++) {
Chip chip = (Chip) mChipGroup.getChildAt(i);
if (chip != null) {
chip.setClickable(!(chip.getId() == mChipGroup.getCheckedChipId()));
}
}
});
回答7:
To prevent all chips from being deselected you can use the method setSelectionRequired
:
chipGroup.setSelectionRequired(true)
You can also define it in the layout using the app:selectionRequired
attribute:
<com.google.android.material.chip.ChipGroup
app:singleSelection="true"
app:selectionRequired="true"
app:checkedChip="@id/..."
..>
Note: This requires a minimum of version 1.2.0-alpha02
来源:https://stackoverflow.com/questions/53155035/chipgroup-single-selection