关闭

具有多选功能的spinner自定义控件

标签: 多选的spinner自定义控件
4444人阅读 评论(3) 收藏 举报
分类:

概述

当我们要做单选功能的时候,我们会很自然的想到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控件

3
0
查看评论

Spinner下拉菜单多选 MultiSelectionSpinner

  • 2016-01-21 10:47
  • 7KB
  • 下载

具有多选功能的spinner自定义控件

  • 2015-10-26 20:56
  • 5.80MB
  • 下载

Android Spinner控件 显示数据和下拉选中数据分离

项目即将快完工了,还有两个关键的部分,心情还是很激动的,经过两个月的从零开始,学到的都已经记录在博客里了,主要涉及的是fragment还有一些乱码解决、
  • omayyouhappy
  • omayyouhappy
  • 2015-09-06 13:59
  • 3161

Android如何愉快的使用Spinner列表选择框

Android如何愉快的使用Spinner列表选择框说实话 我刚学习的时候,感觉这就是网页上的select标签,不过,这个标签可以带图,哈哈是不是感觉像 又到了我们粘贴代码的时间了布局文件:activity_main.xml<LinearLayout xmlns:android="...
  • xyzz609
  • xyzz609
  • 2016-07-15 15:18
  • 3324

下拉列表(Spinner),多选框(CheckBox),单选按钮(RadioButton)的使用

一个简单的功能测试,一个界面录入数据,一个界面xians
  • hubeilihao
  • hubeilihao
  • 2014-06-10 22:36
  • 1328

使用Spinner控件实现选项选择

动画样式文件: <translate android:fromXDelta="0" android:toXDelta="-100%p" android:duration="300" > ...
  • guoqingshuang
  • guoqingshuang
  • 2016-07-26 19:49
  • 508

Android开发之组件单选框(RadioButton)多选框(CheckBox)下拉框(Spinner)

请大家伙多多指教: 邮箱:weimingweicom@sina.com 请关注:ailiandeziwei 1.单选框(RadioButton) package com.example.radiobutton; import android.os.Bundle; ...
  • ailiandeziwei
  • ailiandeziwei
  • 2013-06-24 17:57
  • 22714

Android开发系列(二十一):Spinner的功能和用法以及实现列表选择框

Spinner实现下拉列表框
  • u010800530
  • u010800530
  • 2014-10-28 19:14
  • 1816

当ListView的item为CheckBox,EditText,Spinner的时候处理滑动数据错乱

还记得自己第一次解决listView嵌套数据错乱问题,所以写个笔记记录一下,希望对看到的各位有所帮助。
  • fire_nirvana
  • fire_nirvana
  • 2017-03-07 20:07
  • 445

Spinner的两种使用方式 及 设置选中值

Spinner在android中是用来显示下拉框的组件,对其进行设置主要有两种方式: 方式一:直接在xml文件中设置其要现实的内容:        在对应的布局文件中例如main.xml 要显示的内容在String.xml...
  • hwhzyy
  • hwhzyy
  • 2016-03-29 11:46
  • 8177
    个人资料
    • 访问:185080次
    • 积分:2516
    • 等级:
    • 排名:第17217名
    • 原创:48篇
    • 转载:5篇
    • 译文:0篇
    • 评论:194条
    技术交流

    Android技术讨论群

    Java Android开发技术讨论
    博客专栏
    最新评论
    百度统计