带有微调器和复选框的 Android Listview

Posted

技术标签:

【中文标题】带有微调器和复选框的 Android Listview【英文标题】:Android Listview with spinner and a checkbox 【发布时间】:2011-04-26 12:38:40 【问题描述】:

我是安卓开发的新手。我正在尝试创建一个具有微调器、编辑文本和复选框的列表。微调器和复选框的数据来自数据库。我有以下文件。

NewTransac class which extends ListActivity 

private PayDbAdapter mDbHelper;
private  Spinner paySpinner;
private CheckBox mCheckBox;

@Override
protected void onCreate(Bundle savedInstanceState) 
     super.onCreate(savedInstanceState);
     setContentView(R.layout.new_transac_listview);
     mDbHelper = new PayDbAdapter(this);
     mDbHelper.open();

     populatedata();


private void populatedata() 

    paySpinner = (Spinner)findViewById(R.id.payerspinner);
    mCheckBox = (CheckBox)findViewById(R.id.paidforcheckboxname);

    Cursor mCursor = mDbHelper.fetchAllTransactionValue();
    startManagingCursor(mCursor);

    // Create an array to specify the fields we want to display in the list.
    String[] from = new String[]PayDbAdapter.KEY_NAME;

    int[] to = new int[]android.R.id.text1;
    int[] cbto = new int[]R.id.paidforcheckboxname;

    // Now create a simple cursor adapter and set it to display
    SimpleCursorAdapter adapter =
        new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item, mCursor, from, to );

    adapter.setDropDownViewResource( android.R.layout.simple_spinner_dropdown_item );
    paySpinner.setAdapter(adapter);

    SimpleCursorAdapter cbAdapter =
        new SimpleCursorAdapter(this, R.layout.show_new_transac_data, mCursor, from, cbto );
    setListAdapter(cbAdapter);

列表视图xml

<ListView android:id="@android:id/list"
    android:layout_
    android:layout_
    android:layout_weight="1"
    android:drawSelectorOnTop="false"
    android:textSize="14sp"
/>

<TextView android:id="@android:id/empty"
    android:layout_
    android:layout_
    android:text="@string/no_friends"
    android:textSize="14sp"
/>

<Button android:id="@+id/confirmpay" 
    android:text="@string/confirm"
    android:layout_
    android:layout_ 
    android:gravity="center_vertical|center_horizontal" 
    android:layout_gravity="center_vertical|center_horizontal|center">
</Button>

列表视图填充xml

<TextView
    style="?android:attr/listSeparatorTextViewStyle"
    android:text="@string/listSeparatorPay"
    android:layout_marginTop="5dip"
    android:layout_marginBottom="5dip"
/>

<Spinner android:id="@+id/payerspinner"
    android:layout_
    android:layout_
    android:drawSelectorOnTop="true"
    android:prompt="@string/selectpayer"
/>

<TextView android:layout_
    android:layout_ 
    android:text="@string/paytext"
/>

<EditText android:id="@+id/payamount" 
    android:layout_
    android:layout_ 
    android:layout_weight="1" 
    android:inputType="text"
/>

<TextView
    style="?android:attr/listSeparatorTextViewStyle"
    android:text="@string/listSeparatorPayedFor"
    android:layout_marginTop="5dip"
    android:layout_marginBottom="5dip"
/>

<CheckBox android:id="@+id/paidforcheckboxname"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
/>

<EditText android:id="@+id/paidforamount"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:inputType="number"
/>

Problem 我根据数据库中的字段数获得多个微调器、复选框和编辑文本。我看到我们无法为复选框设置适配器,就像我为微调器设置的那样。 我只需要一个带有一个编辑文本和多个复选框(数据库行总数)的微调器。请帮忙!

【问题讨论】:

我还在等待回复。需要帮助! 【参考方案1】:

编辑 - 请参阅 cmets,此解决方案可能不正确

我知道这个问题很古老,但它是 Google 上的第一个结果,我正在开发一个在 ListView 中使用 Spinners 的应用程序。我使用了来自here 的一些示例代码来开始。我希望这个例子能回答你的问题。我没有实现 CheckBoxes,但它们与 Spinner 非常相似——事实上要容易得多。这个例子有一个 ListView 和一个 TextView 和一个 Spinner。每当用户更改微调器中的选择时,TextView 都会更改以反映这一点。

我把这个项目分为 3 类:

ListViewTestActivity - 主要活动 DataAdapter - 扩展 ArrayAdapter 并用于在 ListView 中显示元素 DataHolder - 仅包含有关元素的一些信息的简单对象。这可以通过许多其他方式来满足您的需求。

我还修改/创建了 3 个关键的 Android XML 文件:

main.xml - 修改 - 主布局 rowview.xml - 添加 - ListView 中每个元素的布局 strings.xml - 修改 - 默认 Android 字符串文件

自下而上,这个 main.xml 文件只包含一个 ListView,没有其他内容:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" 
    android:layout_ android:layout_>
    <ListView android:id="@+id/listView1" android:layout_ android:layout_ />
</LinearLayout>

这里是rowview.xml。请记住,对于 ListView 中的每一行,此视图都是重复的:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_
    android:layout_ android:weightSum="1">
    <TextView android:layout_
        android:layout_ android:id="@+id/text"
        android:layout_weight="0.5" android:textSize="25sp" />
    <Spinner android:layout_ android:layout_
        android:id="@+id/spin" android:prompt="@string/choice_prompt"
        android:layout_weight="0.5" />
</LinearLayout>

strings.xml 文件。我添加的只是微调器内容的数组:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, ListViewTestActivity!</string>
    <string name="app_name">ListViewTest</string>
    <string name="choice_prompt">Select a choice</string>
    <string-array name="choices">
        <item>Alpha</item>
        <item>Bravo</item>
        <item>Charlie</item>
    </string-array>
</resources>

现在是有趣的东西。 ListViewActivity 类:

public class ListViewTestActivity extends Activity 

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

        ListView listView = (ListView) findViewById(R.id.listView1);

        DataHolder data = new DataHolder(this);
        DataHolder data1 = new DataHolder(this);
        DataHolder data2 = new DataHolder(this);
        DataHolder data3 = new DataHolder(this);
        DataHolder data4 = new DataHolder(this);

        DataAdapter d = new DataAdapter(this, R.layout.rowview, new DataHolder[]  data, data1, data2, data3, data4 );

        listView.setAdapter(d);
    

这很简单,你只需获取列表,创建一个新的适配器,然后将 ListView 的适配器设置为你创建的那个。这是 DataHolder 类:

public class DataHolder 

    private int selected;
    private ArrayAdapter<CharSequence> adapter;

    public DataHolder(Context parent) 
        adapter = ArrayAdapter.createFromResource(parent, R.array.choices, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    

    public ArrayAdapter<CharSequence> getAdapter() 
        return adapter;
    

    public String getText() 
        return (String) adapter.getItem(selected);
    

    public int getSelected() 
        return selected;
    

    public void setSelected(int selected) 
        this.selected = selected;
    


DataHolder 类所做的只是保存 Spinner 的适配器以及您可能希望为 ListView 中的每个条目存储的任何其他信息(例如,您可能希望存储它是否被选中)。最后是应用程序真正的“肉”,DataAdapter 类:

public class DataAdapter extends ArrayAdapter<DataHolder> 

    private Activity myContext;

    public DataAdapter(Activity context, int textViewResourceId, DataHolder[] objects) 
        super(context, textViewResourceId, objects);
        myContext = context;
    

    // We keep this ViewHolder object to save time. It's quicker than findViewById() when repainting.
    static class ViewHolder 
        protected DataHolder data;
        protected TextView text;
        protected Spinner spin;
    

    @Override
    public View getView(int position, View convertView, ViewGroup parent) 
        View view = null;

        // Check to see if this row has already been painted once.
        if (convertView == null) 

            // If it hasn't, set up everything:
            LayoutInflater inflator = myContext.getLayoutInflater();
            view = inflator.inflate(R.layout.rowview, null);

            // Make a new ViewHolder for this row, and modify its data and spinner:
            final ViewHolder viewHolder = new ViewHolder();
            viewHolder.text = (TextView) view.findViewById(R.id.text);
            viewHolder.data = new DataHolder(myContext);
            viewHolder.spin = (Spinner) view.findViewById(R.id.spin);
            viewHolder.spin.setAdapter(viewHolder.data.getAdapter());

            // Used to handle events when the user changes the Spinner selection:
            viewHolder.spin.setOnItemSelectedListener(new OnItemSelectedListener() 

                @Override
                public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) 
                    viewHolder.data.setSelected(arg2);
                    viewHolder.text.setText(viewHolder.data.getText());
                

                @Override
                public void onNothingSelected(AdapterView<?> arg0) 
                

            );

            // Update the TextView to reflect what's in the Spinner
            viewHolder.text.setText(viewHolder.data.getText());

            view.setTag(viewHolder);

            Log.d("DBGINF", viewHolder.text.getText() + "");
         else 
            view = convertView;
        

        // This is what gets called every time the ListView refreshes
        ViewHolder holder = (ViewHolder) view.getTag();
        holder.text.setText(getItem(position).getText());
        holder.spin.setSelection(getItem(position).getSelected());

        return view;
    

这是最终应用的截图(不是很漂亮,但确实有效):

就是这样!我希望我回答了你的问题,并帮助了像我一样偶然发现它的任何人。如果要动态更改列表中的数据,请使用 DataAdapter 的 add()remove()get()set() 方法。 要更改每个微调器的数据,您需要修改 DataHolder 类。 SpinnerAdapter 是在此处创建的,因此您只需要根据数据库响应动态生成适配器即可。

【讨论】:

实际上,这是非常错误的并且不会起作用,因为它依赖于ListView 项目本身来存储数据,这是使用ListView 的一大禁忌。任何分配为带有ListView 项目的标签的任何内容都不能用于存储对需要显示的位置敏感的数据。任何ListView 项目可以在以后重用以在另一个位置显示另一个项目。一旦你有足够的项目让ListView 开始滚动,这个例子就会被打破,只需用 10 个或更多项目测试它,这取决于你的模拟器的屏幕大小。 @devmiles.com 你是对的。该问题发生在足够多的项目和滚动时。 jpalm,你必须先检查一下。伙计们请为这个问题发布完美的答案。帮助我。【参考方案2】:

为了使这样的事情发挥作用,必须将所有数据存储在适配器中,而不是 ListView 项目中。任何表示 ListView 项目的视图都可以重复用于显示另一个项目,从而使存储在其自身中的任何数据都无关紧要,直到在 getView 中再次设置正确的数据。

【讨论】:

以上是关于带有微调器和复选框的 Android Listview的主要内容,如果未能解决你的问题,请参考以下文章

没有AlertDialog的android中的多选微调器

Android:减小微调器下拉框的宽度

Android微调器使用XML进行数据绑定并显示所选值

BERT 微调的优化器和调度器

带有下划线 appcompat 的 Android 微调器

带有日期选择器的 Android 微调器,例如 Google 日历应用