In Android, given a ListView of items with TextView and RadioGroup, how to add items dynamically?

I need to manage a ListView, so that each item has a textView and a RadioGroup. Following is the xml file for one item: controls_layout_row.xml:

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     android:orientation="vertical"     android:padding="20dp"     android:background="@drawable/fragment_template"     android:layout_width="match_parent"     android:layout_height="wrap_content">      <TextView         android:id="@+id/control_name"         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:textColor="#ffffff"         android:textSize="20sp"         android:textStyle="bold"         android:layout_marginBottom="5dp"/>      <RadioGroup         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:layout_below="@id/control_name"         android:id="@+id/control_options_list"         android:layout_marginBottom="20dp"         tools:layout_height="150dip">         <!-- items added within code -->     </RadioGroup>  </RelativeLayout> 

The items are part of a ListView – following is the xml file for the ListView:

controls_dialog.xml:

<?xml version="1.0" encoding="utf-8"?>  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     android:orientation="vertical"     android:padding="20dp"     android:background="@drawable/fragment_template"     android:layout_width="match_parent"     android:layout_height="wrap_content">      <TextView         android:id="@+id/controls_list_title"         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:textColor="#ffffff"         android:text="Controls"         android:textSize="20dp"         android:textStyle="bold"         android:layout_marginBottom="5dp"/>      <ListView         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:layout_below="@id/controls_list_title"         android:id="@+id/controls_list"         tools:layout_height="150dip">         <!-- items added within code -->     </ListView>      //Close button     <Button android:id="@+id/controls_close_button"         android:layout_below="@id/controls_list"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:textSize="14dp"         android:text="Close"         android:layout_alignParentEnd="true"         android:textAllCaps="false"         android:textStyle="bold"/> </RelativeLayout> 

Now, the items are not known at the beginning. The application uses JNI interface to get info from connected hardware, and then some getters are used in the activity in order to know which items must appear in the dialog. I have tried 2 methods, and I got stuck in both of them.

First method: simply create some item each time I need and add its view to the list:

    // retrieve item view     final View emittersRowView = inflater.inflate(R.layout.controls_layout_row, null);     // set TextView     final TextView emitterTitle = emittersRowView.findViewById(R.id.control_name);     emitterTitle.setText("Projector");     //set RadioGroup     final String emitterDescriptions[] = getOptionDescriptions(Option.EMITTER_ENABLED);     final RadioGroup emittersRadioGroup = emittersRowView.findViewById(R.id.control_options_list);     // adding buttons to the group     for(int i = 0; i < emitterDescriptions.length; ++i) {         RadioButton button = new RadioButton(activity);         button.setId(i);         button.setText(emitterDescriptions[i]);         button.setTextColor(getResources().getColor(R.color.white));         button.setChecked(i == indexOfCurrentEmitter);         emittersRadioGroup.addView(button);     }      emittersRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener(){         @Override         public void onCheckedChanged(RadioGroup group, int checkedId) {             List<Sensor> sensors = mDevice.querySensors();             for (Sensor s : sensors) {                 if (s.supports(Option.EMITTER_ENABLED)) {                     s.setValue(Option.EMITTER_ENABLED, checkedId);                 }             }         }     });      //add control to list     ListView controlsList = fragmentView.findViewById(R.id.controls_list);     controlsList.addView(emittersRowView); 

This method did not work. I have read in other forums that this cannot work without using an adpater. This seems weird to me, because using the addView method on the RadioGroup object, in order to add RadioButton objects works great.

Second Method: Using a Custom Adapter: I have defined an adpater and my plan was to first build:

  • a String array for the TextView objects
  • a list of RadioGroup objects for the RadioGroup objects and then use them for creating the adapter. But when I got to the code, I got stuck, no knowing how to set the RadioGroup in the adapter:

Code for the adapter:

   class CustomAdapter extends BaseAdapter {      @Override     public int getCount() {         return numOfControls;     }      @Override     public Object getItem(int position) {         return null;     }      @Override     public long getItemId(int position) {         return 0;     }      @Override     public View getView(int position, View convertView, ViewGroup parent) {         final Activity activity = getActivity();         convertView = activity.getLayoutInflater().inflate(R.layout.controls_layout_row, null);          TextView control_name = convertView.findViewById(R.id.control_name);         RadioGroup control_options = convertView.findViewById(R.id.control_options_list);          control_name.setText(mControlNames[i]);         control_options.set....???         return convertView;     } } 

Please help me to make it work.

Add Comment
1 Answer(s)

Start a new project and try below complete sample code,

MainActivity.java:

public class MainActivity extends AppCompatActivity {  class Control {     String name;     String[] options;     int checkedPosition = -1;      public Control(String name, String[] options) {         this.name = name;         this.options = options;     }     public String getName() {         return name;     }     public String[] getOptions() {         return options;     }     public int getCheckedPosition() {         return checkedPosition;     }     public void setCheckedPosition(int checkedPosition) {         this.checkedPosition = checkedPosition;     } }  Control[] controls = new Control[10];  @Override protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.activity_main);      ListView controlsList = findViewById(R.id.controls_list);     createSampleData();     CustomAdapter adapter = new CustomAdapter(this, 0, controls);     controlsList.setAdapter(adapter);      Button button = findViewById(R.id.controls_close_button);     button.setOnClickListener(new View.OnClickListener() {         @Override         public void onClick(View view) {             String msg = "";             for (int i = 0; i < controls.length; i++) {                 msg += controls[i].getName() + " , " + controls[i].getCheckedPosition() + "\n";             }             Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();         }     }); }  private void createSampleData() {     Random random = new Random();     for (int i = 0; i < controls.length; i++) {         int j = random.nextInt(4) + 2;         String[] options = new String[j];         for (int k = 0; k < j; k++) {             options[k] = (i + 1) + "-" + k;         }         controls[i] = new Control("Control " + (i + 1), options);     } } } 

CustomAdapter.java:

public class CustomAdapter extends ArrayAdapter {  Context context; LayoutInflater inflater;  public CustomAdapter(@NonNull Context context, int resource, @NonNull MainActivity.Control[] objects) {     super(context, resource, objects);     this.context = context;     inflater = LayoutInflater.from(context); }  @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {     convertView = inflater.inflate(R.layout.controls_layout_row, null);      TextView control_name = convertView.findViewById(R.id.control_name);     RadioGroup control_options = convertView.findViewById(R.id.control_options_list);      MainActivity.Control control = (MainActivity.Control)getItem(position);     control_name.setText(control.getName());      String[] options = control.getOptions();     for(int i = 0; i < options.length; i++) {         RadioButton button = new RadioButton(context);         button.setId(i);         button.setText(options[i]);         button.setTextColor(Color.WHITE);         button.setChecked(i == control.getCheckedPosition());         control_options.addView(button);     }     control_options.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {         @Override         public void onCheckedChanged(RadioGroup radioGroup, int i) {             int pos = (int)radioGroup.getTag();             MainActivity.Control changedControl = (MainActivity.Control)getItem(pos);             changedControl.setCheckedPosition(i);         }     });     control_options.setTag(position);      return convertView; } } 

use your posted layouts.

Answered on July 16, 2020.
Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.