【问题标题】:Large custom listview with radio groups带有单选组的大型自定义列表视图
【发布时间】:2015-02-05 07:03:39
【问题描述】:

我是一个新的安卓学习者。我正在开发一个需要 50 行或更多行的自定义列表视图的项目。每行包含一个指示行号的文本视图和一个具有四个单选按钮的单选组。问题是当我检查任何单选按钮然后向下滚动时,我看到许多单选按钮自动选中。当向上滚动时,我看到一些随机单选按钮被选中!

我猜测它的发生是因为 here 所说的 getView() 方法的回收问题。坦率地说,作为一个新手,我听不懂整个讲座。

我也看过this 线程。这与我的问题相似,但无法清楚地理解并解决我的问题。

那么我该如何解决这个问题并从广播组获取数据。由于我是新手,请简单解释一下。

谢谢!

[image]Here is my list view with a radio button checked of 1st row.

[image]When I scroll down I see 15th row is auto checked!

[image]When scroll up again I see radio group of the 1st row is in initial state again!

这是我的代码:

MainActivity:

public class MainActivity extends Activity {

    /* ListView */
    ListView lv;

    /* Data source for numbering */
    String[] numbering = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50"};

    /* Custom adapter */
    CustomListAdapter adapter;

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

        /* initialization */
        adapter = new CustomListAdapter(this, R.layout.list_row_item, numbering);
        lv = (ListView) findViewById(R.id.lvQuestion);

        /* show list view */
        lv.setAdapter(adapter);
    }
}

list_row_item.xml:

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

    <TextView
        android:id="@+id/tvNumbering"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="4"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <RadioGroup
        android:id="@+id/radioGroup"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="horizontal" >

        <RadioButton
            android:id="@+id/answer0"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@drawable/radio_button"
            android:checked="true" />

        <RadioButton
            android:id="@+id/answer1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@drawable/radio_button" />

        <RadioButton
            android:id="@+id/answer2"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@drawable/radio_button" />

        <RadioButton
            android:id="@+id/answer3"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@drawable/radio_button" />
    </RadioGroup>

</LinearLayout>

自定义列表适配器:

public class CustomListAdapter extends ArrayAdapter<String> {
    Context context;
    int layoutResourceId;
    String[] numbers;

    public CustomListAdapter(Context context, int layoutResourceId,
            String[] numbers) {
        super(context, layoutResourceId, numbers);
        this.context = context;
        this.layoutResourceId = layoutResourceId;
        this.numbers = numbers;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder holder = null;

        if (convertView == null) {
            /* Add layout inflater */
            LayoutInflater infletar = ((Activity) context).getLayoutInflater();
            convertView = infletar.inflate(layoutResourceId, null);

            /* initialization */
            holder = new ViewHolder();
            holder.tvNumbering = (TextView) convertView
                    .findViewById(R.id.tvNumbering);
            holder.rg = (RadioGroup) convertView.findViewById(R.id.radioGroup);

            /* set tag */
            convertView.setTag(holder);

        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.tvNumbering.setText(numbers[position]);

        return convertView;
    }

    static class ViewHolder {
        TextView tvNumbering;
        RadioGroup rg;
    }
}

【问题讨论】:

    标签: android


    【解决方案1】:

    当调用getView 时,您需要使用相关position 的数据初始化holder 中保存的视图。

    您目前正在为该行中的TextView 执行此操作。

    holder.tvNumbering.setText(numbers[position]);
    

    您需要对 RadioGroup 执行相同的操作。

    目前您的CustomListAdapter 被定义为扩展StringsArrayAdapter。因此,您传递给适配器的项目列表是一个字符串数组,适配器为每个项目保存的唯一信息是每个项目的 numbers 字符串的值项目。

    在您的情况下,您真正​​想要的是每个项目都有一个 numbers 值和一个 选中的单选按钮强> 价值。

    您应该提供一个封装了这两个变量的自定义类的列表,而不是向适配器提供字符串列表。

    public class MyItem {
        public String number;
        public int checkedRadioButtonId;
    }
    

    你需要让你的适配器处理这个类。

    public class CustomListAdapter extends ArrayAdapter<MyItem> {
        Context context;
        int layoutResourceId;
        MyItem[] items;
    
        public CustomListAdapter(Context context, int layoutResourceId,
                                 MyItem[] items) {
            super(context, layoutResourceId, items);
            this.context = context;
            this.layoutResourceId = layoutResourceId;
            this.items = items;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
    
            View row = convertView;
            ViewHolder holder = null;
    
            if (row == null) {
                LayoutInflater inflater = ((Activity) context).getLayoutInflater();
                row = inflater.inflate(layoutResourceId, null);
                holder = new ViewHolder(row);
                row.setTag(holder);
                // Set a listener to update the data in your items list when the RadioGroup is clicked
                holder.rowRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
                    public void onCheckedChanged(RadioGroup group, int checkedId) {
    
                        // **get which item this RadioGroup refers to**
                        Integer pos = (Integer) group.getTag();
                        Log.d("onCheckedChanged", "pos = " + pos + ", checkedId = " + checkedId);
                        items[pos].checkedRadioButtonId = checkedId;
    
                    }
                });
            } else {
                holder = (ViewHolder) row.getTag();
            }
    
            // **Tag each RadioGroup so we know what item it refers to**
            holder.rowRadioGroup.setTag(position);
    
            // setup both views from the values stored in your items list
            holder.rowTextView.setText(items[position].number);
            holder.rowRadioGroup.check(items[position].checkedRadioButtonId);
    
    
    
            return row;
        }
    
        static class ViewHolder {
            TextView rowTextView = null;
            RadioGroup rowRadioGroup = null;
    
            ViewHolder(View row) {
                this.rowTextView = (TextView) row.findViewById(R.id.tvNumbering);
                this.rowRadioGroup = (RadioGroup) row.findViewById(R.id.radioGroup);
            }
        }
    }
    

    你的 MainActivity 会变成这样的

    public class MainActivity extends Activity {
    
        /* ListView */
        ListView lv;
    
        /* Data source for the ListView */
        MyItem[] myItems = new MyItems[50];
    
        /* Custom adapter */
        CustomListAdapter adapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // Create the data for the list
            for (int i = 0; i < myItems.length; i++) {
                final MyItem item = new MyItem();
                // your numbering goes from 1 to 50, but the array indexes go from 0 to 49
                item.number = String.valueOf(i + 1); 
                // set all items to answer0 by default
                item.checkedRadioButtonId = R.id.answer0
    
                // put the new item in the array
                myItems[i] = item;
            }
    
            /* initialization */
            adapter = new CustomListAdapter(this, R.layout.list_row_item, myItems);
            lv = (ListView) findViewById(R.id.lvQuestion);
    
            /* show list view */
            lv.setAdapter(adapter);
        }
    }
    

    【讨论】:

    • 谢谢!但是我怎样才能为 RadioGroup 做到这一点?在 TextView 中,我正在传递信息,但 RadioGroup 没有这样的东西!
    • 当然有 RadioGroup 的信息!您可以通过 getCheckedRadioButtonId() 获得检查哪个按钮的信息。
    • 大部分错误都消失了,除了,现在如果我选中一个单选按钮并向下滚动(以便选中的单选按钮离开屏幕),然后向上滚动我看到选中的单选按钮已经转到它的初始状态!为什么会这样?
    • 对不起。查看我的最新编辑。 OnCheckedChangeListener 返回被单击的 RadioGroup 组,但我们需要知道该组引用的项目。通过使用位置编号标记每个组,我们可以从侦听器的 onCheckChanged 方法中的group 对象中提取该信息。
    • 哈,再编辑一次。标签可以是任何object,所以当我们getTag()时,我们需要将它转换回Integer,这样我们才能使用它。
    猜你喜欢
    • 2013-03-10
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    • 2015-03-01
    • 2011-07-23
    • 1970-01-01
    相关资源
    最近更新 更多