Android ListView构建支持单选和多选的投票项目

引言

我们在android的APP开发中有时候会碰到提供一个选项列表供用户选择的需求,如在投票类型的项目中,我们提供一些主题给用户选择,每个主题有若干选项,用户对这些主题的选项进行选择,然后提交。

本文以一个支持单选和多选投票项目为例,演示了在一个ListView中如何构建CheckBox列表和RadioButton列表,并分析了实现的原理和思路,提供有需要的朋友参考。

项目的演示效果如下。

数据源

通常我们的数据源来自于数据库。首先,我们构建投票项目类SubjectItem。

/**
 * 主题项目类
 * @author zoupeiyang
 *
 */
public class SubjectItem {
 /**
  * 主题id
  */
 private String subjectId;
 /**
  * 主题名称
  */
 private String subjectName;
 /**
  * 主题id
  */
 private String itemId;
 /**
  * 主题名称
  */
 private String itemName;
 /**
  * 是否多选
  */
 private Boolean isMultiChoice;
 public String getSubjectId() {
  return subjectId;
 }
 public void setSubjectId(String subjectId) {
  this.subjectId = subjectId;
 }
 public String getSubjectName() {
  return subjectName;
 }
 public void setSubjectName(String subjectName) {
  this.subjectName = subjectName;
 }
 public String getItemId() {
  return itemId;
 }
 public void setItemId(String itemId) {
  this.itemId = itemId;
 }
 public String getItemName() {
  return itemName;
 }
 public void setItemName(String itemName) {
  this.itemName = itemName;
 }
 public Boolean getIsMultiChoice() {
  return isMultiChoice;
 }
 public void setIsMultiChoice(Boolean isMultiChoice) {
  this.isMultiChoice = isMultiChoice;
 }
}

然后我们构造一个SubjectItem对象的List集合作为我们这个投票项目的数据源,实际项目中这个数据源可以来自数据库投票项目表。

/**
  * 模拟从数据库表获取投票主题项目的数据源
  *
  * @return
  */
 public static List<SubjectItem> getSubjectItems() {
  List<SubjectItem> list = new ArrayList<SubjectItem>();
  HashMap<String, Boolean> subjectMap = new HashMap<String, Boolean>();
  for (int i = 0; i < 3; i++) {

   for (int j = 0; j < 3; j++) {

    SubjectItem item = new SubjectItem();
    item.setSubjectId(i + "");
    //为了方便主题标题和主题项目的布局,集合中同一个主题的项目,只有主题第一个项目的对象的主题名称不为空,其它为空
    //这样显示ListView的每列时如果主题名称为空就隐藏主题名称
    if (subjectMap.containsKey(item.getSubjectId())) {
     item.setSubjectName("");
    } else {
     item.setSubjectName("投票主题" + i);
     subjectMap.put(item.getSubjectId(), true);
    }

    item.setItemId(i + "" + j);
    item.setItemName("项目名称" + i + "" + j);
    item.setIsMultiChoice(i % 2 == 1 ? true : false);
    list.add(item);

   }
  }
  return list;
 }

如何在ListView控件上展示以列表的方式展示投票项目

首先我们先来了解下在ListView控件展示列表数据的流程。
1、定义一个展示列表每一行的布局layout,我们这里定义这个layout的文件名为listview_subject_item.xml。
2、定义展示listview的布局layout,我们这里定义这个layout的文件名为listview_subject_activity.xml。
3、定义listview的数据适配器SubjectAdapter。

定义ListView控件每列的布局

listview_subject_item.xml文件定义的ListView控件中每列view的布局。我们这里的投票项目是支持单选和多项,可以每列view的布局都包含了CheckBox和RadioButton控件,在手机界面显示视图的时候根据当前项目的投票类型(单选或多选)来自动显示(隐藏)对应的控件。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:orientation="vertical" >
 <!-- 投票主题ID,默认隐藏 -->
 <TextView
  android:id="@+id/tv_subject_id"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text=""
  android:visibility="gone" />
  <!-- 投票主题下项目ID,默认隐藏 -->
 <TextView
  android:id="@+id/tv_subject_item_id"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text=""
  android:visibility="gone" />
  <!-- 投票主题类型,true为多选,否则为单选,默认隐藏 -->
  <TextView
  android:id="@+id/tv_is_multi_choice"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text=""
  android:visibility="gone" />
  <!-- 投票主题名称,只有主题下的第一个项目才会显示主题名称,其它项目不显示 -->
 <TextView
  android:id="@+id/tv_subject_name"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:layout_marginTop="20dp"
  android:layout_marginBottom="10dp"
  android:textSize="14sp"
  android:textColor="#1387DD"
  android:textStyle="bold"
  android:text="" />
 <LinearLayout
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="horizontal" >
   <!-- 投票项目名称 -->
  <TextView
   android:id="@+id/tv_subject_item_name"
   android:layout_width="0dp"
   android:layout_height="wrap_content"
   android:layout_weight="1"
   android:gravity="center_vertical" />
   <!-- 多选项目显示CheckBox -->
  <CheckBox
   android:id="@+id/cb_subject_item"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:clickable="false"
   android:focusable="false"
   android:focusableInTouchMode="false"
   android:gravity="center_vertical" />
   <!-- 单选项目显示RadioButton -->
  <RadioButton
   android:id="@+id/rb_subject_item"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:clickable="false"
   android:focusable="false"
   android:focusableInTouchMode="false"
   android:gravity="center_vertical" />
 </LinearLayout>
</LinearLayout>

定义展示ListView的布局

定义展示listview的布局layou,文件名为listview_subject_activity.xml
这里使用了RelativeLayout布局,将提交按钮固定在屏幕底部,方便用户提交投票信息。

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="#ffffffff" >
 <RelativeLayout
  android:id="@+id/rl_head"
  android:layout_width="match_parent"
  android:layout_height="45dp"
  android:layout_alignParentTop="true"
  android:background="#0C99EF"
  android:paddingLeft="10dp" >
  <TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_centerInParent="true"
   android:text="投票项目"
   android:textColor="#ffffffff"
   android:textSize="16sp" />
 </RelativeLayout>
 <!-- 投票项目ListView -->
 <ListView
  android:id="@+id/lv_subject"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_below="@id/rl_head"
  android:layout_marginBottom="50dp"
  android:layout_marginLeft="10dp" >
 </ListView>
 <Button
  android:id="@+id/btn_add"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_alignParentBottom="true"
  android:layout_marginBottom="10dp"
  android:text="提交" />
</RelativeLayout>

定义数据适配器SubjectAdapter

listview_subject_activity.xml文件定义了名为lv_subject的ListView,这个ListView如何和listview控件中每列view的布局listview_subject_item.xml进行关联,还有我们前面定义了投票主题项目数据源,它又如何和listview进行关联数据绑定,要完成这些,我们必须依赖一个Apdater适配器类。
ListView控件通过方法setAdapter和Adapter关联。
在Adapter中通过getView方法和列view的布局listview_subject_item.xml进行关联。
数据源通过Adapter的自定义构造函数的参数传人Adapter。

package com.example.listviewcheckbox.adapter;

import java.util.HashMap;
import java.util.List;

import com.example.listviewcheckbox.R;
import com.example.listviewcheckbox.entity.SubjectItem;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.RadioButton;
import android.widget.TextView;

public class SubjectAdapter extends BaseAdapter {

 private List<SubjectItem> list;
 private Context context;
 //存储所有主题的项目的选中状态,遍历这个容器可以获取选中的项目信息
 private HashMap<String,Boolean> subjectItemMap;
 private LayoutInflater inflater;

 public class ViewHolder{
  //投票主题id控件
  public TextView tvSubjectId;
  //投票主题名称控件
  public TextView tvSubjectName;
  //投票项目名称控件
  public TextView tvSubjectItemName;
  //投票项目id控件
  public TextView tvSubjectItemId;
  //投票主题类型(单选或多选)控件
  public TextView tvIsMultiChoice;
  //选中CheckBox控件(主题类型为多选时显示)
  public CheckBox cbSubjectItem;
  //选中RadioButton控件(主题类型为单选时显示)
  public RadioButton rbSubjectItem;

 }

 public SubjectAdapter(List<SubjectItem> list,Context context)
 {
  this.list=list;
  this.context=context;
   inflater = LayoutInflater.from(context);
  this.subjectItemMap=new HashMap<String, Boolean>();
  //初始化subjectItemMap,默认所有项目为未选中状态
  for (int i = 0; i < list.size(); i++) {
   this.subjectItemMap.put(list.get(i).getItemId(), false);
  }
 }

 @Override
 public int getCount() {
  // TODO Auto-generated method stub
  return list.size();
 }

 @Override
 public Object getItem(int position) {
  // TODO Auto-generated method stub
  return list.get(position);
 }

 @Override
 public long getItemId(int position) {
  // TODO Auto-generated method stub
  return position;
 }

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  // TODO Auto-generated method stub
  ViewHolder viewHolder = null;
  SubjectItem item = list.get(position);
  if(convertView!=null&&convertView.getId()==R.id.lv_subject)
  {
   viewHolder=(ViewHolder)convertView.getTag();
  }
  else {
   viewHolder = new ViewHolder();
   convertView=inflater.inflate(R.layout.listview_subject_item, null);
   viewHolder.tvSubjectId=(TextView)convertView.findViewById(R.id.tv_subject_id);
   viewHolder.tvSubjectName=(TextView) convertView.findViewById(R.id.tv_subject_name);
   viewHolder.tvSubjectItemId = (TextView) convertView.findViewById(R.id.tv_subject_item_id);
   viewHolder.tvSubjectItemName = (TextView) convertView.findViewById(R.id.tv_subject_item_name);
   viewHolder.cbSubjectItem = (CheckBox) convertView.findViewById(R.id.cb_subject_item);
   viewHolder.rbSubjectItem = (RadioButton) convertView.findViewById(R.id.rb_subject_item);
   viewHolder.tvIsMultiChoice = (TextView) convertView.findViewById(R.id.tv_is_multi_choice );

  }
  //如果项目名称为空就隐藏当前项的产品名称,即所有子项目只允许第一个子项目出现产品名称
  if(item.getSubjectName().equals(""))
  {
   viewHolder.tvSubjectName.setVisibility(View.GONE);
  }
  else {
   viewHolder.tvSubjectName.setText(item.getSubjectName());
  }
  viewHolder.tvSubjectItemId.setText(item.getItemId());
  viewHolder.tvSubjectId.setText(item.getSubjectId());
  viewHolder.tvSubjectItemName.setText(item.getItemName());
  viewHolder.tvIsMultiChoice.setText(item.getIsMultiChoice().toString());
  //当前项目为多选项目
  if(item.getIsMultiChoice().toString().equals("true"))
  {
   viewHolder.cbSubjectItem.setVisibility(View.VISIBLE);
   viewHolder.rbSubjectItem.setVisibility(View.GONE);
   viewHolder.cbSubjectItem.setChecked(this.subjectItemMap.get(item.getItemId()));

  }
  //当前项目为单选项目
  else {
   viewHolder.cbSubjectItem.setVisibility(View.GONE);
   viewHolder.rbSubjectItem.setVisibility(View.VISIBLE);
   viewHolder.rbSubjectItem.setChecked(this.subjectItemMap.get(item.getItemId()));
  }
  convertView.setTag(viewHolder);
  return convertView;
 }

 /**
  * 获取所有主题的项目的选中状态容器
  * @return
  */
  public HashMap<String,Boolean> getSubjectItemMap() {
   return this.subjectItemMap;
  }
}

定义显示投票项目的Activity组件

最后我们定义一个Activity组件,将投票项目显示出来。
为了解决单选项目选中后同时要将同主题原来已经选中的项目取消,定义了一个Map(radioButtonSelectedMaps)来存储单选主题的选中的项目信息,key为单选主题ID,value为选中的项目ID。
这样在用户选择某个单选项目时,程序先将SubjectAdapter对象中subjectItemMap该项目主题之前选中的项目的状态设置为false,然后将当前选中的项目设置为true,然后更新ListView,实现单选效果。

public class SubjectActivity extends Activity {

 private ListView lvSubject;
 private SubjectAdapter subjectAdapter;
 private List<SubjectItem> list;
 private Button btnAdd;
 // 用来保存单选主题当前选中的项目,这样用户在切换选择同一个主题下其它选项时能够将之前选中的项目的状态设置为未选状态
 private HashMap<String, String> radioButtonSelectedMaps;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  setContentView(R.layout.listview_subject_activity);
  lvSubject = (ListView) findViewById(R.id.lv_subject);
  btnAdd = (Button) findViewById(R.id.btn_add);
  //从数据源获取投票主题和项目信息
  list = DataService.getSubjectItems();
  subjectAdapter = new SubjectAdapter(list, this);
  lvSubject.setAdapter(subjectAdapter);
  radioButtonSelectedMaps = new HashMap<String, String>();
  // 提交投票事件处理
  btnAdd.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    String selectValues="选中信息:";
    //遍历用户选中项目,可以根据实际需求获取选中项目的任何信息
    for (int i = 0; i < list.size(); i++) {
     if(subjectAdapter.getSubjectItemMap().get(list.get(i).getItemId()))
     {
      selectValues+="项目ID:"+list.get(i).getItemId()+"项目名称:"+list.get(i).getItemName();
     }

    }
    Toast.makeText(SubjectActivity.this, selectValues.equals("选中信息:")?"未选中任何信息":selectValues, Toast.LENGTH_LONG).show();
   }
  });

  // ListView控件每一行点击事件处理
  lvSubject.setOnItemClickListener(new OnItemClickListener() {

   @Override
   public void onItemClick(AdapterView<?> parent, View view,
     int position, long id) {
    // TODO Auto-generated method stub
    ViewHolder viewHolder = (ViewHolder) view.getTag();
    // 如果当前行是多选项目
    if (viewHolder.tvIsMultiChoice.getText().equals("true")) {
     viewHolder.cbSubjectItem.toggle();
     subjectAdapter.getSubjectItemMap().put(viewHolder.tvSubjectItemId.getText().toString(),viewHolder.cbSubjectItem.isChecked());

    } 

    //如果当前行为单选项目,注意单选项目选中后需要将同一主题下已经选中的项目设置为未选中状态
    else {
     String currentSubjectIdSelected=viewHolder.tvSubjectId.getText().toString();
     String currentSubjectItemId=viewHolder.tvSubjectItemId.getText().toString();
     //判断该单选主题是否有已经选中项目,如果有需要将它的选中状态设置为未选中
     if (radioButtonSelectedMaps.containsKey(currentSubjectIdSelected)) {
      subjectAdapter.getSubjectItemMap().put(radioButtonSelectedMaps.get(currentSubjectIdSelected),false);

     }
     //将当前选中的项目设置为该单选主题的选中项目
     radioButtonSelectedMaps.put(currentSubjectIdSelected,currentSubjectItemId);
     viewHolder.rbSubjectItem.toggle();
     subjectAdapter.getSubjectItemMap().put(currentSubjectItemId,viewHolder.rbSubjectItem.isChecked());
     //更新ListView
     updateListView();

    }}});
 }

 /**
  * 更新ListView
  */
 private void updateListView()
 {
  subjectAdapter.notifyDataSetChanged();
 }

}

获取投票结果

// 提交投票事件处理
  btnAdd.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    String selectValues="选中信息:";
    //遍历用户选中项目,可以根据实际需求获取选中项目的任何信息
    for (int i = 0; i < list.size(); i++) {
     if(subjectAdapter.getSubjectItemMap().get(list.get(i).getItemId()))
     {
      selectValues+="项目ID:"+list.get(i).getItemId()+"项目名称:"+list.get(i).getItemName();
     }

    }
    Toast.makeText(SubjectActivity.this, selectValues.equals("选中信息:")?"未选中任何信息":selectValues, Toast.LENGTH_LONG).show();
   }
  });

代码下载:https://github.com/zoupeiyang/ListViewCheckBox

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • android基于ListView和CheckBox实现多选和全选记录的功能

    应用开发中经常会有从数据库中读取数据显示,然后选中多条.全部记录并且删除的需求.在做定制系统联系人的时候也遇到这样的需求,下面写个简单的通过ListView和CheckBox实现多选.全选的例子.下面是具体的代码. 效果如下: MultiSelectActivity /** * MultiSelectActivity */ public class MultiSelectActivity extends Activity implements OnClickListener, OnItemCli

  • Android中ListView + CheckBox实现单选、多选效果

    还是先来看看是不是你想要的效果: 不废话,直接上代码,很简单,代码里都有注释 1 单选 public class SingleActivity extends AppCompatActivity { private ListView listView; private ArrayList<String> groups; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInsta

  • Android中ListView结合CheckBox实现数据批量选择(全选、反选、全不选)

    APP的开发中,会常遇到这样的需求:批量取消(删除)List中的数据.这就要求ListVIew支持批量选择.全选.单选等等功能,做一个比较强大的ListView批量选择功能是很有必要的,那如何做呢? 可想而知,要支持批量选择,那CheckBox的使用是不可或缺的,下面,就使用ListView结合CheckBox实现数据的批量选择. 先看下效果图,有图有真相: 先说明接下来要实现的ListView+CheckBox支持的功能:     1.  外部点击"编辑"(长按ListView的某一

  • Android ListView ImageView实现单选按钮实例

    做Android开发两年的时间,技术稍稍有一些提升,刚好把自己实现的功能写出来,记录一下,如果能帮助到同行的其他人,我也算是做了件好事,哈哈!!废话不多说,先上个图. 先上一段代码: 1 if (lastposition == position){ 2 viewHolder.setImageResource(R.id.iv_yuandian1,R.mipmap.ic_button_checked); 3 } else { 4 viewHolder.setImageResource(R.id.iv

  • Android中ListView绑定CheckBox实现全选增加和删除功能(DEMO)

    ListView控件还是挺复杂的,也是项目中应该算是比较常用的了,所以写了一个小Demo来讲讲,主要是自定义adapter的用法,加了很多的判断等等等等-.我们先来看看实现的效果吧! 好的,我们新建一个项目LvCheckBox 我们事先先把这两个布局写好吧,一个是主布局,还有一个listview的item.xml,相信不用多说 activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/

  • Android ListView获得选项中的值

    在Android中我们要如何获取ListView选中项的值呢? 我们举个例子,假如我们已经获得了手机中保存的联系人姓名和电话号码,并把它们显示在了一个Android ListView中,现在要实现的功能是当点击选中项时直接拨号,那么如何取得此时Android ListView中的号码? 要显示联系人姓名和电话号码,那你现在肯定已经在listview 的item里面放了两个控件吧,假如是textview吧,那你就首先要给listview添加一个OnItemClickListener来监听你点击了那

  • Android ListView实现单选及多选等功能示例

    本文实例讲述了Android ListView实现单选及多选等功能的方法.分享给大家供大家参考,具体如下: 在项目中也遇到过给ListView的item添加选择功能.比如一个网购APP,有个历史浏览页面,这个页面现点击item单选/多选及全选删除功能. 当时也是通过在数据中添加一个是否选择的字段来记录item的状态,然后根据这个字段有相应的position位置进行选择状态更改及删除操作. 刚刚看了Android API Demos中17种ListView的实现方法,发现ListView自身就带有

  • Android的ListView多选删除操作实现代码

    最近尝试做了个listview的多选demo,网上看其他人的例子感觉不是很难,自己动手做了下,各种细节问题,没那么简单啊.既然做了,简单写个笔记记录下. 练手demo,命名笔记乱,不要介意哦. 主界面布局activity_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/to

  • Android listview ExpandableListView实现多选,单选,全选,edittext实现批量输入的实例代码

    最近在项目开发中,由于项目的需求要实现一些列表的单选,多选,全选,批量输入之类的功能,其实功能的实现倒不是很复杂,需求中也没有涉及到复杂的动画什么之类,主要是解决列表数据复用的问题,解决好这个就可以了.下面是最近项目中涉及到的一些: listview实现多选.全选.取消全选: 下面是适配器,一开始在适配器的构造函数中,对数据进行初始化,同时定义一个集合用于管理listview的点击: class BatchAdpter extends BaseAdapter { private HashMap<

  • Android实现ListView控件的多选和全选功能实例

    本文实例讲述了Android实现ListView控件的多选和全选功能.分享给大家供大家参考,具体如下: 主程序代码 MainActivity.Java package yy.test; import java.util.ArrayList; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.view.Menu; import android.vi

  • Android实现便于批量操作可多选的图片ListView实例

    本文实例讲述了Android实现便于批量操作可多选的图片ListView.分享给大家供大家参考,具体如下: 之前项目需要实现一个可多选的图片列表,用户选中一到多张图片后,批量上传.但是网上有可多选普通列表的代码.也有单纯图片列表的代码,却没有两者合并的代码,只好自己实现一个. 废话不说,直接上代码. 先是两个layout: 1.main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout

随机推荐