支持多选的Spinner控件
概述
当我们要做单选功能的时候,我们会很自然的想到Spinner,它可以在一个集合中选择一个我们需要的值。但是有时候我们需要在一个集合中选择多个值,这个时候Spinner就不能满足需求。此时可以根据自己的需要来实现类似于Spinner效果的多选控件。
效果图
实现分析
需要实现的效果是点击一个文本后弹出一个多选列表,在点击之后选择、取消选择,点击确定之后设置文本。这个文本框就用TextView,让它支持点击。点击之后弹出一个dialog就可以了,至于选择效果可以在ListView的Adapter里进行逻辑处理。下面开始具体步骤:
1、首先需要用TextView来显示选择信息,在上面说明了,就继承TextView,在弹出对话框的时候需要一个标题,我们也传进来。然后就是要显示的数据集,因为考虑到可能显示的样式会和需要的值不一样,这里我们就自己定义一个类给它一个Name和Value属性。
此外还有被选择的数据集,就用Set来存放。定义需要的属性,生成相应的get和set方法。
public class MultiSpinner extends TextView implements View.OnClickListener,DialogInterface.OnClickListener{
private ListView listView;
private Context context;
private String title;
private List<SimpleSpinnerOption> dataList;
private Adapter adapter;
private Set<Object> checkedSet;
private int selectCount=-1;
private boolean isEmpty(){
return dataList==null?true:dataList.isEmpty();
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public void setCheckedSet(Set<Object> checkedSet) {
this.checkedSet = checkedSet;
showSelectedContent();
}
public List<SimpleSpinnerOption> getDataList() {
return dataList;
}
public int getSelectCount() {
return selectCount;
}
public void setSelectCount(int selectCount) {
this.selectCount = selectCount;
}
public void setDataList(List<SimpleSpinnerOption> dataList) {
this.dataList = dataList;
if (adapter==null){
adapter=new Adapter(dataList);
this.listView.setAdapter(adapter);
}else {
adapter.setList(dataList);
adapter.notifyDataSetChanged();
}
}
public MultiSpinner(Context context) {
super(context, null);
}
public MultiSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
this.context=context;
this.setOnClickListener(this);
listView=new ListView(context);
listView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
adapter = new Adapter(null);
this.listView.setAdapter(adapter);
}
public MultiSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
数据类型SimpleSpinnerOption的代码如下:
public class SimpleSpinnerOption {
private String name;
private Object value;
public SimpleSpinnerOption(){
this.name="";
this.value="";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
在上面的代码中,我们在初始化的时候为该控件本身设置了监听事件,由于此时还不知道数据源,所以为ListView设置了一个空的数据集。而在setDataList方法中拿到数据源并设置给listView中用于显示。为了显示出来,我们在控件本身的onClick事件中做显示工作,代码如下:
@Override
public void onClick(View view) {
ViewGroup parent=(ViewGroup)listView.getParent();
if(parent!=null){
parent.removeView(listView);
}
if (dataList==null){
Log.d("MultiSpinner","no data to show");
}
adapter.setCheckedSet(checkedSet);
new AlertDialog.Builder(context)
.setTitle(title)
.setPositiveButton("确定",this)
.setNegativeButton("取消",this)
.setView(listView).show();
}
我们在onClick中弹出一个对话框让listview能够进行显示。并且设置了相应的点击事件。由于如果之前已经选择过了,再次点击控件,应该能把选择的效果还原出来。所以用adapter.setCheckedSet(checkedSet)来把已经选择的数据传入adapter中进行处理。
接下来看一下Adapter适配器的代码:
class Adapter extends BaseAdapter implements OnClickListener {
private List<SimpleSpinnerOption> list;
private Set<Object> checkedSet;
public Adapter(List<SimpleSpinnerOption> list){
this.list=list;
checkedSet=new HashSet<Object>();
}
public void setList(List<SimpleSpinnerOption> list) {
this.list = list;
}
public Set<Object> getCheckedSet(){
return this.checkedSet;
}
public void setCheckedSet(Set<Object> checkedSet) {
this.checkedSet=new HashSet<Object>();
if(checkedSet!=null){
this.checkedSet.addAll(checkedSet);
}
}
@Override
public int getCount() {
return list==null?0:list.size();
}
@Override
public Object getItem(int position) {
return list==null?null:list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
SimpleSpinnerOption mul=(SimpleSpinnerOption)this.getItem(position);
Wrapper wrapper=null;
if(convertView==null){
convertView = LayoutInflater.from(MultiSpinner.this.getContext()).inflate(R.layout.multi_spinner_item,null);
wrapper=new Wrapper();
wrapper.textView=(TextView)convertView.findViewById(R.id.textView);
wrapper.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
wrapper.checkBox.setOnClickListener(this);
convertView.setTag(wrapper);
}
wrapper=(Wrapper)convertView.getTag();
wrapper.textView.setText(mul.getName());
if(checkedSet!=null){
if(checkedSet.contains(mul.getValue())){
wrapper.checkBox.setChecked(true);
}else{
wrapper.checkBox.setChecked(false);
}
}
wrapper.checkBox.setTag(position);
return convertView;
}
@Override
public void onClick(View v) {
CheckBox checkBox=(CheckBox)v;
Integer position=(Integer)checkBox.getTag();
if(position==null){
return;
}
SimpleSpinnerOption op=(SimpleSpinnerOption)getItem(position);
if(checkBox.isChecked()){
int maxCount= MultiSpinner.this.getSelectCount();
if(maxCount>-1&&checkedSet.size()>=maxCount){
checkBox.setChecked(false);
Toast.makeText(MultiSpinner.this.getContext(), String.format("最多只能选择 %s 个", selectCount), Toast.LENGTH_SHORT).show();
return;
}
checkedSet.add(op.getValue());
}else{
checkedSet.remove(op.getValue());
}
}
class Wrapper{
public TextView textView;
public CheckBox checkBox;
}
}
在适配器的item布局里,用一个textview来显示文字,用checkbox来显示选中状态。在getView中判断是否已经选择修改checkbox的状态。同时在checkbox的点击事件中进行选择值checkedSet的修改。
最后是我们点击确定取消按钮的逻辑:
@Override
public void onClick(DialogInterface dialogInterface, int i) {
switch (i){
case -1:
this.checkedSet=adapter.getCheckedSet();
showSelectedContent();
break;
}
}
private void showSelectedContent(){
StringBuilder sb=new StringBuilder();
for(SimpleSpinnerOption option:getCheckedOptions()){
sb.append(option.getName()).append(",");
}
if(sb.length()>0){
sb.setLength(sb.length()-1);
}
setText(sb.toString());
}
代码很简单,就是拿到数据集之后进行一下展示,你也可以根据自己想要的展示方式进行修改。
使用就在代码中找到控件同时设置一下数据集就ok了。在需要拿选择数据的时候调用multiSpinner.getCheckedOptions()做自己的处理。
multiSpinner = (MultiSpinner) findViewById(R.id.mulSpinner);
multiSpinner.setTitle("月份选择");
ArrayList multiSpinnerList=new ArrayList();
for(int i=0;i<12;i++){
SimpleSpinnerOption option=new SimpleSpinnerOption();
option.setName((i+1)+" 月");
option.setValue(i+1);
multiSpinnerList.add(option);
}
multiSpinner.setDataList(multiSpinnerList);
到这里就实现了一个可以多选的类似于的spinner控件啦!
源码下载请戳:自定义实现多选的Spinner控件
支持多选的Spinner控件的更多相关文章
- CYQ.Data 支持WPF相关的数据控件绑定(2013-08-09)
事件的结果 经过多天的思考及忙碌的开发及测试,CYQ.Data 终于在UI上全面支持WPF,至此,CYQ.Data 已经可以方便支持wpf的开发,同时,框架仍保留最低.net framework2.0 ...
- Spinner控件
首先在XML文件中声明一个Spinner控件: <Spinner android:id="@+id/spinnerId" android:layout_width=" ...
- Android spinner控件
spinner控件是Android中下拉控件,现在介绍它两种用法.第一种,从资源文件中获取下拉值:第二种,从代码中获取下拉值. 第一种,首先要在资源文件中把值写好: <?xml version= ...
- jasonTree多选多级树控件
jasonTree1.0 jasonTree多选多级树控件(名字是自己取),用于友好的展示树形结构的数据,并可以多选,传统的做法是在一个select的下拉框中显示一个可折叠的树结构,公司的需求人员这种 ...
- ProgressBar、RatingBar和Spinner控件
1.ProgressBar.SeekBar与RatingBar控件 ProgressBar控件,也就是我们通常的进度条控件,可以显示加载的进度等.SeekBar控件,滑块控件,可以根据用户的需要动态为 ...
- 大约Android PopupWindow有用Spinner控件点击APP Crash案例整理!
场景异常,如下面: android.view.WindowManager$BadTokenException: Unable to add window -- token android.view.V ...
- CYQ.Data 支持WPF相关的数据控件绑定.Net获取iis版本
CYQ.Data 支持WPF相关的数据控件绑定(2013-08-09) 事件的结果 经过多天的思考及忙碌的开发及测试,CYQ.Data 终于在UI上全面支持WPF,至此,CYQ.Data 已经可以方便 ...
- 支持Angular 2的表格控件
前端框架一直这最近几年特别火的一个话题,尤其是Angular 2拥有众多的粉丝.在2016年9月份Angular 2正式发布之后,大量的粉丝的开始投入到了Angular 2的怀抱.当然这其中也包括我. ...
- android 学习 Spinner控件的使用
今晚看了下spinner控件的使用,结合博客大神的教程,一个小demo 一,SpinnerActivity private Spinner spinner; private ArrayAdapter& ...
随机推荐
- java面试欠缺知识点总结
针对最近面试被问到的问题,总结自己欠缺的知识点,并要在接下来的1年内加强这些知识: Java方面:反射.线程concurrent包: Spring方面:Ioc和Aop.事务: 持久化框架:设计并实现分 ...
- 笔记——Visual Studio 程序员箴言
记录了一些感觉比较用得到的tips用于随时查看.要想看完整的的内容还是阅读<Visual Studio 程序员箴言>,不过有些内容我在新版本的VS里没能实现,或者有替代方案了. 避免意外复 ...
- EF Attach时已存在的处理方式
如果我们在先前的步骤中读取过数据,如 var list = db.Model.ToList(); 之后再,附加 var o = new Model { Id = 1 }; db.Model.Attac ...
- fcitx 无法启动
困扰了好久的问题,终于解决了. 问题描述: 在fcitx的输入法配置栏里,输入法列表是空的,使用Ctrl+space无法启用任何的输入法, 当然此截图中的是有的,这是问题已经解决后的状态了. 解决方法 ...
- 第一次接触终极事务处理——Hekaton
在这篇文章里,我想给出如何与终极事务处理(Extreme Transaction Processing (XTP) )的第一次接触,即大家熟知的Hakaton.如果你想对XTP有个很好的概况认识,我推 ...
- Django项目--web聊天室
需求 做一个web聊天室,主要练习前端ajax与后台的交互: 一对一聊天和群组聊天 添加用户为好友 搜索并添加群组 管理员可以审批用户加群请求,群管理员可以有多个,群管理员可以删除,添加禁言群友 与聊 ...
- CentOS6.5菜鸟之旅:文件权限详解
一.前言 Linux下所有资源.设备均被视作文件来操作,而文件权限则是决定用户可各文件操作的范围,无论是平时使用Linux,还是写程序均涉及这方面.以下为个人学习的整理,供以后查阅. 二. 三种权限 ...
- Gradle学习系列之十——自定义Plugin(本系列完)
在本系列的上篇文章中,我们讲到了如何自定义Task类型,在本篇文章中,我们将讲到如何自定义Plugin. 请通过以下方式下载本系列文章的Github示例代码: git clone https://gi ...
- java版复利计算器升级
github地址:https://github.com/iamcarson/Carson 伙伴:彭宏亮 学号:201406114148 与伙伴工作帅照: 本次升级的地方: 1.改善了界面显示,让界面整 ...
- log4net日志记录
这里是接着上一篇来优化的,上篇:ASP.NET MVC中错误日志信息记录 log4Net是用来记录日志的,可以将程序运行过程中的信息输出到一些地方(文件,数据库,EventLog等),日志就是程序的黑 ...