功能控件

仿ios滚动日期控件,所有的三级联动都在这里

2017-04-20  本文已影响1969人  码客_Yang

从上个月15号来到吉林出差,几乎就没有正常下过班,虽说每天没干到凌晨一两点,但基本也都是10点以后回去。既然选择了这工作,那也得认命,现在所有的努力都是为了以后更好的生活。再说习大大不也说了嘛,“2017年,撸起袖子,加油干”。年轻,你就得可劲造。

配一张我女朋友的照片

不好意思,前面我装了个13,各位看官老爷别骂我。下面进入正题,今天在业务测试时,他们提出一个需求,把现有的系统自带的选择日期控件,改成像ios那样可以滚动的。虽然听到这个消息,心里是不高兴的,但是想着也不是啥大事,就自己摸索下吧、

安卓原生日期控件

1、有时间和选项这两种选择器
2、选项选择器支持三级联动
3、时间选择器支持起始和终止日期设定
4、支持“年,月,日,时,分,秒”,“省,市,区”等选项的单位(label)显示、隐藏和自定义
5、支持自定义文字、颜色、文字大小等属性
6、支持背景颜色更换,有夜间模式需求的问题可以解决了
7、Item的文字长度过长时,文字会自适应缩放到Item的长度,避免显示不完全的问题

——TimePickerView 时间选择器,支持年月日时分,年月日,年月,时分等格式
——OptionsPickerView 选项选择器,支持一,二,三级选项选择,并且可以设置是否联动

先上效果图:

时间选择器.gif 选项选择器.gif 自定义时间选择器 自定义选项选择器.gif 不联动时间选择器.gif 三级联动省市区.gif

使用步骤:

1、在Jcenter仓库添加 Gradle依赖:
compile 'com.contrarywind:Android-PickerView:3.2.4'
2.在Activity中添加如下代码就可以使用了:
//时间选择器
TimePickerView pvTime = new TimePickerView.Builder(this, new TimePickerView.OnTimeSelectListener() {
            @Override
            public void onTimeSelect(Date date,View v) {//选中事件回调
               Toast.makeText(Main2Activity.this,getTime(date),Toast.LENGTH_LONG).show();
            }
        })
             .build();
 pvTime.setDate(Calendar.getInstance());//注:根据需求来决定是否使用该方法(一般是精确到秒的情况),此项可以在弹出选择器的时候重新设置当前时间,避免在初始化之后由于时间已经设定,导致选中时间与当前时间不匹配的问题。
 pvTime.show();//显示时间选择器
3.如果默认样式不符合你的口味,也可以自定义各种属性:
 Calendar selectedDate = Calendar.getInstance();
 Calendar startDate = Calendar.getInstance();
 startDate.set(2013,1,1);
 Calendar endDate = Calendar.getInstance();
 endDate.set(2020,1,1);

 pvTime = new TimePickerView.Builder(this, new TimePickerView.OnTimeSelectListener() {
            @Override
            public void onTimeSelect(Date date,View v) {//选中事件回调
                tvTime.setText(getTime(date));
            }
        })
                .setType(TimePickerView.Type.ALL)//默认全部显示
                .setCancelText("Cancel")//取消按钮文字
                .setSubmitText("Sure")//确认按钮文字
                .setContentSize(18)//滚轮文字大小
                .setTitleSize(20)//标题文字大小
                .setTitleText("Title")//标题文字
                .setOutSideCancelable(false)//点击屏幕,点在控件外部范围时,是否取消显示
                .isCyclic(true)//是否循环滚动
                .setTitleColor(Color.BLACK)//标题文字颜色
                .setSubmitColor(Color.BLUE)//确定按钮文字颜色
                .setCancelColor(Color.BLUE)//取消按钮文字颜色
                .setTitleBgColor(0xFF666666)//标题背景颜色 Night mode
                .setBgColor(0xFF333333)//滚轮背景颜色 Night mode
                .setRange(calendar.get(Calendar.YEAR) - 20, calendar.get(Calendar.YEAR) + 20)//默认是1900-2100年
                .setDate(selectedDate)// 如果不设置的话,默认是系统时间*/
                .setRangDate(startDate,endDate)//起始终止年月日设定
                .setLabel("年","月","日","时","分","秒")
                .isCenterLabel(false) //是否只显示中间选中项的label文字,false则每项item全部都带有label。
                .isDialog(true)//是否显示为对话框样式
                .build();
4.如果需要自定义布局:
        // 注意:自定义布局中,id为 optionspicker 或者 timepicker 的布局以及其子控件必须要有,否则会报空指针
        // 具体可参考demo 里面的两个自定义布局
        pvCustomOptions = new OptionsPickerView.Builder(this, new OptionsPickerView.OnOptionsSelectListener() {
            @Override
            public void onOptionsSelect(int options1, int option2, int options3, View v) {
                //返回的分别是三个级别的选中位置
                String tx = cardItem.get(options1).getPickerViewText();
                btn_CustomOptions.setText(tx);
            }
        })
                .setLayoutRes(R.layout.pickerview_custom_options, new CustomListener() {
                    @Override
                    public void customLayout(View v) {
                        //自定义布局中的控件初始化及事件处理
                        final TextView tvSubmit = (TextView) v.findViewById(R.id.tv_finish);
                        final TextView tvAdd = (TextView) v.findViewById(R.id.tv_add);
                        ImageView ivCancel = (ImageView) v.findViewById(R.id.iv_cancel);
                        tvSubmit.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                pvCustomOptions.returnData(tvSubmit);
                            }
                        });
                        ivCancel.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                pvCustomOptions.dismiss();
                            }
                        });

                        tvAdd.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                getData();
                                pvCustomOptions.setPicker(cardItem);
                            }
                        });

                    }
                })
                .build();
        pvCustomOptions.setPicker(cardItem);//添加数据
5.对使用还有疑问的话,请参考下面代码(代码量大,注释也很清晰,使用起来很方便)

Main2Activity代码

package com.e_valmont.look_lookdemo;

import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.bigkoo.pickerview.OptionsPickerView;
import com.bigkoo.pickerview.TimePickerView;
import com.bigkoo.pickerview.listener.CustomListener;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

/**
* 主页面
*/
public class Main2Activity extends AppCompatActivity implements View.OnClickListener{

    /*按钮*/
    private Button btn_Time;//时间选择器
    private Button btn_Options;//选项选择器
    private Button btn_CustomOptions;
    private Button btn_CustomTime;
    private Button btn_no_linkage;//无联动选择器
    private Button btn_goToJsonData;//解析json数据

    /*选择器*/
    private TimePickerView pvTime;
    private TimePickerView pvCustomTime;
    private OptionsPickerView pvOptions;
    private OptionsPickerView pvCustomOptions;
    private OptionsPickerView pvNoLinkOptions;

    private ArrayList<CardBean> cardItem = new ArrayList<>();

    /*无联动数据*/
    private ArrayList<String> food = new ArrayList<>();//食品类型
    private ArrayList<String> clothes = new ArrayList<>();//衣服品牌
    private ArrayList<String> computer = new ArrayList<>();//电脑品牌

    private ArrayList<ProvinceBean> options1Items = new ArrayList<>();
    private ArrayList<ArrayList<String>> options2Items = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        initView();
        //最好等数据加载完毕再初始化并显示,以免数据量大的时候,还未加载完毕就显示,造成APP崩溃。
        initTimePicker();
        initCustomTimePicker();
        initOptionData();
        initOptionPicker();
        initCustomOptionPicker();
        initNoLinkOptionsPicker();

        initClilck();
    }
    private void initView(){
        btn_Time = (Button) findViewById(R.id.btn_Time);
        btn_Options = (Button) findViewById(R.id.btn_Options);
        btn_CustomOptions = (Button) findViewById(R.id.btn_CustomOptions);
        btn_CustomTime = (Button) findViewById(R.id.btn_CustomTime);
        btn_no_linkage = (Button) findViewById(R.id.btn_no_linkage);
        btn_goToJsonData = (Button) findViewById(R.id.btn_GotoJsonData);
    }

    private void initClilck(){
        btn_Time.setOnClickListener(this);
        btn_Options.setOnClickListener(this);
        btn_CustomOptions.setOnClickListener(this);
        btn_CustomTime.setOnClickListener(this);
        btn_no_linkage.setOnClickListener(this);
        btn_goToJsonData.setOnClickListener(this);
    }
    /**
    * 初始化时间选择器
    **/
    private void initTimePicker() {
        //控制时间范围(如果不设置范围,默认时间1900-2100年)
        //因为系统Calendar的月份是从0-11的,所以如果是调用Calendar的set方法来设置时间,月份的范围也要是从0-11
        Calendar selectedDate = Calendar.getInstance();
        Calendar startDate = Calendar.getInstance();
        startDate.set(1900,1,1);

        Calendar endDate = Calendar.getInstance();
        endDate.set(2100,12,31);
        //时间选择器
        pvTime = new TimePickerView.Builder(this, new TimePickerView.OnTimeSelectListener() {
            @Override
            public void onTimeSelect(Date date, View v) {//选中事件回调
                // 这里回调过来的v,就是show()方法里面所添加的 View 参数,如果show的时候没有添加参数,v则为null
//              //点击确定时,按钮显示选中时间
//                Button btn = (Button) v;
//                btn.setText(getTime(date));
                Toast.makeText(Main2Activity.this,getTime(date),Toast.LENGTH_LONG).show();
            }
        })
                .setType(TimePickerView.Type.YEAR_MONTH_DAY)//显示样式,共6种
                .setLabel("", "", "", "", "", "") //设置空字符串以隐藏单位提示,可任意选填其中几个或不填,eg:年月日时分秒
                .setDividerColor(Color.TRANSPARENT)//分隔线颜色
                .setContentSize(20)//字体大小
                .isCyclic(true)//设置是否循环
                .setDate(selectedDate)
                .setRangDate(startDate,endDate)
                .build();
    }

    /**
     * 初始化自定义时间选择器
     * */
    private void initCustomTimePicker() {

        /**
         * @description
         *
         * 注意事项:
         * 1.自定义布局中,id为 optionspicker 或者 timepicker 的布局以及其子控件必须要有,否则会报空指针.
         * 具体可参考demo 里面的两个自定义layout布局。
         * 2.因为系统Calendar的月份是从0-11的,所以如果是调用Calendar的set方法来设置时间,月份的范围也要是从0-11
         * setRangDate方法控制起始终止时间(如果不设置范围,则使用默认时间1900-2100年,此段代码可注释)
         */
        Calendar selectedDate = Calendar.getInstance();//系统当前时间
        Calendar startDate = Calendar.getInstance();
        startDate.set(2014,1,23);
        Calendar endDate = Calendar.getInstance();
        endDate.set(2027,0,28);//月份0-11代表1-12
        //时间选择器 ,自定义布局
        pvCustomTime = new TimePickerView.Builder(this, new TimePickerView.OnTimeSelectListener() {
            @Override
            public void onTimeSelect(Date date, View v) {//选中事件回调
                //btn_CustomTime.setText(getTime(date));
                Toast.makeText(Main2Activity.this,getTime(date),Toast.LENGTH_LONG).show();
            }
        })
                /*.setType(TimePickerView.Type.ALL)//default is all
                .setCancelText("Cancel")
                .setSubmitText("Sure")
                .setContentSize(18)
                .setTitleSize(20)
                .setTitleText("Title")
                .setTitleColor(Color.BLACK)
               /*.setDividerColor(Color.WHITE)//设置分割线的颜色
                .setTextColorCenter(Color.LTGRAY)//设置选中项的颜色
                .setLineSpacingMultiplier(1.6f)//设置两横线之间的间隔倍数
                .setTitleBgColor(Color.DKGRAY)//标题背景颜色 Night mode
                .setBgColor(Color.BLACK)//滚轮背景颜色 Night mode
                .setSubmitColor(Color.WHITE)
                .setCancelColor(Color.WHITE)*/
               /*.gravity(Gravity.RIGHT)// default is center*/
                .setDate(selectedDate)
                .setRangDate(startDate,endDate)
                .setLayoutRes(R.layout.pickerview_custom_time, new CustomListener() {

                    @Override
                    public void customLayout(View v) {
                        final TextView tvSubmit = (TextView) v.findViewById(R.id.tv_finish);
                        ImageView ivCancel = (ImageView) v.findViewById(R.id.iv_cancel);
                        tvSubmit.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                pvCustomTime.returnData();
                            }
                        });
                        ivCancel.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                pvCustomTime.dismiss();
                            }
                        });
                    }
                })
                .setType(TimePickerView.Type.YEAR_MONTH_DAY)
                .isCenterLabel(true) //是否只显示中间选中项的label文字,false则每项item全部都带有label。
                .setDividerColor(Color.RED)
                .isCyclic(true)
                .build();

    }

    /**
     * 初始化无联动选项选择器
     * */
    private void initNoLinkOptionsPicker() {
        pvNoLinkOptions = new OptionsPickerView.Builder(this, new OptionsPickerView.OnOptionsSelectListener() {

            @Override
            public void onOptionsSelect(int options1, int options2, int options3, View v) {

                String str = "食品:"+food.get(options1)
                        +"\n衣服:"+clothes.get(options2)
                        +"\n电脑:"+computer.get(options3);

                Toast.makeText(Main2Activity.this,str,Toast.LENGTH_SHORT).show();
            }
        })
                .build();
        pvNoLinkOptions.setNPicker(food,clothes,computer);//设置数据
    }

    /**
     * 初始化选择器数据
     * */
    private void initOptionData() {

        /**
         * 注意:如果是添加JavaBean实体数据,则实体类需要实现 IPickerViewData 接口,
         * PickerView会通过getPickerViewText方法获取字符串显示出来。
         */

        getCardData();
        getNoLinkData();

        //选项1
        options1Items.add(new ProvinceBean(0,"广东","描述部分","其他数据"));
        options1Items.add(new ProvinceBean(1,"湖南","描述部分","其他数据"));
        options1Items.add(new ProvinceBean(2,"广西","描述部分","其他数据"));

        //选项2
        ArrayList<String> options2Items_01 = new ArrayList<>();
        options2Items_01.add("广州");
        options2Items_01.add("佛山");
        options2Items_01.add("东莞");
        options2Items_01.add("珠海");
        ArrayList<String> options2Items_02 = new ArrayList<>();
        options2Items_02.add("长沙");
        options2Items_02.add("岳阳");
        options2Items_02.add("株洲");
        options2Items_02.add("衡阳");
        ArrayList<String> options2Items_03 = new ArrayList<>();
        options2Items_03.add("桂林");
        options2Items_03.add("玉林");
        options2Items.add(options2Items_01);
        options2Items.add(options2Items_02);
        options2Items.add(options2Items_03);

        /*--------数据源添加完毕---------*/
    }

    /**
     * 初始化条件选择器
     * */
    private void initOptionPicker() {

        /**
         * 注意 :如果是三级联动的数据(省市区等),请参照 JsonDataActivity 类里面的写法。
         */

        pvOptions = new OptionsPickerView.Builder(this, new OptionsPickerView.OnOptionsSelectListener() {
            @Override
            public void onOptionsSelect(int options1, int options2, int options3, View v) {
                //返回的分别是三个级别的选中位置
                String tx = options1Items.get(options1).getPickerViewText()
                        + options2Items.get(options1).get(options2)
                       /* + options3Items.get(options1).get(options2).get(options3).getPickerViewText()*/;
//                btn_Options.setText(tx);
                Toast.makeText(Main2Activity.this,tx,Toast.LENGTH_SHORT).show();
            }
        })
                .setTitleText("城市选择")
                .setContentTextSize(20)//设置滚轮文字大小
                .setDividerColor(Color.GREEN)//设置分割线的颜色
                .setSelectOptions(0,1)//默认选中项
                .setBgColor(Color.BLACK)
                .setTitleBgColor(Color.DKGRAY)
                .setTitleColor(Color.LTGRAY)
                .setCancelColor(Color.YELLOW)
                .setSubmitColor(Color.YELLOW)
                .setTextColorCenter(Color.LTGRAY)
                .isCenterLabel(false) //是否只显示中间选中项的label文字,false则每项item全部都带有label。
                .setLabels("省","市","区")
                .build();

        //pvOptions.setSelectOptions(1,1);

        /*pvOptions.setPicker(options1Items);//一级选择器*/
        pvOptions.setPicker(options1Items, options2Items);//二级选择器
        /*pvOptions.setPicker(options1Items, options2Items,options3Items);//三级选择器*/

    }

    /**
     * 初始化自定义选项选择器
     * */
    private void initCustomOptionPicker() {//条件选择器初始化,自定义布局
        /**
         * @description
         *
         * 注意事项:
         * 自定义布局中,id为 optionspicker 或者 timepicker 的布局以及其子控件必须要有,否则会报空指针。
         * 具体可参考demo 里面的两个自定义layout布局。
         */
        pvCustomOptions = new OptionsPickerView.Builder(this, new OptionsPickerView.OnOptionsSelectListener() {
            @Override
            public void onOptionsSelect(int options1, int option2, int options3, View v) {
                //返回的分别是三个级别的选中位置
                String tx = cardItem.get(options1).getPickerViewText();
//                btn_CustomOptions.setText(tx);
                Toast.makeText(Main2Activity.this,tx,Toast.LENGTH_SHORT).show();
            }
        })
                .setLayoutRes(R.layout.pickerview_custom_options, new CustomListener() {
                    @Override
                    public void customLayout(View v) {
                        final TextView tvSubmit = (TextView) v.findViewById(R.id.tv_finish);
                        final TextView tvAdd = (TextView) v.findViewById(R.id.tv_add);
                        ImageView ivCancel = (ImageView) v.findViewById(R.id.iv_cancel);
                        tvSubmit.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                pvCustomOptions.returnData();
                            }
                        });
                        ivCancel.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                pvCustomOptions.dismiss();
                            }
                        });

                        tvAdd.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                getCardData();
                                pvCustomOptions.setPicker(cardItem);
                            }
                        });

                    }
                })
                .isDialog(true)
                .build();

        pvCustomOptions.setPicker(cardItem);//添加数据

    }

    /**
     * 添加油卡信息
     * */
    private void getCardData() {
        for (int i = 0; i < 5; i++) {
            cardItem.add(new CardBean(i, "No.ABC12345 " + i));
        }
    }

    /**
     * 添加无联动数据
     * */
    private void getNoLinkData() {
        food.add("肯德基");
        food.add("麦当劳");
        food.add("披萨");

        clothes.add("耐克");
        clothes.add("阿迪");
        clothes.add("匡威");

        computer.add("华硕");
        computer.add("联想");
        computer.add("苹果");
        computer.add("惠普");
    }

    /**
     * @describe 时间显示样式
     * @params Date
     * @return 时间
     **/
    private String getTime(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//时间显示样式,可选
        return format.format(date);
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_Time && pvTime != null) {
            // pvTime.setDate(Calendar.getInstance());
           /* pvTime.show(); //show timePicker*/
            pvTime.show(v);//弹出时间选择器,传递参数过去,回调的时候则可以绑定此view
        } else if (v.getId() == R.id.btn_Options && pvOptions != null) {
            pvOptions.show(); //弹出条件选择器
        } else if (v.getId() == R.id.btn_CustomOptions && pvCustomOptions != null) {
            pvCustomOptions.show(); //弹出自定义条件选择器
        }else if (v.getId() == R.id.btn_CustomTime && pvCustomTime != null) {
            pvCustomTime.show(); //弹出自定义时间选择器
        }else if (v.getId() == R.id.btn_no_linkage&& pvNoLinkOptions !=null){//不联动数据选择器
            pvNoLinkOptions.show();
        }else if (v.getId() == R.id.btn_GotoJsonData){//跳转到 省市区解析示例页面
            startActivity(new Intent(Main2Activity.this,JsonDataActivity.class));
        }
    }
}

JsonDataActivity 代码

package com.e_valmont.look_lookdemo;

import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
import com.bigkoo.pickerview.OptionsPickerView;
import com.google.gson.Gson;
import org.json.JSONArray;
import java.util.ArrayList;

/***
 * 解析Json文件,并三级联动显示
 */

public class JsonDataActivity extends AppCompatActivity implements View.OnClickListener{
    /*省市区数据集合*/
    private ArrayList<JsonBean> options1Items = new ArrayList<>();
    private ArrayList<ArrayList<String>> options2Items = new ArrayList<>();
    private ArrayList<ArrayList<ArrayList<String>>> options3Items = new ArrayList<>();

    private Thread thread;
    /*解析状态*/
    private static final int MSG_LOAD_DATA = 0x0001;
    private static final int MSG_LOAD_SUCCESS = 0x0002;
    private static final int MSG_LOAD_FAILED = 0x0003;

    private boolean isLoaded = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_json_data);
        initView();
    }

    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_LOAD_DATA:
                    if (thread==null){//如果已创建就不再重新创建子线程了

                        Toast.makeText(JsonDataActivity.this,"开始解析数据",Toast.LENGTH_SHORT).show();
                        thread = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                // 写子线程中的操作,解析省市区数据
                                initJsonData();
                            }
                        });
                        thread.start();
                    }
                    break;

                case MSG_LOAD_SUCCESS:
                    Toast.makeText(JsonDataActivity.this,"解析数据成功",Toast.LENGTH_SHORT).show();
                    isLoaded = true;
                    break;

                case MSG_LOAD_FAILED:
                    Toast.makeText(JsonDataActivity.this,"解析数据失败",Toast.LENGTH_SHORT).show();
                    break;

            }
        }
    };

    private void initView() {
        findViewById(R.id.btn_data).setOnClickListener(this);
        findViewById(R.id.btn_show).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_data:
                mHandler.sendEmptyMessage(MSG_LOAD_DATA);
                break;
            case R.id.btn_show:
                if (isLoaded){
                    ShowPickerView();
                }else {
                    Toast.makeText(JsonDataActivity.this,"数据暂未解析成功,请等待",Toast.LENGTH_SHORT).show();
                }

                break;

        }

    }

    /**
     * 弹出选择器
     * */
    private void ShowPickerView() {

        OptionsPickerView pvOptions = new OptionsPickerView.Builder(this, new OptionsPickerView.OnOptionsSelectListener() {
            @Override
            public void onOptionsSelect(int options1, int options2, int options3, View v) {
                //返回的分别是三个级别的选中位置
                String tx = options1Items.get(options1).getPickerViewText()+
                        options2Items.get(options1).get(options2)+
                        options3Items.get(options1).get(options2).get(options3);

                Toast.makeText(JsonDataActivity.this,tx,Toast.LENGTH_SHORT).show();
            }
        })

                .setTitleText("城市选择")
                .setDividerColor(Color.BLACK)
                .setTextColorCenter(Color.BLACK) //设置选中项文字颜色
                .setContentTextSize(20)
                .setOutSideCancelable(false)// default is true
                .build();

        /*pvOptions.setPicker(options1Items);//一级选择器
        pvOptions.setPicker(options1Items, options2Items);//二级选择器*/
        pvOptions.setPicker(options1Items, options2Items,options3Items);//三级选择器
        pvOptions.show();
    }

    /**
     * 解析数据
     * */
    private void initJsonData() {

        /**
         * 注意:assets 目录下的Json文件仅供参考,实际使用可自行替换文件
         * 关键逻辑在于循环体
         * */
        String JsonData = new GetJsonDataUtil().getJson(this,"province.json");//获取assets目录下的json文件数据

        ArrayList<JsonBean> jsonBean = parseData(JsonData);//用Gson 转成实体

        /**
         * 添加省份数据
         *
         * 注意:如果是添加的JavaBean实体,则实体类需要实现 IPickerViewData 接口,
         * PickerView会通过getPickerViewText方法获取字符串显示出来。
         */
        options1Items = jsonBean;

        for (int i=0;i<jsonBean.size();i++){//遍历省份
            ArrayList<String> CityList = new ArrayList<>();//该省的城市列表(第二级)
            ArrayList<ArrayList<String>> Province_AreaList = new ArrayList<>();//该省的所有地区列表(第三极)

            for (int c=0; c<jsonBean.get(i).getCityList().size(); c++){//遍历该省份的所有城市
                String CityName = jsonBean.get(i).getCityList().get(c).getName();
                CityList.add(CityName);//添加城市

                ArrayList<String> City_AreaList = new ArrayList<>();//该城市的所有地区列表

                //如果无地区数据,建议添加空字符串,防止数据为null 导致三个选项长度不匹配造成崩溃
                if (jsonBean.get(i).getCityList().get(c).getArea() == null
                        ||jsonBean.get(i).getCityList().get(c).getArea().size()==0) {
                    City_AreaList.add("");
                }else {

                    for (int d=0; d < jsonBean.get(i).getCityList().get(c).getArea().size(); d++) {//该城市对应地区所有数据
                        String AreaName = jsonBean.get(i).getCityList().get(c).getArea().get(d);

                        City_AreaList.add(AreaName);//添加该城市所有地区数据
                    }
                }
                Province_AreaList.add(City_AreaList);//添加该省所有地区数据
            }

            /**
             * 添加城市数据
             */
            options2Items.add(CityList);

            /**
             * 添加地区数据
             */
            options3Items.add(Province_AreaList);
        }

        mHandler.sendEmptyMessage(MSG_LOAD_SUCCESS);

    }

    /**
     * Gson 解析
     * */
    public ArrayList<JsonBean> parseData(String result) {
        ArrayList<JsonBean> detail = new ArrayList<>();
        try {
            JSONArray data = new JSONArray(result);
            Gson gson = new Gson();
            for (int i = 0; i < data.length(); i++) {
                JsonBean entity = gson.fromJson(data.optJSONObject(i).toString(), JsonBean.class);
                detail.add(entity);
            }
        } catch (Exception e) {
            e.printStackTrace();
            mHandler.sendEmptyMessage(MSG_LOAD_FAILED);
        }
        return detail;
    }
}

CardBean 实体类代码

package com.e_valmont.look_lookdemo;

import com.bigkoo.pickerview.model.IPickerViewData;

/**
 * 油卡实体类
 */

public class CardBean implements IPickerViewData {
    int id;
    String cardNo;

    public CardBean(int id, String cardNo) {
        this.id = id;
        this.cardNo = cardNo;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getCardNo() {
        return cardNo;
    }

    public void setCardNo(String cardNo) {
        this.cardNo = cardNo;
    }

    @Override
    public String getPickerViewText() {
        return cardNo;
    }
}

ProvinceBean 实体类代码

package com.e_valmont.look_lookdemo;

import com.bigkoo.pickerview.model.IPickerViewData;

/**
 * 省份实体类
 */

public class ProvinceBean implements IPickerViewData {
    private long id;
    private String name;
    private String description;
    private String others;

    public ProvinceBean(long id,String name,String description,String others){
        this.id = id;
        this.name = name;
        this.description = description;
        this.others = others;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getOthers() {
        return others;
    }

    public void setOthers(String others) {
        this.others = others;
    }

    //这个用来显示在PickerView上面的字符串,PickerView会通过getPickerViewText方法获取字符串显示出来。
    @Override
    public String getPickerViewText() {
        return name;
    }
}

JsonBean 实体类代码

package com.e_valmont.look_lookdemo;

import com.bigkoo.pickerview.model.IPickerViewData;

import java.util.List;

/**
 * 省市区实体类
 */

public class JsonBean  implements IPickerViewData {


    /**
     * name : 省份
     * city : [{"name":"北京市","area":["东城区","西城区","崇文区","宣武区","朝阳区"]}]
     */

    private String name;
    private List<CityBean> city;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<CityBean> getCityList() {
        return city;
    }

    public void setCityList(List<CityBean> city) {
        this.city = city;
    }

    // 实现 IPickerViewData 接口,
    // 这个用来显示在PickerView上面的字符串,
    // PickerView会通过IPickerViewData获取getPickerViewText方法显示出来。
    @Override
    public String getPickerViewText() {
        return this.name;
    }



    public static class CityBean {
        /**
         * name : 城市
         * area : ["东城区","西城区","崇文区","昌平区"]
         */

        private String name;
        private List<String> area;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public List<String> getArea() {
            return area;
        }

        public void setArea(List<String> area) {
            this.area = area;
        }
    }
}

GetJsonDataUtil 工具类

package com.e_valmont.look_lookdemo;

import android.content.Context;
import android.content.res.AssetManager;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 解析本地Json文件工具类
 */

public class GetJsonDataUtil {
    public String getJson(Context context, String fileName) {

        StringBuilder stringBuilder = new StringBuilder();
        try {
            AssetManager assetManager = context.getAssets();
            BufferedReader bf = new BufferedReader(new InputStreamReader(assetManager.open(fileName)));
            String line;
            while ((line = bf.readLine()) != null) {
                stringBuilder.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuilder.toString();
    }
}

activity_main2.xml布局代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <Button
        android:id="@+id/btn_Time"
        android:layout_margin="10dp"
        android:text="时间选择器"
        android:layout_width="match_parent"
        android:layout_height="50dp"/>
    <Button
        android:id="@+id/btn_Options"
        android:layout_margin="10dp"
        android:layout_below="@+id/tvTime"
        android:text="选项选择器"
        android:layout_width="match_parent"
        android:layout_height="50dp"/>

    <Button
        android:id="@+id/btn_CustomTime"
        android:layout_margin="10dp"
        android:layout_below="@+id/tvTime"
        android:text="自定义时间选择器"
        android:layout_width="match_parent"
        android:layout_height="50dp"/>

    <Button
        android:id="@+id/btn_CustomOptions"
        android:layout_margin="10dp"
        android:layout_below="@+id/tvTime"
        android:text="自定义选项选择器"
        android:layout_width="match_parent"
        android:layout_height="50dp"/>

    <Button
        android:id="@+id/btn_no_linkage"
        android:layout_margin="10dp"
        android:layout_below="@+id/tvTime"
        android:text="条件选择器(不联动)"
        android:layout_width="match_parent"
        android:layout_height="50dp"/>

    <Button
        android:id="@+id/btn_GotoJsonData"
        android:layout_margin="10dp"
        android:layout_below="@+id/tvTime"
        android:text="省市区Json文件解析示例"
        android:layout_width="match_parent"
        android:layout_height="50dp"/>

</LinearLayout>

activity_json_data.xml布局代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/activity_json_data"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              android:gravity="center"
              android:paddingBottom="@dimen/activity_vertical_margin"
              android:paddingLeft="@dimen/activity_horizontal_margin"
              android:paddingRight="@dimen/activity_horizontal_margin"
              android:paddingTop="@dimen/activity_vertical_margin">

    <Button
        android:id="@+id/btn_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="解析数据"/>

    <Button
        android:id="@+id/btn_show"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="弹出省市区选择器"
        android:layout_marginTop="@dimen/activity_horizontal_margin" />

</LinearLayout>

pickerview_custom_time自定义时间选择器布局.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#EEEEEE">

        <View
            android:layout_width="match_parent"
            android:layout_height="0.5dp"
            android:background="#aaa" />

        <ImageView
            android:id="@+id/iv_cancel"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="17dp"
            android:padding="8dp"
            android:src="@drawable/to_down" />

        <TextView
            android:id="@+id/tv_finish"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="17dp"
            android:padding="8dp"
            android:text="完成"
            android:textColor="#24AD9D"
            android:textSize="18sp" />

        <View
            android:layout_width="match_parent"
            android:layout_height="0.5dp"
            android:background="#aaa" />
    </RelativeLayout>


    <!--此部分需要完整复制过去,删减或者更改ID会导致初始化找不到内容而报空-->
    <LinearLayout
        android:id="@+id/timepicker"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:orientation="horizontal">

        <com.bigkoo.pickerview.lib.WheelView
            android:id="@+id/year"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <com.bigkoo.pickerview.lib.WheelView

            android:id="@+id/month"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1.1" />

        <com.bigkoo.pickerview.lib.WheelView
            android:id="@+id/day"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1.1" />

        <com.bigkoo.pickerview.lib.WheelView
            android:id="@+id/hour"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1.1" />

        <com.bigkoo.pickerview.lib.WheelView
            android:id="@+id/min"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1.1" />

        <com.bigkoo.pickerview.lib.WheelView
            android:id="@+id/second"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1.1" />
    </LinearLayout>


</LinearLayout>

pickerview_custom_options.xml自定义选项选择器布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#EEEEEE">

        <View
            android:layout_width="match_parent"
            android:layout_height="0.5dp"
            android:background="#aaa" />

        <ImageView
            android:id="@+id/iv_cancel"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="17dp"
            android:padding="8dp"
            android:src="@drawable/to_down" />

        <TextView
            android:id="@+id/tv_finish"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="17dp"
            android:padding="8dp"
            android:text="完成"
            android:textColor="#24AD9D"
            android:textSize="18sp" />

        <View
            android:layout_width="match_parent"
            android:layout_height="0.5dp"
            android:background="#aaa" />
    </RelativeLayout>

    <!--此部分需要完整复制过去,删减或者更改ID会导致初始化找不到内容而报空-->
    <LinearLayout
        android:id="@+id/optionspicker"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:orientation="horizontal">

        <com.bigkoo.pickerview.lib.WheelView
            android:id="@+id/options1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <com.bigkoo.pickerview.lib.WheelView
            android:id="@+id/options2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <com.bigkoo.pickerview.lib.WheelView
            android:id="@+id/options3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1" />
    </LinearLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:background="#24ad9d" />

    <TextView
        android:id="@+id/tv_add"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#E5E9EC"
        android:gravity="center"
        android:text="+ 添加加油卡"
        android:textColor="#24AD9D"
        android:textSize="18sp" />

</LinearLayout>

总结:TimePickerView封装的很灵活,基本可以满足日常开发,滚动日期显示(任意格式)、省市区三级联动、无联动选项选择器等等。代码量大,但是逻辑清晰,各位根据需求使用代码。

参考文章:http://www.jianshu.com/p/d3cab4714b8a 第155条

上一篇 下一篇

猜你喜欢

热点阅读