ListView作为Androd开发中最常用又最“多事”的组件,本人也是既爱之又“恨”之。
今天有一个需求:(测试题库中常用到的单选题,多选题等)
1、安卓自带的RadioButton,CheckBox太丑了,特别是当选项中出现大图片,ABCD之类的也得加到按钮后面,混合到一起,那是简直没法看了。所以,需要重新绘制RadioButton和CheckBox。
2、选项个数不确定,所以需要动态添加。
综上说述,决定用ListView+ListViewAdapter(自定义的,继承与BaseAdapter)来解决这个问题。
先上效果图:
思路:
看到上图样式,我们首先应该怎么做呢?因为,它有选中和不选中两个状态,第一个想到的就是:创建样式选择器selector以及做一下上图中的按钮背景图片。
如下代码:(其中,custom_rbutton_checked和custom_rbutton_unchecked分别是选中以及不选中时的按钮背景图)
然后在style.xml中添加相关RadioButton的样式。如下:(将背景设置为选择器的样式)
接下来我们给相关布局文件中的RadioButton添加style样式即可。如下:
其中,
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 mData;
private Context mContext;
private HashMap rButtonStates = new HashMap();
public RadioButtonListViewAdapter(Context mContext, List mData, HashMap 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();
HashMap optionStates = new HashMap();
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