Preparing customized radio group type of layout
Asked Answered
W

7

17

I am trying to prepare custom radiogroup like layout in the below image. I have nearly 8-10 rows to do that. So, I prepared one linear layout which has horizontal orientation and added the imageview, textview and radiobutton programatically.

enter image description here

So if I check on one radio button, the other radio buttons should automatically unchecked. Before going to that task itself, I got another problem that if my radio buttons are checked once, then the radio button are not uncheckable though clicked on them. Below is my code.

public class MainActivity extends Activity{

RadioButton[] radioBtns = new RadioButton[10];

    String texts[] = {"text1", "text2", .... "text10"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);


        entireLayout = (LinearLayout)findViewById(R.id.main_layout);


        for(int i =0; i<10; i++)
        {
            LinearLayout rowLayout=new LinearLayout(this);
            radioBtns[i] = new RadioButton(this);

            radioBtns[i].setId(i);
            radioBtns[i].setOnCheckedChangeListener(cblistener);
            ImageView imageView = new ImageView(this);


            TextView tv = new TextView(this);
            tv.setText(texts[i]);

            rowLayout.addView(imageView);
            rowLayout.addView(tv);
                        rowLayout.addView(radioBtns[i]);

            entireLayout.addView(rowLayout);

                View line = new View(this); 
                line.setBackgroundColor(getResources().getColor(R.color.horizontallinecolor));
                entireLayout.addView(line, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, 1));


        }
         }

CompoundButton.OnCheckedChangeListener cblistener = new CompoundButton.OnCheckedChangeListener()
    {
      public void onCheckedChanged(CompoundButton checkedbutton, boolean paramAnonymousBoolean)
      {

        switch (checkedbutton.getId())
        {

        case 0:
          Log.d("tag", "checked 0th position");

          break;
          ..........................
          ..........................
        }
      }
     };
}

I have observed through keeping logs. The control enters onCheckedChanged() for the first time when those are getting checked, but not when unchecked. I wonder how those are uncheckable.

OR According to my requirement I have one more idea to prepare this layout like I prepare one more layout for the row in xml. Then inflating the view 10 times. But then also, how can I check only one radio button so that other selected one gets unchecked. Can someone please suggest me how to achieve this kind of radiogroup through the best way?

Note: I have kept my above code because to show what I have tried. If it is completely wrong way, please go easy and please suggest me how to get that done.

Wail answered 8/12, 2013 at 17:12 Comment(2)
Could you post the layout, please? So, to understand what you are trying to do more easily.Upsilon
@Klaus66 Thanks for your comment. I have nothing in the main layout except a linear layout. All I am doing is adding views dynamically which is in my above code already. I am trying to achieve what is shown in the image.Wail
K
7

In my experience is a little of a troublemaker to work with these kind of customized RadioGroups. I've prepared you some code that would be my approach to solve what you're trying to accomplish. Hope it works for you!

First you must call this function in your onCreate() (or wherever you're creating the views)

 private void addRadioButtons() {
    LinearLayout llGroup = (LinearLayout) findViewById(R.id.linearLayoutGroup);
    for(int i=0; i<10; i++){
        MyRadioButton mrb = new MyRadioButton(this);
        mrb.setText(String.valueOf(i));
        llGroup.addView(mrb.getView());
    }
}

The class should be

private static class MyRadioButton implements View.OnClickListener{

    private ImageView iv;
    private TextView tv;
    private RadioButton rb;
    private View view;

    public MyRadioButton(Context context) {

        view = View.inflate(context, R.layout.my_radio_button, null);
        rb = (RadioButton) view.findViewById(R.id.radioButton1);
        tv = (TextView) view.findViewById(R.id.textView1);
        iv = (ImageView) view.findViewById(R.id.imageView1);

        view.setOnClickListener(this);
        rb.setOnCheckedChangeListener(null);

    }


    public View getView() {
        return view;
    }

    @Override
    public void onClick(View v) {

        boolean nextState = !rb.isChecked();

        LinearLayout lGroup = (LinearLayout)view.getParent();
        if(lGroup != null){
            int child = lGroup.getChildCount();
            for(int i=0; i<child; i++){
                //uncheck all
                ((RadioButton)lGroup.getChildAt(i).findViewById(R.id.radioButton1)).setChecked(false);
            }
        }

        rb.setChecked(nextState);
    }

    public void setImage(Bitmap b){
        iv.setImageBitmap(b);
    }

    public void setText(String text){
        tv.setText(text);
    }

    public void setChecked(boolean isChecked){
        rb.setChecked(isChecked);
    }


}

And the xml to inflate, something like:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:orientation="horizontal" >
    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher" />
    <TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Medium Text"
        android:textAppearance="?android:attr/textAppearanceMedium" />
    <RadioButton
        android:id="@+id/radioButton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>
Kursk answered 8/12, 2013 at 18:44 Comment(7)
This code did the same what I already have got. My problem is if I once check the radiobutton, that button is not getting unchecked :( Please suggest.Wail
+1 and accepting your answer.Keeping clickable=false did the trick. I too posted answer. Thanks.Wail
This actually gives problem when the orientation is changed. Did you observe? Please suggest.Wail
The xml is only for illustration purposes. You can provide different resources for portrait/landscape mode, different dimensions to target screen sizes, among others. You must also be aware of configChanges in your activity. Regards.Kursk
It's not regarding the screen sizes or so. It's leaking resources when orientation is changed.Wail
configChanges should be checked in the manifest. If not handled, we must recreate the radiobuttons 'cause we're passing down a reference to activity's context which is being destroyed (because of the config change). Happy new year, folk!Kursk
how to get checked item text??Tripodic
F
5

A bit late to answer, but I meet with the same problem and out of frustration I wrote a new class called RadioGroupPlus to solve this problem, and I wanted to share.

The repo can be found here: https://github.com/worker8/RadioGroupPlus/

How to install

Add the library in your top level build.gradle:

allprojects {
    repositories {
        maven { url "https://jitpack.io" }
    }
}

In your app/build.gradle, add this as dependency:

compile 'com.github.worker8:RadioGroupPlus:v1.0.1'

How to use

In your xml, wrap your custom layout with <worker8.com.github.radiogroupplus.RadioGroupPlus, such as:

<worker8.com.github.radiogroupplus.RadioGroupPlus
    android:id="@+id/radio_group_plus"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
        <LinearLayout...>
           <ImageView...>
           <TextView...>
           <RadioButton...>
        </LinearLayout>
        <LinearLayout...>
           <ImageView...>
           <TextView...>
           <RadioButton...>
        </LinearLayout>
        <LinearLayout...>
           <ImageView...>
           <TextView...>
           <RadioButton...>
        </LinearLayout>
</worker8.com.github.radiogroupplus.RadioGroupPlus>

I leave out the details on purpose so that it's easier to read. I wrote more information about how to use RadioGroupPlus in the README page. Besides I also write a simple example of how to use it. So if you need to know more, you can learn more in the RadioGroupPlus repo.

Hope it helps!

Flite answered 29/12, 2015 at 15:23 Comment(5)
The library doesn't seem to work when the children are custom views containing RadioButtons, for example: <RadioGroupPlus> <CustomRadioButton/> <CustomRadioButton/> <CustomRadioButton/> ... </RadioGroupPlus>Lytton
@EduBarbas, is your CustomRadioButton extending from RadioButton? It should only work if CustomRadioButton is inherited from RadioButton. Take a look at traverseTree() in RadioGroupPlus.java. It does this: view instanceof RadioButton. You can try copying RadioGroupPlus.java into your project, and change all RadioButton found in the file to CustomRadioButton, I haven't try it, but it might work.Plumlee
My custom view is pretty similar to the one used in the opening question of this thread - a radio button to the left, some text in the center, and an image view to the right, with only one subtle difference: I'm using data binding in that custom view. I tried to add my view's layout directly inside a <RadioGroupPlus>, and worked fine. Could that be causing the issue?Lytton
Forgot to mentioned: I added my view's layout directly inside a <RadioGroupPlus> WITHOUT data binding, and worked fine. I will look into the code and see if I can find something :-)Lytton
Ohh I see, it will be great to take a look at the code to find out yourself since I cannot see it. Anyhow, if you cannot solve it, you can fork the repo in Github and include your layout with data binding in another branch, then I can take a look too. I have no experience with data binding, so I am not sure what's wrong at the moment.Plumlee
M
2

The tricky part is that you want the button to be on the right side.
To do that, in each button I deleted the original button and set the Right drawable as the button.
Nothing to say for the Left drawable.

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffff"
    android:padding="8dp"
    >
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:padding="4dp"
        >
        <RadioGroup
            android:layout_gravity="center_horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/rgOne"
            >
            <RadioButton
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/rdo1"
                android:text="RadioButton 1"
                android:button="@null"
                android:drawableRight="@android:drawable/btn_radio"
                android:drawableLeft="@drawable/ic_launcher"
                android:checked="true"
                android:onClick="onRadioButtonClicked"
            />
            <RadioButton
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/rdo2"
                android:text="RadioButton 2"
                android:button="@null"
                android:drawableRight="@android:drawable/btn_radio"
                android:drawableLeft="@drawable/ic_launcher"
                android:onClick="onRadioButtonClicked"
            />
            <RadioButton
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/rdo3"
                android:text="RadioButton 3"
                android:button="@null"
                android:drawableRight="@android:drawable/btn_radio"
                android:drawableLeft="@drawable/ic_launcher"
                android:onClick="onRadioButtonClicked"
            />
        </RadioGroup>
    </RelativeLayout>
</RelativeLayout>

And this is the code:

package com.example.aaa;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;

public class MainActivity
extends Activity
{

    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // If you need to fire RadioButtonClick event:
        onRadioButtonClicked(findViewById(R.id.rdo1));
        // Otherwise, remove previous line
    }

    public final void onRadioButtonClicked(final View v)
    {
        String str = "1";
        switch(v.getId())
        {
            case R.id.rdo1:
            {
                // do something
                str = "1";
                break;
            }
            case R.id.rdo2:
            {
                // do something
                str = "2";
                break;
            }
            case R.id.rdo3:
            {
                // do something
                str = "3";
                break;
            }
            default:
            {
                // do something
                str = "that doesn' exist";
                break;
            }
        }
        Toast.makeText
        (
            getApplicationContext(), "RadioButton " + str, Toast.LENGTH_LONG
            ).show();
    }
}
Maple answered 8/12, 2013 at 20:4 Comment(2)
Thanks for your answer. I already got that layout with my code in the question. But My problem is if I once check the radiobutton, that button is not getting unchecked.Wail
If you were to use my layout, the check moves from a radiobutton to the other. That is, you'll never ever have COMPLETE EMPTYNESS in the RadioGroup (no radiobutton checked). Althogh you don't force all RadioButtons to be unchecked (you make a loop in code and set checked = false).Upsilon
M
2

I edited the layout removing the second part, which was useless for your purpose.
If you look at the layout, you will see what is the trick to put the button on the right.
This can be made in code, too, if you don't want to use the layout (why?)
Using my layout (without the need for a cusom class), the result you'd get is...

enter image description hereenter image description hereenter image description here

Quite similar to your goal, isn't it?

The tricky lines you'll want to replicate in your code (again, why?) are:

android:button="@null"
android:drawableRight="@android:drawable/btn_radio" // or your selector, with custom on/off pngs
android:drawableLeft="@drawable/ic_launcher" // or whatever
Maple answered 9/12, 2013 at 11:25 Comment(2)
Thank you so much for your effort. I posted my answer. +1 for your both answers :)Wail
Thank you. I like to help, every time I can.Upsilon
S
2

It's not difficult to implement your custom RadioGroup class to fit your requirements. Also you can implement a custom RadioButton. Having custom components defined makes it easier to extend and bypass restrictions of default components.

I have described the process of creating a custom RadioGroup and a custom RadioButton in this tutorial. Also I have uploaded my code to Github.

Selfpropulsion answered 14/6, 2017 at 6:24 Comment(0)
T
0

Answer by @Junior Buckeridge worked for me. I just want to add my 2 cents to that. In case if you have any clickable views in your linear layout make sure you add android:descendantFocusability="blocksDescendants" to your linear layout and android:focusable="false" to your view(Can be a button,Radio Button etc)

Timaru answered 1/6, 2016 at 15:31 Comment(0)
H
0

I had the same layout as you but the number of rows in my case was limited by four. And I found out that the easiest way to make radioButtons work together is to use the simple method that will loop through array of radioButtons and check ALL of them OFF and then check ON the one which is needed.

And that's all folks (c)

You don't need to use regular RadioGroup neither creating custom radio group class, you don't need to setOnCheckChangedListeners.

    final RadioButton radio1 = (RadioButton) findViewById(R.id.radio_1);
    final RadioButton radio2 = (RadioButton) findViewById(R.id.radio_2);
    final RadioButton radio3 = (RadioButton) findViewById(R.id.radio_3);
    final RadioButton radio4 = (RadioButton) findViewById(R.id.radio_4);

    final RadioButton[] radios = {radio1, radio2, radio3, radio4};

    View.OnClickListener buttonListener = new View.OnClickListener(){
        @Override
        public void onClick(View v) {
            for(RadioButton radio : radios){
                radio.setChecked(false);
            }

            switch (v.getId()){
                case R.id.button_1:
                    radio1.setChecked(true);
                    break;
                case R.id.button_2:
                    radio2.setChecked(true);
                    break;
                case R.id.button_3:
                    radio3.setChecked(true);
                    break;
                case R.id.button_4:
                    radio4.setChecked(true);
                    break;
            }
        }
    };


    RelativeLayout button1 = (RelativeLayout) findViewById(R.id.button_1);
    button1.setOnClickListener(buttonListener);

    RelativeLayout button2 = (RelativeLayout) findViewById(R.id.button_2);
    button2.setOnClickListener(buttonListener);

    RelativeLayout button3 = (RelativeLayout) findViewById(R.id.button_3);
    button3.setOnClickListener(buttonListener);

    RelativeLayout button4 = (RelativeLayout) findViewById(R.id.button_4);
    button4.setOnClickListener(buttonListener);

*Hint: Don't forget to set

android:text=""
android:checked="false"
android:clickable="false"

to your layout to each RadioButton. And set initial state programmatically for that radioButton which should be checked.

Herculaneum answered 24/4, 2018 at 15:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.