安卓:自定义列表视图中的单选按钮

25

我正在开发一个应用程序,需要在列表视图中实现单选按钮。我想要实现一个列表视图,每行有一个单选按钮和两个文本视图。并且在列表视图下方有一个“确定”按钮。

我已经创建了一个列表视图和一个自定义适配器。 列表视图的代码如下:

<ListView
    android:id="@+id/listview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:cacheColorHint="#00000000"
    android:overScrollMode="never"
    tools:ignore="NestedScrolling"
    android:choiceMode="singleChoice" >
</ListView>

我创建了一个自定义适配器布局:

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <TableRow
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        tools:ignore="UselessParent" >

        <RadioButton
            android:id="@+id/radiobutton"
            android:layout_width="0sp"
            android:layout_height="wrap_content"
            android:layout_weight=".1" />

        <TextView
            android:id="@+id/textview1"
            android:layout_width="0sp"
            android:layout_height="wrap_content"
            android:layout_weight=".3" />

        <TextView
            android:id="@+id/textview2"
            android:layout_width="0sp"
            android:layout_height="wrap_content"
            android:layout_weight=".3" />

    </TableRow>

</TableLayout>

片段的Java代码如下:

ListView listView = (ListView) view.findViewById(R.id.listview);

// values is a StringArray holding some string values.
CustomAdapter customAdapter = new CustomAdapter (getActivity(), values);
listView.setAdapter(customAdapter );
listView.setOnItemClickListener(this);

@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {}

适配器的代码如下:

public class CustomAdapter extends ArrayAdapter<String> {   
    /** Global declaration of variables. As there scope lies in whole class. */
    private Context context;
    private String[] listOfValues;

    /** Constructor Class */
    public CustomAdapter (Context c,String[] values) {
        super(c,R.layout.adapter_layout,values);
        this.context = c;
        this.listOfValues = values;
    }

    /** Implement getView method for customizing row of list view. */
    public View getView(final int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = ((Activity)context).getLayoutInflater();
        // Creating a view of row.
        View rowView = inflater.inflate(R.layout.adapter_layout, parent, false);
            
            TextView textView1 = (TextView)rowView.findViewById(R.id.textview1);
            TextView textView2 = (TextView)rowView.findViewById(R.id.textview2);

            RadioButton radioButton = (RadioButton) rowView.findViewById(R.id.radiobutton);

            radioButton.setOnClickListener(new OnClickListener() {          
            @Override   
            public void onClick(View v) {
                Toast.makeText(context, CustomAdapter[position], Toast.LENGTH_SHORT).show();
            }
        });
    
        return review;
    }
}    

文本视图1的数据来自SQLite数据库,文本视图2的数据为“状态关闭”。当选择某个单选按钮或点击它时,文本视图的文本将更改为“状态打开”。

问题是:应用程序的需求是只能选择一个单选按钮,选择后文本视图2的数据会更改。当用户点击其他单选按钮时,前一个单选按钮应该取消选择,并且先前选择的单选按钮的文本视图2的文本应更改为“状态关闭”,而点击的单选按钮的文本视图2的文本应更改为“状态打开”。

编辑1:

并且在单击“确定”按钮后,我希望获取列表视图文本视图1和文本视图2的位置和文本,因为我想将该文本保存在审核中的SQLite数据库中。

请指导我应该按照什么步骤执行。我正在我的应用程序中间。需要您宝贵的指导。

2个回答

79

以下是关键思想:

  • 当一个RadioButton被选中时,我们必须调用notifyDataSetChanged()方法,以便更新所有视图。
  • 当一个RadioButton被选中时,我们必须设置一个selectedPosition来跟踪哪个RadioButton被选中。
  • Views在ListView内部被循环使用。 因此,它们在ListView中的绝对位置会发生变化。因此,在ListAdapter#getView()内部,我们必须对每个RadioButton调用setTag()方法。这允许我们确定单击RadioButton时其在列表中的当前位置。
  • 对于新的或预先存在的Views,必须在getView()内更新RadioButton#setChecked()方法。

以下是我编写并测试过的一个示例ArrayAdapter,以演示这些思想

public class MainActivity extends ListActivity {

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

        // I do no use these values anywhere inside the ArrayAdapter. I could, but don't.
        final Integer[] values = new Integer[] {1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,};

        ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(this, R.layout.row, R.id.textview, values) {

            int selectedPosition = 0;

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View v = convertView;
                if (v == null) {
                    LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                    v = vi.inflate(R.layout.row, null);
                    RadioButton r = (RadioButton)v.findViewById(R.id.radiobutton);
                }
                TextView tv = (TextView)v.findViewById(R.id.textview);
                tv.setText("Text view #" + position);
                RadioButton r = (RadioButton)v.findViewById(R.id.radiobutton);
                r.setChecked(position == selectedPosition);
                r.setTag(position);
                r.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        selectedPosition = (Integer)view.getTag();
                        notifyDataSetChanged();
                    }
                });
                return v;
            }

        };
        setListAdapter(adapter);
    }
}

谢谢您的建议。但是我现在仍然遇到困难。我是新手,所以我编辑了我的问题。现在,您能告诉我在哪里放置这段代码,以及如何使用它吗?您的指导对我非常有价值。 - Manoj Fegde
我已经添加了额外的代码来展示我如何使用ArrayAdapter。你应该能够从我的代码中得到一个工作的应用程序,然后修改它以适应你的目的。 - Brian Attwell
谢谢您的建议。我已经完成了您的指导。 - Manoj Fegde
1
不要使用notifyDataSetInvalidated()方法,它会使你的ListView失效并从顶部显示列表,请使用notifyDataSetChanged()方法。 - Sher Ali
1
Brian,非常好用!感谢提供这些信息。我能够在新的recyclerview上使用它而没有任何问题。 - Ray Hunter
显示剩余5条评论

2
尝试使用以下适配器:
public class ChooseAdapter extends ArrayAdapter<LinkedHashMap<String, String>> {
private ArrayList<LinkedHashMap<String, String>> listMenu;

int position_id;

private LayoutInflater inflater;
Context context;

public ChooseAdapter(Activity activity,
        ArrayList<LinkedHashMap<String, String>> listMenu, int type) {

    super(activity, R.layout.choose_single_item, listMenu);
    this.listMenu = listMenu;

    context = activity.getApplicationContext();
    inflater = LayoutInflater.from(context);

}

public int getCount() {
    return listMenu.size();
}

public long getItemId(int position) {
    return position;

}

public static class ViewHolder

{
    public CheckBox chk;

}

public View getView(final int position, View convertView, ViewGroup parent) {
    final ViewHolder view;

    if (convertView == null) {

        view = new ViewHolder();

        convertView = inflater.inflate(R.layout.choose_single_item, null);
        view.chk = (CheckBox) convertView
                .findViewById(R.id.selection_checkbox);

        view.chk.setOnCheckedChangeListener(new OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton buttonView,
                    boolean isChecked) {
                // TODO Auto-generated method stub
                if (isChecked) {

                    listMenu.get((Integer) buttonView.getTag()).put(
                            "checked", "true");
                    for (int i = 0; i < listMenu.size(); i++) {
                        if (i != (Integer) buttonView.getTag()) {
                            if (listMenu.get(i).containsKey("checked"))
                                listMenu.get(i).remove("checked");
                        }
                    }
                } else {
                    listMenu.get((Integer) buttonView.getTag()).remove(
                            "checked");
                }

                notifyDataSetChanged();
            }
        });

        convertView.setTag(R.id.selection_checkbox, view.chk);
        convertView.setTag(view);

    }

    else {
        view = (ViewHolder) convertView.getTag();
    }
    view.chk.setTag(position);

    view.chk.setText(listMenu.get(position).get("name"));

    if (listMenu.get(position).containsKey("checked")) {
        view.chk.setChecked(true);
    } else
        view.chk.setChecked(false);

    return convertView;

}
}

我需要翻译的内容是:

我正在加载的布局是:

<?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:orientation="horizontal" >

<CheckBox
    android:id="@+id/selection_checkbox"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:text="abc"
    android:textColor="#8C8C8C"
    android:textSize="16sp" />

</LinearLayout>

这里我使用了复选框,您也可以使用单选按钮代替它,不需要做其他更改。
希望这有所帮助!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接