button single selection

Java/Android – Single Selection for CompoundButtons!

Sometimes the seemingly simplest implementations cause us a lot of trouble. While working on my last Android project I decided to create a single selection helper class I could implement in any Project.

Java/Android – Single Selection for CompoundButtons!

Welcome to our first coverage of the Android ecosystem. Today we will write a helper class to manage the selection of a single item within our application.

The following guide can be used for any CompoundButton (RadioButtons, ToggleButtons, CheckBoxes, and Switches!).

Normally we would just use a bunch of RadioButtons inside a RadioGroup, but this is not always an option. Sometimes we have to use nested layouts, and sometimes we just don’t want to use RadioButtons.

Let’s create a new project and get started!

First, let’s look at the problem:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/viewgroupparent"
    tools:context=".MainActivity">
    <RadioGroup
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:orientation="horizontal">
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:orientation="horizontal">
                    <RadioButton
                        android:id="@+id/radioButton1"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:tag="btn1"
                        android:text="RadioButton1" />
                </LinearLayout>
                <RadioButton
                    android:id="@+id/radioButton2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:tag="btn2"
                    android:text="RadioButton2" />
            </LinearLayout>
            <RadioButton
                android:id="@+id/radioButton3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:tag="btn3"
                android:text="RadioButton3" />
        </LinearLayout>
    </RadioGroup>
</androidx.constraintlayout.widget.ConstraintLayout>

This should be working right? Well, it doesn’t. The RadioGroup does not manage to group the Buttons. Maybe someone thought this is not something we need.

Output:

bad result no single selection

As you can see using a RadioGroup here is absolutely pointless. It does not do anything, every RadioButton acts independently!

Now I will show you one of the ways to get the expected behavior.

Create a new class inside your project and call it Help.java

This class will consist of 2 methods. One will take a ViewGroup as a parameter and return all CompoundButtons within this ViewGroup and the second method will take care of unselecting all Buttons except the selected one!

The ViewGroup should always be the highest Layout in the hierarchy, in this case, it is the ConstraintLayout.

Now let’s implement the helping class:

public class Help {

    public static void setButtonSingleClick(ViewGroup parent) {

        final List<CompoundButton> buttons = getButtons(parent);
        for (CompoundButton button : buttons) {
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    CompoundButton r = (CompoundButton) v;
                    if (r.isChecked()) {
                        for (CompoundButton r2 : buttons) {
                            if (r2.getTag() != r.getTag()) {
                                r2.setChecked(false);
                            }
                        }
                    }
                }
            });
        }
    }

    public static List<CompoundButton> getButtons(ViewGroup parent) {

        List<CompoundButton> buttons = new ArrayList<CompoundButton>();
        for (int i = 0; i < parent.getChildCount(); i++) {
            View v = parent.getChildAt(i);
            if (v instanceof CompoundButton) {
                buttons.add((CompoundButton) v);
            } else if (v instanceof ViewGroup) {
                List<CompoundButton> nestedButtons = getButtons((ViewGroup) v);
                buttons.addAll(nestedButtons);
            }
        }
        return buttons;
    }
}

and call it:

public class MainActivity extends AppCompatActivity {

    ViewGroup parent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        parent=findViewById(R.id.viewgroupparent);
        Help.setButtonSingleClick(parent);
    }
}

A brief note: This class works with getTag(), so make sure either your Buttons have unique Tags or change the method to use getId() instead.

Now we have the desired output:

desired output single selection

And this is it! You can remove the RadioGroup from activity_main.xml and just work with Buttons instead.

Conclusion

This is a very simple method for a single selection. There are many ways to get the desired output but this class can be implemented almost everywhere.

It can be used inside a RecyclerView as well, just call it inside onBindViewHolder and inside onScrollChange. Just be careful, it will only find visible Buttons inside a RecyclerView!

In the future, we will talk about Multi Selection aswell.

Here you can read more about CompoundButtons.

1 thought on “Java/Android – Single Selection for CompoundButtons!”

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: