Android开发中动态向ListView中添加RadioButton(用心抒写)

ListView作为Androd开发中最常用又最“多事”的组件,本人也是既爱之又“恨”之。

今天有一个需求:(测试题库中常用到的单选题,多选题等)

1、安卓自带的RadioButton,CheckBox太丑了,特别是当选项中出现大图片,ABCD之类的也得加到按钮后面,混合到一起,那是简直没法看了。所以,需要重新绘制RadioButton和CheckBox。

2、选项个数不确定,所以需要动态添加。

综上说述,决定用ListView+ListViewAdapter(自定义的,继承与BaseAdapter)来解决这个问题。

先上效果图:

思路:

看到上图样式,我们首先应该怎么做呢?因为,它有选中和不选中两个状态,第一个想到的就是:创建样式选择器selector以及做一下上图中的按钮背景图片。

如下代码:(其中,custom_rbutton_checked和custom_rbutton_unchecked分别是选中以及不选中时的按钮背景图)

<?xml version="1.0" encoding="utf-8"?>
<!-- 单选按钮背景自定义效果 -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/custom_rbutton_checked" android:state_checked="true"
        android:state_enabled="true" />
    <item android:drawable="@drawable/custom_rbutton_unchecked" android:state_checked="false"
        android:state_enabled="true" />

</selector>

然后在style.xml中添加相关RadioButton的样式。如下:(将背景设置为选择器的样式)

<style name="custom_radio_styles">
        <item name="android:background">@drawable/selector_radiobutton_bg</item>
        <item name="android:gravity">center</item>
    </style>

接下来我们给相关布局文件中的RadioButton添加style样式即可。如下:

    <RadioButton
        android:id="@+id/radiobuttonlist_singleChoiceButton"
        style="@style/custom_radio_styles"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_marginRight="10dp"
        android:button="@null"
        android:focusable="false"
        android:clickable="false"
        android:focusableInTouchMode="false"
        android:text="A" />
其中,
 android:button="@null"

可以把RadioButton的自带按钮样式去掉。

        android:focusable="false"
        android:clickable="false"
        android:focusableInTouchMode="false"

上面的可以解决ListView中添加Button或者CheckBox等时造成的ListView的onItemClickListener监听事件没反应的问题。(说白了就是焦点获取不到)

至此,按钮样式已经完成。下面我们开始做一下和ListView相关的操作。

首先,如果向ListView中添加子项,毋庸置疑,第一个想到的是不是数据适配器(ArrayAdapter,SimpleAdapter,BaseAdapter等)呢?这个大家应该都是这么想的,那么问题来了,用现有的SimpleAdapter适配器能够实现我们想要的展示出来的效果,但是想要的状态改变和数据改变,我们要怎么获取呢?想了想,行不通,那怎么办?那么我们自定义一个数据适配器就可以了,继承BaseAdapter。

如下图:RadioButtonListViewAdapter.java(单选题的数据适配器)

public class RadioButtonListViewAdapter extends BaseAdapter {

    private List<ItemBean> mData;
    private Context mContext;
    private HashMap<String,Boolean> rButtonStates = new HashMap<String,Boolean>();

    public RadioButtonListViewAdapter(Context mContext, List<ItemBean> mData, HashMap<String, Boolean> states) {
        this.mContext = mContext;
        this.mData = mData;
        this.rButtonStates = states;
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Object getItem(int position) {
        return mData.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_radiobuttonlist, null);
            holder = new ViewHolder(convertView);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        final ItemBean itemObj = mData.get(position);
        holder.textView.setText(itemObj.getText());
        holder.radioButton.setText(itemObj.getBtnText());
        boolean res = false;
        if(getStates(position) == null || getStates(position) == false)//判断当前位置的radiobutton点击状态
        {
            res = false;
            setStates(position, false);
        }else{
            res = true;
        }
        holder.radioButton.setChecked(res);
        return convertView;
    }

    //用于在activity中重置所有的radiobutton的状态
    public void clearStates(int position){
        // 重置,确保最多只有一项被选中
        for(String key:rButtonStates.keySet()){
            rButtonStates.put(key, false);
        }
        rButtonStates.put(String.valueOf(position), true);
    }
    //用于获取状态值
    public Boolean getStates(int position){
        return rButtonStates.get(String.valueOf(position));
    }
    //设置状态值
    public void setStates(int position, boolean isChecked){
        rButtonStates.put(String.valueOf(position), false);
    }

    private class ViewHolder {
        private RadioButton radioButton;
        private TextView textView;

        public ViewHolder(View convertView) {
            radioButton = convertView.findViewById(R.id.radiobuttonlist_singleChoiceButton);
            textView = convertView.findViewById(R.id.radiobuttonlist_singleChoiceContent);
        }
    }
}

像其中的一些类以及item布局文件,大家可以自己定义即可。主要理解思路。

适配器整好了,那么我们现在在MainActivity中进行调用即可。

如下:(这是一个单选题选项动态添加的方法,在你需要的位置调用一下即可。)

//单选题选项添加
    public void singleChoiceQuestionsAutoAddOption(int addNum, String userAnswer){
        singleChoiceQuestionData = new ArrayList<ItemBean>();
        HashMap<String, Boolean> optionStates = new HashMap<String, Boolean>();
        for (int i = 0; i < addNum; i++) {
            if (userAnswer.equals(optionTags[i])) {
                optionStates.put(String.valueOf(i), true);
            } else {
                optionStates.put(String.valueOf(i), false);
            }
        }
        for (int i = 0; i < addNum; i++){
            ItemBean itemBean = new ItemBean();
            itemBean.setBtnText(optionTags[i]);
            itemBean.setText(singleChoiceQuestionsOptionContents[i]);
            singleChoiceQuestionData.add(itemBean);
        }
        singleChoiceQuestionsAdapter = new RadioButtonListViewAdapter(this
                , singleChoiceQuestionData, optionStates);
        singleChoiceQuestionsAdapter.notifyDataSetChanged();
        rbList.setAdapter(singleChoiceQuestionsAdapter);
    }

注意:因为做的是测试题库程序,所以用户的答案也要做保存以及切换题目的时候的用户答案显示。

最后,还要实现ListView的onItemClickListener的监听事件。

如下:

public AdapterView.OnItemClickListener singleChoiceAndMultipleChoiceQuestionsListviewOnItemClickListener
            = new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            switch (questionType) {
                case 0:{
                    singleChoiceQuestionsTransfer(view, position);
                    userAnswers[0] = optionTags[position];
                    break;
                }
                case 1:{
                    multipleChoiceQuestionsTransfer(view, position);
                    String userAnswer = userAnswers[1];
                    String whichOption = optionTags[position];
                    if (userAnswer.indexOf(whichOption) >= 0){

                        userAnswer = userAnswer.replace(whichOption, "");
                    }
                    else {
                        userAnswer = (userAnswer + whichOption).trim();
                    }
                    userAnswers[1] = userAnswer;
                    break;
                }
                default:break;
            }
        }
    };

    private void singleChoiceQuestionsTransfer(View view, int position) {
        RadioButton radioButton = (RadioButton) view.findViewById(R.id.radiobuttonlist_singleChoiceButton);
        //每次选择一个item时都要清除所有的状态,防止出现多个被选中
        singleChoiceQuestionsAdapter.clearStates(position);
        radioButton.setChecked(singleChoiceQuestionsAdapter.getStates(position));
        //刷新数据,调用getView刷新ListView
        singleChoiceQuestionsAdapter.notifyDataSetChanged();

    }

再重申一遍,代码已经很详细了,以理解为主,希望对大家有所帮助。大家互相学习,互相提升。

完整Demo地址:https://download.csdn.net/download/lpcrazyboy/10465373

猜你喜欢

转载自blog.csdn.net/lpcrazyboy/article/details/80611174