简体   繁体   中英

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM