android 继承popupWindow实现时间、地址选择器

简介: 日期选择、地址选择,都是开发中少不了的功能,下面通过自定义的形式,同一套代码实现时间选择与地址选择,通过构造方法的不同来实现。

今天自定义了一个选择器,可以选择是时间还是地址,使用起来很方便,继承popupWindow实现的,代码很简单,使用也简单,效果图如下
image.png
image.png

先看下使用方法
时间选择器的使用
image.png
默认是显示年月日时分秒,可以通过构造方法传入的type值来设置要显示的日期格式,如type为2的话,显示的是年月日时分,没有秒,具体看完整代码中的解释,备注很清楚。

地址选择器的使用
image.png
关于地址选择器,如果使用xml文件引入地址信息,在这里使用的是SAX方法对xml进行了解析,至于xml地址资源,可自行去网上寻找,很容易找到,这里截个图个大家看一下,主要一点要注意一下,标签名跟格式要一致,即使网上找到的标签名不一样,手动修改一下就好,截图如下:
image.png

可以看到时间选择器跟地址选择器在使用上的区别在于调用不同的构造方法,在这个自定义组件中,提供了三个构造方法,备注很清晰
image.png

选择器是使用了NumberPicker来实现的,也还是比较简单。

在activity的使用中,show()方法用于从底部弹出时间选择器,ClickCallBack为回调方法,用于接收左右两边的两个按钮的点击事件,confirm回调方法中返回的还是一个json对象,方便使用。

另外代码中还提供了两个方法用于修改左右两个两个TextView的文本内容,完整代码如下

java版本

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.NumberPicker;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
 
import org.json.JSONException;
import org.json.JSONObject;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
 
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
 
public class TimeSelector extends PopupWindow {
 
    private DivNumberPicker mYearPicker;
    private DivNumberPicker mMonthPicker;
    private DivNumberPicker mDayPicker;
    private DivNumberPicker mHourPicker;
    private DivNumberPicker mMinutePicker;
    private DivNumberPicker mSecondPicker;
 
    private NumberPicker mProvincePicker;
    private NumberPicker mCityPicker;
    private NumberPicker mDistrictPicker;
 
    private TextView mTvConfirm, mTvCancel;
 
 
    //数据集合__混合文字
    private List<String> mYearList = new ArrayList<>();
    private List<String> mMonthList = new ArrayList<>();
    private List<String> mDayList = new ArrayList<>();
    private List<String> mHourList = new ArrayList<>();
    private List<String> mMinuteList = new ArrayList<>();
    private List<String> mSecondList = new ArrayList<>();
    //纯数字
    private List<Integer> mYearNumList = new ArrayList<>();
    private List<Integer> mMonthNumList = new ArrayList<>();
    private List<Integer> mDayNumList = new ArrayList<>();
    private List<Integer> mHourNumList = new ArrayList<>();
    private List<Integer> mMinuteNumList = new ArrayList<>();
    private List<Integer> mSecondNumList = new ArrayList<>();
 
    //地址数据集合
    private List<String> mProvinceList = new ArrayList<>();
    private Map<String, List<String>> mCityMap = new HashMap<>();
    private Map<String, List<String>> mDistrictMap = new HashMap<>();
 
    private String[] mCityArray;
    private String[] mDistrictArray;
    private String[] provinceStrArray;
 
    //当前选择的数据
    private String mCurSelProvince = "";
    private String mCurSelCity = "";
    private String mCurSelDistrict = "";
 
    private Context mContext;
    private ClickCallBack mClickCallBack;
    private String mStrLeft = "取消";
    private String mStrRight = "确认";
 
    private int mType = 1;//1.年月日时分秒,2.年月日时分 3.年月日时,4.年月日,5.时分秒,6.时分
    private String mStrType = "time";//time:表示时间选择器,address:表示地址选择器
    private String mStrAddressPath;//地址资源
 
    /**
     * 使用此构造方法,则默认mType=1的情况下的时间选择器
     *
     * @param context 上下文对象
     */
    public TimeSelector(Context context) {
        super(context);
        mContext = context;
        initView(context);
    }
 
    /**
     * 使用此构造方法,mType可变的时间选择器
     *
     * @param context 上下文对象
     * @param mType   可变的mType
     */
    public TimeSelector(Context context, int mType) {
        super(context);
        mContext = context;
        this.mType = mType;
        initView(context);
    }
 
    /**
     * 使用此构造方法,则为地址选择器
     *
     * @param context     上下文对象
     * @param addressPath 地址资源文件路径,一般是assets文件夹下的xml文件
     */
    public TimeSelector(Context context, String addressPath) {
        super(context);
        mContext = context;
        mStrType = "address";
        mStrAddressPath = addressPath;
        initView(context);
    }
 
    private void initView(final Context context) {
        //获取屏幕宽高信息
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics dm = new DisplayMetrics();
        if (wm != null) {
            wm.getDefaultDisplay().getMetrics(dm);
        }
        this.setHeight(dm.heightPixels / 3);
        this.setWidth(dm.widthPixels);
 
        //动态创建外层布局
        LinearLayout llContent = new LinearLayout(context);
        llContent.setOrientation(LinearLayout.VERTICAL);
        llContent.setBackgroundColor(Color.WHITE);
 
        RelativeLayout rlTitle = new RelativeLayout(context);
        rlTitle.setBackgroundColor(Color.WHITE);
 
        //动态创建两个TextView
        mTvCancel = new TextView(context);
        mTvCancel.setText(mStrLeft);
        mTvCancel.setTextSize(15);
 
        mTvConfirm = new TextView(context);
        mTvConfirm.setText(mStrRight);
        mTvConfirm.setTextSize(15);
 
        rlTitle.addView(mTvCancel);
        rlTitle.addView(mTvConfirm);
 
        RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams) mTvCancel.getLayoutParams();
        rlp.setMargins(14, 12, 0, 12);
        rlp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
        mTvCancel.setLayoutParams(rlp);
 
        RelativeLayout.LayoutParams rlp1 = (RelativeLayout.LayoutParams) mTvConfirm.getLayoutParams();
        rlp1.setMargins(0, 12, 14, 12);
        rlp1.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        mTvConfirm.setLayoutParams(rlp1);
 
        //动态创建NumberPicker
        LinearLayout llDataSel = new LinearLayout(context);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        llDataSel.setOrientation(LinearLayout.HORIZONTAL);
        lp.weight = 1;
        lp.setMargins(7, 0, 7, 0);
        if ("time".equals(mStrType)) {
            mYearPicker = new DivNumberPicker(context);
            mMonthPicker = new DivNumberPicker(context);
            mDayPicker = new DivNumberPicker(context);
            mHourPicker = new DivNumberPicker(context);
            mMinutePicker = new DivNumberPicker(context);
            mSecondPicker = new DivNumberPicker(context);
 
            mYearPicker.setLayoutParams(lp);
            mMonthPicker.setLayoutParams(lp);
            mDayPicker.setLayoutParams(lp);
            mHourPicker.setLayoutParams(lp);
            mMinutePicker.setLayoutParams(lp);
            mSecondPicker.setLayoutParams(lp);
 
            llDataSel.addView(mYearPicker);
            llDataSel.addView(mMonthPicker);
            llDataSel.addView(mDayPicker);
            llDataSel.addView(mHourPicker);
            llDataSel.addView(mMinutePicker);
            llDataSel.addView(mSecondPicker);
        } else if ("address".equals(mStrType)) {
            mProvincePicker = new DivNumberPicker(context);
            mCityPicker = new DivNumberPicker(context);
            mDistrictPicker = new DivNumberPicker(context);
 
            mProvincePicker.setLayoutParams(lp);
            mCityPicker.setLayoutParams(lp);
            mDistrictPicker.setLayoutParams(lp);
 
            llDataSel.addView(mProvincePicker);
            llDataSel.addView(mCityPicker);
            llDataSel.addView(mDistrictPicker);
        }
 
        llContent.addView(rlTitle);
        llContent.addView(llDataSel);
 
        this.setContentView(llContent);
 
        if ("time".equals(mStrType))
            initData(mType);
        else if ("address".equals(mStrType))
            getAddressData(context, mStrAddressPath);
        initListener();
    }
 
    /**
     * 添加监听方法
     */
    private void initListener() {
        mTvConfirm.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mClickCallBack != null) {
                    if ("time".equals(mStrType))
                        mClickCallBack.confirm(getResult());
                    else if ("address".equals(mStrType))
                        mClickCallBack.confirm(getAddressResult());
                }
                setAlpha(1.0f);
            }
        });
 
        mTvCancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mClickCallBack != null)
                    mClickCallBack.cancel();
                setAlpha(1.0f);
            }
        });
        this.setOnDismissListener(new OnDismissListener() {
            @Override
            public void onDismiss() {
                setAlpha(1.0f);
            }
        });
 
        if (mProvincePicker != null) {
            //监听事件
            mProvincePicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
                /**
                 * 每当选择的值改变时都会调用一次
                 * @param oldVal 改变前的值
                 * @param newVal 改变后的值
                 */
                @Override
                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
                    //改变市,区的值
                    mCurSelProvince = provinceStrArray[picker.getValue()];
                    mCityArray = mCityMap.get(mCurSelProvince).toArray(new String[0]);
                    mCityPicker.setDisplayedValues(null);
                    mCityPicker.setMaxValue(mCityArray.length - 1); //设置最大值
                    mCityPicker.setDisplayedValues(mCityArray);
 
                    mCurSelCity = mCityArray[0];
                    mDistrictArray = mDistrictMap.get(mCurSelCity).toArray(new String[0]);
                    mDistrictPicker.setDisplayedValues(null);
                    mDistrictPicker.setMaxValue(mDistrictArray.length - 1); //设置最大值
                    mDistrictPicker.setDisplayedValues(mDistrictArray);
 
                }
            });
        }
 
        if (mCityPicker != null) {
            mCityPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
                /**
                 * 每当选择的值改变时都会调用一次
                 * @param oldVal 改变前的值
                 * @param newVal 改变后的值
                 */
                @Override
                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
                    //获取当前位置,设置地区
                    mCurSelCity = mCityArray[picker.getValue()];
                    mDistrictArray = mDistrictMap.get(mCurSelCity).toArray(new String[0]);
                    mDistrictPicker.setDisplayedValues(null);
                    mDistrictPicker.setMaxValue(mDistrictArray.length - 1); //设置最大值
                    mDistrictPicker.setDisplayedValues(mDistrictArray);
 
                }
            });
        }
 
        if (mDistrictPicker != null) {
            mDistrictPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
                /**
                 * 每当选择的值改变时都会调用一次
                 * @param oldVal 改变前的值
                 * @param newVal 改变后的值
                 */
                @Override
                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
                    mCurSelDistrict = mDistrictArray[picker.getValue()];
                }
            });
        }
 
    }
 
    /**
     * 显示时间选择器
     *
     * @param view
     */
    public void show(View view) {
        this.setOutsideTouchable(true);
        this.showAtLocation(view, Gravity.BOTTOM, 0, 0);
        setAlpha(0.3f);
    }
 
    /**
     * 改变背景透明度
     *
     * @param value
     */
    private void setAlpha(Float value) {
        WindowManager.LayoutParams layoutParams = ((Activity) mContext).getWindow().getAttributes();
        layoutParams.alpha = value;
        ((Activity) mContext).getWindow().setAttributes(layoutParams);
    }
 
    /**
     * 设置左边文本的内容
     *
     * @param o
     */
    public void setLeftTextContent(Object o) {
        if (mTvCancel == null)
            return;
        if (o instanceof String)
            mTvCancel.setText((String) o);
        else if (o instanceof Integer)
            mTvCancel.setText((Integer) o);
        else
            mTvCancel.setText(mStrLeft);
    }
 
    /**
     * 设置左边文本的内容
     *
     * @param o
     */
    public void setRightTextContent(Object o) {
        if (mTvConfirm == null)
            return;
        if (o instanceof String)
            mTvConfirm.setText((String) o);
        else if (o instanceof Integer)
            mTvConfirm.setText((Integer) o);
        else
            mTvConfirm.setText(mStrRight);
    }
 
    private JSONObject getAddressResult() {
        JSONObject object = new JSONObject();
        if (!TextUtils.isEmpty(mCurSelProvince) || !TextUtils.isEmpty(mCurSelCity) || !TextUtils.isEmpty(mCurSelDistrict)) {
            try {
                object.put("province", mCurSelProvince);
                object.put("city", mCurSelCity);
                object.put("district", mCurSelDistrict);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return object;
    }
 
    /**
     * 设置选中后的返回数据,以json数据的形式返回
     *
     * @return
     */
    private JSONObject getResult() {
        //数据回调
        int yearPos = mYearPicker.getValue();
        int monthPos = mMonthPicker.getValue();
        int dayPos = mDayPicker.getValue();
        int hourPos = mHourPicker.getValue();
        int minutePos = mMinutePicker.getValue();
        int secondPos = mSecondPicker.getValue();
        JSONObject object = new JSONObject();
        try {
            switch (mType) {
                case 1:
                    object.put("year", mYearNumList.get(yearPos).toString());
                    object.put("month", mMonthNumList.get(monthPos).toString());
                    object.put("day", mDayNumList.get(dayPos).toString());
                    object.put("hour", mHourNumList.get(hourPos).toString());
                    object.put("minute", mMinuteNumList.get(minutePos).toString());
                    object.put("second", mSecondNumList.get(secondPos).toString());
                    break;
                case 2:
                    object.put("year", mYearNumList.get(yearPos).toString());
                    object.put("month", mMonthNumList.get(monthPos).toString());
                    object.put("day", mDayNumList.get(dayPos).toString());
                    object.put("hour", mHourNumList.get(hourPos).toString());
                    object.put("minute", mMinuteNumList.get(minutePos).toString());
                    break;
                case 3:
                    object.put("year", mYearNumList.get(yearPos).toString());
                    object.put("month", mMonthNumList.get(monthPos).toString());
                    object.put("day", mDayNumList.get(dayPos).toString());
                    object.put("hour", mHourNumList.get(hourPos).toString());
                    break;
                case 4:
                    object.put("year", mYearNumList.get(yearPos).toString());
                    object.put("month", mMonthNumList.get(monthPos).toString());
                    object.put("day", mDayNumList.get(dayPos).toString());
                    break;
                case 5:
                    object.put("hour", mHourNumList.get(hourPos).toString());
                    object.put("minute", mMinuteNumList.get(minutePos).toString());
                    object.put("second", mSecondNumList.get(secondPos).toString());
                case 6:
                    object.put("hour", mHourNumList.get(hourPos).toString());
                    object.put("minute", mMinuteNumList.get(minutePos).toString());
                    break;
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return object;
    }
 
    @SuppressLint("DefaultLocale")
    private void initData(int type) {
        //根据type现实ui__1年月日时分秒,2年月日时分 3年月日时,4年月日,5时分秒,6时分
        switch (type) {
            case 2:
                mSecondPicker.setVisibility(View.GONE);
                break;
            case 3:
                mMinutePicker.setVisibility(View.GONE);
                mSecondPicker.setVisibility(View.GONE);
                break;
            case 4:
                mHourPicker.setVisibility(View.GONE);
                mMinutePicker.setVisibility(View.GONE);
                mSecondPicker.setVisibility(View.GONE);
                break;
            case 5:
                mYearPicker.setVisibility(View.GONE);
                mMonthPicker.setVisibility(View.GONE);
                mDayPicker.setVisibility(View.GONE);
                break;
            case 6:
                mYearPicker.setVisibility(View.GONE);
                mMonthPicker.setVisibility(View.GONE);
                mDayPicker.setVisibility(View.GONE);
                mHourPicker.setVisibility(View.GONE);
                break;
        }
 
        //数据集合初始化
        //年
        Calendar startCal = Calendar.getInstance();
        startCal.setTimeInMillis(0);
        Calendar curCal = Calendar.getInstance();
        int startYear = startCal.get(Calendar.YEAR);
        int endYear = curCal.get(Calendar.YEAR);
 
        for (int i = endYear; i >= startYear; i--) {
            mYearList.add(i + "年");
            mYearNumList.add(i);
        }
        //月
        for (int i = 1; i <= 12; i++) {
            mMonthList.add(String.format("%02d", i) + "月");
            mMonthNumList.add(i);
        }
        //日
        int curDay = curCal.getActualMaximum(Calendar.DAY_OF_MONTH);//当前月份有多少天
        for (int i = 1; i <= curDay; i++) {
            mDayList.add(String.format("%02d", i) + "日");
            mDayNumList.add(i);
        }
        //时
        for (int i = 1; i <= 24; i++) {
            mHourList.add(String.format("%02d", i) + "时");
            mHourNumList.add(i);
        }
        //分
        for (int i = 1; i <= 60; i++) {
            mMinuteList.add(String.format("%02d", i) + "分");
            mMinuteNumList.add(i);
        }
        //秒
        for (int i = 1; i <= 60; i++) {
            mSecondList.add(String.format("%02d", i) + "秒");
            mSecondNumList.add(i);
        }
        //设置数据----------------------------------------------------------
        //获取当前初始化数据__月日时分秒
        int cMonth = curCal.get(Calendar.MONTH);//从0开始
        int cDay = curCal.get(Calendar.DATE) - 1;//日
        int cHour = curCal.get(Calendar.HOUR_OF_DAY) - 1;//时
        int cMinute = curCal.get(Calendar.MINUTE) - 1;//分
        int cSecond = curCal.get(Calendar.SECOND) - 1;//秒
 
        mYearPicker.setDisplayedValues(mYearList.toArray(new String[0]));
        mYearPicker.setMaxValue(mYearList.size() - 1); //设置最大值
        mYearPicker.setWrapSelectorWheel(true);
        mYearPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); //禁止输入
 
        mMonthPicker.setDisplayedValues(mMonthList.toArray(new String[0]));
        mMonthPicker.setMaxValue(mMonthList.size() - 1); //设置最大值
        mMonthPicker.setWrapSelectorWheel(true);
        mMonthPicker.setValue(cMonth);
        mMonthPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); //禁止输入
 
        mDayPicker.setDisplayedValues(mDayList.toArray(new String[0]));
        mDayPicker.setMaxValue(mDayList.size() - 1); //设置最大值
        mDayPicker.setWrapSelectorWheel(true);
        mDayPicker.setValue(cDay);
        mDayPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); //禁止输入
 
        mHourPicker.setDisplayedValues(mHourList.toArray(new String[0]));
        mHourPicker.setMaxValue(mHourList.size() - 1); //设置最大值
        mHourPicker.setWrapSelectorWheel(true);
        mHourPicker.setValue(cHour);
        mHourPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); //禁止输入
 
        mMinutePicker.setDisplayedValues(mMinuteList.toArray(new String[0]));
        mMinutePicker.setMaxValue(mMinuteList.size() - 1); //设置最大值
        mMinutePicker.setWrapSelectorWheel(true);
        mMinutePicker.setValue(cMinute);
        mMinutePicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); //禁止输入
 
        mSecondPicker.setDisplayedValues(mSecondList.toArray(new String[0]));
        mSecondPicker.setMaxValue(mSecondList.size() - 1); //设置最大值
        mSecondPicker.setWrapSelectorWheel(true);
        mSecondPicker.setValue(cSecond);
        mSecondPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); //禁止输入
    }
 
    private void getAddressData(Context context, String path) {
        List<AddressInfo> result = readXmlBySAX(context, path);
        //数据转换
        if (result != null) {
            for (AddressInfo cache : result) {
                mProvinceList.add(cache.getProvince());
                mCityMap.putAll(cache.getCityMap());
                mDistrictMap.putAll(cache.getDistrictMap());
            }
        }
        //转换完成__设置数据
        //省份
        provinceStrArray = mProvinceList.toArray(new String[0]);
        mProvincePicker.setDisplayedValues(provinceStrArray);
        mProvincePicker.setMaxValue(provinceStrArray.length - 1); //设置最大值,最大值是datas[3]
        mProvincePicker.setWrapSelectorWheel(true);
        mProvincePicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); //禁止输入
        mCurSelProvince = provinceStrArray[0];
        //城市
        mCityArray = mCityMap.get(mCurSelProvince).toArray(new String[0]);
        mCityPicker.setDisplayedValues(mCityArray);
        mCityPicker.setMaxValue(mCityArray.length - 1); //设置最大值
        mCityPicker.setWrapSelectorWheel(true);
        mCityPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); //禁止输入
        mCurSelCity = mCityArray[0];
        //市区
        mDistrictArray = mDistrictMap.get(mCurSelCity).toArray(new String[0]);
        mDistrictPicker.setDisplayedValues(mDistrictArray);
        mDistrictPicker.setMaxValue(mDistrictArray.length - 1); //设置最大值
        mDistrictPicker.setWrapSelectorWheel(true);
        mDistrictPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); //禁止输入
        mCurSelDistrict = mDistrictArray[0];
    }
 
    private List<AddressInfo> readXmlBySAX(Context context, String path) {
        try {
            InputStream in = context.getResources().getAssets().open(path);
            //【创建解析器】
            SAXParserFactory spf = SAXParserFactory.newInstance();
            SAXParser saxParser = spf.newSAXParser();
            AddressSaxHandler handler = new AddressSaxHandler();
            saxParser.parse(in, handler);
            in.close();
            return handler.getResult();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
 
 
    /**
     * 自定义NumberPicker ---------------------------------------------------------------
     */
    public class DivNumberPicker extends NumberPicker {
 
        public DivNumberPicker(Context context) {
            super(context);
        }
 
        public DivNumberPicker(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
 
        public DivNumberPicker(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
 
        @Override
        public void addView(View child) {
            super.addView(child);
            updateView(child);
        }
 
        @Override
        public void addView(View child, int index,
                            android.view.ViewGroup.LayoutParams params) {
            super.addView(child, index, params);
            updateView(child);
        }
 
        @Override
        public void addView(View child, android.view.ViewGroup.LayoutParams params) {
            super.addView(child, params);
            updateView(child);
        }
 
        public void updateView(View view) {
            if (view instanceof EditText) {
                //这里修改显示字体的属性,主要修改颜色
                ((EditText) view).setTextSize(12);
                ((EditText) view).setTextColor(Color.BLACK);
            }
        }
 
        @Override
        public void setDisplayedValues(String[] displayedValues) {
            super.setDisplayedValues(displayedValues);
            setNumberPickerDividerColor(this);
        }
 
        //设置分割线的颜色值
        private void setNumberPickerDividerColor(NumberPicker numberPicker) {
            Field[] pickerFields = NumberPicker.class.getDeclaredFields();
            for (Field pf : pickerFields) {
                if (pf.getName().equals("mSelectionDivider")) {
                    pf.setAccessible(true);
                    try {
                        //设置分割线的颜色值 透明
                        pf.set(numberPicker, new ColorDrawable(Color.BLUE));
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    } catch (Resources.NotFoundException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    break;
                }
            }
        }
    }
 
    /**
     * author:li
     * date:2020/6/21
     * desc:地址model:xml解释 --------------------------------------------------------------
     */
    public class AddressSaxHandler extends DefaultHandler {
        //解释结果结合
        private List<AddressInfo> result;
        private AddressInfo mCurrentInfo;
 
        private String mCurrentProvince = "";
        private String mCurrentCity = "";
 
        private String mTagName = "";
 
        List<AddressInfo> getResult() {
            return result;
        }
 
        @Override
        public void startDocument() throws SAXException {
            super.startDocument();
            result = new ArrayList<>();
        }
 
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            super.startElement(uri, localName, qName, attributes);
            if (localName.equals("province")) {
                mCurrentInfo = new AddressInfo();
                mCurrentInfo.setProvince(attributes.getValue("name"));
                mCurrentProvince = mCurrentInfo.getProvince();
            } else if (localName.equals("city")) {
                mCurrentCity = attributes.getValue("name");
                List<String> cityList = new ArrayList<>();
                if (mCurrentInfo.getCityMap().get(mCurrentProvince) == null) {
                    cityList.add(mCurrentCity);
                    mCurrentInfo.getCityMap().put(mCurrentProvince, cityList);
                } else {
                    cityList = mCurrentInfo.getCityMap().get(mCurrentProvince);
                    cityList.add(mCurrentCity);
                    mCurrentInfo.getCityMap().put(mCurrentProvince, cityList);
                }
            }
            mTagName = localName;
        }
 
 
        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            super.characters(ch, start, length);
            if (!TextUtils.isEmpty(mTagName)) {
                String data = new String(ch, start, length);
                if (mTagName.equals("district")) {
                    List<String> districtList = new ArrayList<>();
                    if (mCurrentInfo.getDistrictMap().get(mCurrentCity) == null) {
                        districtList.add(data);
                        mCurrentInfo.getDistrictMap().put(mCurrentCity, districtList);
                    } else {
                        districtList = mCurrentInfo.getDistrictMap().get(mCurrentCity);
                        districtList.add(data);
                        mCurrentInfo.getDistrictMap().put(mCurrentCity, districtList);
                    }
                }
            }
        }
 
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            super.endElement(uri, localName, qName);
            if (localName.equals("province")) {
                result.add(mCurrentInfo);
            }
            this.mTagName = null;
        }
    }
 
    /**
     * 地址实体类 ------------------------------------------------------------
     */
    class AddressInfo {
        private String province;
        private Map<String, List<String>> cityMap = new HashMap<>();
        private Map<String, List<String>> districtMap = new HashMap<>();
 
        String getProvince() {
            return province;
        }
 
        void setProvince(String province) {
            this.province = province;
        }
 
        Map<String, List<String>> getCityMap() {
            return cityMap;
        }
 
        public void setCityMap(Map<String, List<String>> cityMap) {
            this.cityMap = cityMap;
        }
 
        Map<String, List<String>> getDistrictMap() {
            return districtMap;
        }
 
        public void setDistrictMap(Map<String, List<String>> districtMap) {
            this.districtMap = districtMap;
        }
    }
 
    /**
     * 定义回调接口 ----------------------------------------------------------------------
     */
    public interface ClickCallBack {
        void cancel();
 
        void confirm(JSONObject jsonObject);
    }
 
    public void setmClickCallBack(ClickCallBack mClickCallBack) {
        this.mClickCallBack = mClickCallBack;
    }
}

kotlin版本

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.text.TextUtils
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.*
import org.json.JSONObject
import org.xml.sax.Attributes
import org.xml.sax.helpers.DefaultHandler
import java.lang.Exception
import java.util.*
import javax.xml.parsers.SAXParserFactory
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
 
class Selector : PopupWindow {
 
    private var mYearPicker: DivNumberPicker? = null
    private var mMonthPicker: DivNumberPicker? = null
    private var mDayPicker: DivNumberPicker? = null
    private var mHourPicker: DivNumberPicker? = null
    private var mMinutePicker: DivNumberPicker? = null
    private var mSecondPicker: DivNumberPicker? = null
 
    private var mProvincePicker: DivNumberPicker? = null
    private var mCityPicker: DivNumberPicker? = null
    private var mDistrictPicker: DivNumberPicker? = null
 
    private var mTvCancel: TextView? = null
    private var mTvConfirm: TextView? = null
 
    //数据集合__混合文字
    private val mYearList = ArrayList<String>()
    private val mMonthList = ArrayList<String>()
    private val mDayList = ArrayList<String>()
    private val mHourList = ArrayList<String>()
    private val mMinuteList = ArrayList<String>()
    private val mSecondList = ArrayList<String>()
    //纯数字
    private val mYearNumList = ArrayList<Int>()
    private val mMonthNumList = ArrayList<Int>()
    private val mDayNumList = ArrayList<Int>()
    private val mHourNumList = ArrayList<Int>()
    private val mMinuteNumList = ArrayList<Int>()
    private val mSecondNumList = ArrayList<Int>()
 
    //地址数据集合
    private val mProvinceList = ArrayList<String>()
    private val mCityMap = HashMap<String, List<String>>()
    private val mDistrictMap = HashMap<String, List<String>>()
 
    private var mCityArray: Array<String>? = null
    private var mDistrictArray: Array<String>? = null
    private var provinceStrArray: Array<String>? = null
 
    //当前选择的数据
    private var mCurSelProvince = ""
    private var mCurSelCity = ""
    private var mCurSelDistrict = ""
 
    private var mContext: Context? = null
    private var mType = 1
    private var mStrType = "time"
    private var mStrAddressPath = ""
    private var mStrLeft = "取消"
    private var mStrRight = "确认"
 
    private var mClickCallBack: ClickCallBack? = null
 
    constructor(context: Context?) : super(context) {
        mContext = context
        initView(context)
    }
 
    constructor(context: Context?, mType: Int) : super(context) {
        mContext = context
        this.mType = mType
        initView(context)
    }
 
    constructor(context: Context?, addressPath: String) : super(context) {
        mContext = context
        mStrType = "address"
        mStrAddressPath = addressPath
        initView(context)
    }
 
    @SuppressLint("ServiceCast")
    private fun initView(context: Context?) {
        //获取屏幕宽高信息
        val wm: WindowManager = context!!.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        val dm = DisplayMetrics()
        wm.defaultDisplay.getMetrics(dm)
        this.height = dm.heightPixels / 3
        this.width = dm.widthPixels
 
        //动态创建外层布局
        val llContent = LinearLayout(context)
        llContent.orientation = LinearLayout.VERTICAL
        llContent.setBackgroundColor(Color.WHITE)
 
        val rlTitle = RelativeLayout(context)
        rlTitle.setBackgroundColor(Color.WHITE)
 
        //动态创建两个TextView
        mTvCancel = TextView(context)
        mTvCancel!!.text = mStrLeft
        mTvCancel!!.textSize = 15f
 
        mTvConfirm = TextView(context)
        mTvConfirm!!.text = mStrRight
        mTvConfirm!!.textSize = 15f
 
        rlTitle.addView(mTvCancel)
        rlTitle.addView(mTvConfirm)
 
        val rlp = mTvCancel!!.layoutParams as RelativeLayout.LayoutParams
        rlp.setMargins(14, 12, 0, 12)
        rlp.addRule(RelativeLayout.ALIGN_PARENT_LEFT)
        mTvCancel!!.layoutParams = rlp
 
        val rlp1 = mTvConfirm!!.layoutParams as RelativeLayout.LayoutParams
        rlp1.setMargins(0, 12, 14, 12)
        rlp1.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
        mTvConfirm!!.layoutParams = rlp1
 
        //动态创建NumberPicker
        val llDataSel = LinearLayout(context)
        val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
        llDataSel.orientation = LinearLayout.HORIZONTAL
        lp.weight = 1f
        lp.setMargins(7, 0, 7, 0)
        if ("time" == mStrType) {
            mYearPicker = DivNumberPicker(context)
            mMonthPicker = DivNumberPicker(context)
            mDayPicker = DivNumberPicker(context)
            mHourPicker = DivNumberPicker(context)
            mMinutePicker = DivNumberPicker(context)
            mSecondPicker = DivNumberPicker(context)
 
            mYearPicker!!.layoutParams = lp
            mMonthPicker!!.layoutParams = lp
            mDayPicker!!.layoutParams = lp
            mHourPicker!!.layoutParams = lp
            mMinutePicker!!.layoutParams = lp
            mSecondPicker!!.layoutParams = lp
 
            llDataSel.addView(mYearPicker)
            llDataSel.addView(mMonthPicker)
            llDataSel.addView(mDayPicker)
            llDataSel.addView(mHourPicker)
            llDataSel.addView(mMinutePicker)
            llDataSel.addView(mSecondPicker)
        } else if ("address" == mStrType) {
            mProvincePicker = DivNumberPicker(context)
            mCityPicker = DivNumberPicker(context)
            mDistrictPicker = DivNumberPicker(context)
 
            mProvincePicker!!.layoutParams = lp
            mCityPicker!!.layoutParams = lp
            mDistrictPicker!!.layoutParams = lp
 
            llDataSel.addView(mProvincePicker)
            llDataSel.addView(mCityPicker)
            llDataSel.addView(mDistrictPicker)
        }
 
        llContent.addView(rlTitle)
        llContent.addView(llDataSel)
 
        this.contentView = llContent
 
        if ("time" == mStrType)
            initData(mType)
        else if ("address" == mStrType)
            getAddressData(context, mStrAddressPath)
        initListener()
    }
 
    /**
     * 初始化监听
     */
    private fun initListener() {
        mTvConfirm!!.setOnClickListener {
            if (mClickCallBack != null) {
                if ("time" == mStrType)
                    mClickCallBack!!.confirm(getResult())
                else if ("address" == mStrType)
                    mClickCallBack!!.confirm(getAddressResult())
                setAlpha(1.0f)
            }
        }
 
        mTvCancel!!.setOnClickListener {
            if (mClickCallBack != null)
                mClickCallBack!!.cancel()
            setAlpha(1.0f)
        }
 
        this.setOnDismissListener { setAlpha(1.0f) }
 
        if (mProvincePicker != null) {
            //监听事件
            mProvincePicker!!.setOnValueChangedListener { p0, _, _ ->
                //改变市,区的值
                mCurSelProvince = provinceStrArray?.get(p0.value) ?: ""
                mCityArray = mCityMap[mCurSelProvince]!!.toTypedArray()
                mCityPicker!!.displayedValues = null
                mCityPicker!!.maxValue = mCityArray!!.size - 1//设置最大值
                mCityPicker!!.displayedValues = mCityArray
 
                mCurSelCity = mCityArray!![0]
                mDistrictArray = mDistrictMap[mCurSelCity]!!.toTypedArray()
                mDistrictPicker!!.displayedValues = null
                mDistrictPicker!!.maxValue = mDistrictArray!!.size - 1 //设置最大值
                mDistrictPicker!!.displayedValues = mDistrictArray
            }
        }
 
        if (mCityPicker != null) {
            mCityPicker!!.setOnValueChangedListener { p0, _, _ ->
                //获取当前位置,设置地区
                mCurSelCity = mCityArray?.get(p0.value) ?: ""
                mDistrictArray = mDistrictMap[mCurSelCity]!!.toTypedArray()
                mDistrictPicker!!.displayedValues = null
                mDistrictPicker!!.maxValue = mDistrictArray!!.size - 1 //设置最大值
                mDistrictPicker!!.displayedValues = mDistrictArray
            }
        }
 
        if (mDistrictPicker != null) {
            mDistrictPicker!!.setOnValueChangedListener { p0, _, _ ->
                mCurSelDistrict = mDistrictArray?.get(p0.value) ?: ""
            }
        }
    }
 
    /**
     * 获取选择地址后的结果
     */
    private fun getAddressResult(): JSONObject {
        val jsonObject = JSONObject()
        if (!TextUtils.isEmpty(mCurSelProvince) || !TextUtils.isEmpty(mCurSelCity)
                || !TextUtils.isEmpty(mCurSelDistrict)) {
            jsonObject.put("province", mCurSelProvince)
            jsonObject.put("city", mCurSelCity)
            jsonObject.put("district", mCurSelDistrict)
        }
        return jsonObject
    }
 
    /**
     * 设置选中后的返回数据,以json数据的形式返回
     */
    private fun getResult(): JSONObject {
        //数据回调
        val yearPos = mYearPicker!!.value
        val monthPos = mMonthPicker!!.value
        val dayPos = mDayPicker!!.value
        val hourPos = mHourPicker!!.value
        val minutePos = mMinutePicker!!.value
        val secondPos = mSecondPicker!!.value
        val jsonObject = JSONObject()
        when (mType) {
            1 -> {
                jsonObject.put("year", mYearNumList[yearPos])
                jsonObject.put("month", mMonthNumList[monthPos])
                jsonObject.put("day", mDayNumList[dayPos])
                jsonObject.put("hour", mHourNumList[hourPos])
                jsonObject.put("minute", mMinuteNumList[minutePos])
                jsonObject.put("second", mSecondNumList[secondPos])
            }
            2 -> {
                jsonObject.put("year", mYearNumList[yearPos])
                jsonObject.put("month", mMonthNumList[monthPos])
                jsonObject.put("day", mDayNumList[dayPos])
                jsonObject.put("hour", mHourNumList[hourPos])
                jsonObject.put("minute", mMinuteNumList[minutePos])
            }
            3 -> {
                jsonObject.put("year", mYearNumList[yearPos])
                jsonObject.put("month", mMonthNumList[monthPos])
                jsonObject.put("day", mDayNumList[dayPos])
                jsonObject.put("hour", mHourNumList[hourPos])
            }
            4 -> {
                jsonObject.put("year", mYearNumList[yearPos])
                jsonObject.put("month", mMonthNumList[monthPos])
                jsonObject.put("day", mDayNumList[dayPos])
            }
            5 -> {
                jsonObject.put("hour", mHourNumList[hourPos])
                jsonObject.put("minute", mMinuteNumList[minutePos])
                jsonObject.put("second", mSecondNumList[secondPos])
            }
            6 -> {
                jsonObject.put("hour", mHourNumList[hourPos])
                jsonObject.put("minute", mMinuteNumList[minutePos])
            }
        }
        return jsonObject
    }
 
    /**
     * 显示时间选择器
     */
    fun show(view: View) {
        this.isOutsideTouchable = true
        this.showAtLocation(view, Gravity.BOTTOM, 0, 0)
        setAlpha(0.3f)
    }
 
    /**
     * 改变背景色
     */
    private fun setAlpha(value: Float) {
        val layoutParams = (mContext as Activity).window.attributes
        layoutParams.alpha = value
        (mContext as Activity).window.attributes = layoutParams
    }
 
    /**
     * 获取地址信心
     */
    private fun getAddressData(context: Context, mStrAddressPath: String) {
        val result: MutableList<AddressInfo>? = readXmlBySAX(context, mStrAddressPath)
        //数据转换
        if (result != null) {
            for (rs in result) {
                mProvinceList.add(rs.province)
                mCityMap.putAll(rs.cityMap)
                mDistrictMap.putAll(rs.districtMap)
            }
        }
 
        //转换完成__设置数据
        //省份
        provinceStrArray = mProvinceList.toTypedArray()
        mProvincePicker!!.displayedValues = provinceStrArray
        mProvincePicker!!.maxValue = provinceStrArray!!.size - 1
        mProvincePicker!!.wrapSelectorWheel = true
        mProvincePicker!!.descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS //禁止输入
        mCurSelProvince = provinceStrArray!![0]
        //城市
        mCityArray = mCityMap[mCurSelProvince]!!.toTypedArray()
        mCityPicker!!.displayedValues = mCityArray
        mCityPicker!!.maxValue = mCityArray!!.size - 1
        mCityPicker!!.wrapSelectorWheel = true
        mCityPicker!!.descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS
        mCurSelCity = mCityArray!![0]
        //市区
        mDistrictArray = mDistrictMap[mCurSelCity]!!.toTypedArray()
        mDistrictPicker!!.displayedValues = mDistrictArray
        mDistrictPicker!!.maxValue = mDistrictArray!!.size - 1
        mDistrictPicker!!.wrapSelectorWheel = true
        mDistrictPicker!!.descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS
        mCurSelDistrict = mDistrictArray!![0]
    }
 
    /**
     * 解析读取xml文件信息
     */
    private fun readXmlBySAX(context: Context, mStrAddressPath: String): MutableList<AddressInfo>? {
        try {
            val input = context.resources.assets.open(mStrAddressPath)
            //创建解析器
            val spf = SAXParserFactory.newInstance()
            val saxParser = spf.newSAXParser()
            val handler = AddressSaxHandler()
            saxParser.parse(input, handler)
            input.close()
            return handler.result
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }
 
    /**
     * 初始化数据
     */
    private fun initData(type: Int) {
        //根据type现实ui__1年月日时分秒,2年月日时分 3年月日时,4年月日,5时分秒,6时分
        when (type) {
            2 -> mSecondPicker!!.visibility = View.GONE
            3 -> {
                mSecondPicker!!.visibility = View.GONE
                mMinutePicker!!.visibility = View.GONE
            }
            4 -> {
                mSecondPicker!!.visibility = View.GONE
                mMinutePicker!!.visibility = View.GONE
                mHourPicker!!.visibility = View.GONE
            }
            5 -> {
                mYearPicker!!.visibility = View.GONE
                mMonthPicker!!.visibility = View.GONE
                mDayPicker!!.visibility = View.GONE
            }
            6 -> {
                mYearPicker!!.visibility = View.GONE
                mMonthPicker!!.visibility = View.GONE
                mDayPicker!!.visibility = View.GONE
                mHourPicker!!.visibility = View.GONE
            }
        }
 
        //数据集合初始化
        //年
        val startCal = Calendar.getInstance()
        val curCal = Calendar.getInstance()
        startCal.timeInMillis = 0
        val startYear = startCal[Calendar.YEAR]
        val endYear = curCal[Calendar.YEAR]
 
        for (item in endYear downTo startYear) {
            mYearList.add(item.toString() + "年")
            mYearNumList.add(item)
        }
        //月
        for (item in 1..12) {
            mMonthList.add(String.format("%02d", item) + "月")
            mMonthNumList.add(item)
        }
        //日
        val curDay = curCal.getActualMaximum(Calendar.DAY_OF_MONTH)//当前月份有多少天
        for (item in 1..curDay) {
            mDayList.add(String.format("%02d", item) + "日")
            mDayNumList.add(item)
        }
        //时
        for (item in 1..24) {
            mHourList.add(String.format("%02d", item) + "时")
            mHourNumList.add(item)
        }
        //分
        for (item in 1..60) {
            mMinuteList.add(String.format("%02d", item) + "分")
            mMinuteNumList.add(item)
        }
        //秒
        for (item in 1..60) {
            mSecondList.add(String.format("%02d", item) + "秒")
            mSecondNumList.add(item)
        }
 
        //设置数据---------------------------------------------
        //获取当前初始化数据__月日时分秒
        val cMonth = curCal[Calendar.MONTH]//从0开始
        val cDay = curCal[Calendar.DATE] - 1//ri
        val cHour = curCal[Calendar.HOUR_OF_DAY] - 1//时
        val cMinute = curCal[Calendar.MINUTE] - 1//分
        val cSecond = curCal[Calendar.SECOND] - 1//秒
 
        mYearPicker!!.displayedValues = mYearList.toTypedArray()
        mYearPicker!!.maxValue = mYearList.size - 1//设置最大值
        mYearPicker!!.wrapSelectorWheel = true
        mYearPicker!!.descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS //禁止输入
 
        mMonthPicker!!.displayedValues = mMonthList.toTypedArray()
        mMonthPicker!!.maxValue = mMonthList.size - 1 //设置最大值
        mMonthPicker!!.wrapSelectorWheel = true
        mMonthPicker!!.value = cMonth
        mMonthPicker!!.descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS //禁止输入
 
        mDayPicker!!.displayedValues = mDayList.toTypedArray()
        mDayPicker!!.maxValue = mDayList.size - 1
        mDayPicker!!.wrapSelectorWheel = true
        mDayPicker!!.value = cDay
        mDayPicker!!.descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS //禁止输入
 
        mHourPicker!!.displayedValues = mHourList.toTypedArray()
        mHourPicker!!.maxValue = mHourList.size - 1
        mHourPicker!!.wrapSelectorWheel = true
        mHourPicker!!.value = cHour
        mHourPicker!!.descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS //禁止输入
 
        mMinutePicker!!.displayedValues = mMinuteList.toTypedArray()
        mMinutePicker!!.maxValue = mMinuteList.size - 1
        mMinutePicker!!.wrapSelectorWheel = true
        mMinutePicker!!.value = cMinute
        mMinutePicker!!.descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS //禁止输入
 
        mSecondPicker!!.displayedValues = mSecondList.toTypedArray()
        mSecondPicker!!.maxValue = mSecondList.size - 1
        mSecondPicker!!.wrapSelectorWheel = true
        mSecondPicker!!.value = cSecond
        mSecondPicker!!.descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS //禁止输入
    }
 
    /**
     * 设置右边文本的内容
     */
    fun setRightTextContent(any: Any) {
        if (mTvConfirm == null)
            return
        when (any) {
            is String -> mTvConfirm!!.text = any.toString()
            is Int -> mTvConfirm!!.setText(any)
            else -> mTvConfirm!!.text = mStrLeft
        }
    }
 
    /**
     * 设置左边文本的内容
     */
    fun setLeftTextContent(any: Any) {
        if (mTvCancel == null)
            return
        when (any) {
            is String -> mTvCancel!!.text = any.toString()
            is Int -> mTvCancel!!.setText(any)
            else -> mTvCancel!!.text = mStrLeft
        }
    }
 
    /**
     * 自定义NumberPicker ---------------------------------------------------------------
     */
    class DivNumberPicker : NumberPicker {
        constructor(context: Context?) : super(context)
        constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
        constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
 
        override fun addView(child: View?) {
            super.addView(child)
            updateView(child)
        }
 
        override fun addView(child: View?, index: Int, params: ViewGroup.LayoutParams?) {
            super.addView(child, index, params)
            updateView(child)
        }
 
        override fun addView(child: View?, params: ViewGroup.LayoutParams?) {
            super.addView(child, params)
            updateView(child)
        }
 
        private fun updateView(child: View?) {
            if (child is EditText) {
                //这里修改显示字体的属性,主要修改颜色
                child.textSize = 12f
                child.setTextColor(Color.BLACK)
            }
        }
 
        override fun setDisplayedValues(displayedValues: Array<out String>?) {
            super.setDisplayedValues(displayedValues)
            setNumberPickerDividerColor(this@DivNumberPicker)
        }
 
        private fun setNumberPickerDividerColor(divNumberPicker: DivNumberPicker) {
            val pickerFields = this@DivNumberPicker.javaClass.declaredFields
            for (pf in pickerFields) {
                if (pf.name == "mSelectionDivider") {
                    pf.isAccessible = true
                    try {
                        //设置分割线的颜色值 透明
                        pf.set(divNumberPicker, ColorDrawable(Color.BLACK))
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }
            }
        }
 
    }
 
    /**
     * author: tao
     * date:2020/6/27
     * desc:地址model:xml解释 --------------------------------------------------------------
     */
    class AddressSaxHandler : DefaultHandler() {
        //解释结果集合
        var result: MutableList<AddressInfo>? = null
        private var mCurrenInfo: AddressInfo? = null
 
        private var mCurrentProvince = ""
        private var mCurrentCity = ""
 
        private var mTagName = ""
 
        override fun startDocument() {
            super.startDocument()
            result = ArrayList()
        }
 
        override fun startElement(uri: String?, localName: String?, qName: String?, attributes: Attributes?) {
            super.startElement(uri, localName, qName, attributes)
            if (localName == "province") {
                mCurrenInfo = AddressInfo()
                mCurrenInfo!!.province = attributes!!.getValue("name")
                mCurrentProvince = mCurrenInfo!!.province
            } else if (localName == "city") {
                mCurrentCity = attributes!!.getValue("name")
                var cityList: MutableList<String> = ArrayList()
                if (mCurrenInfo!!.cityMap[mCurrentProvince] == null) {
                    cityList.add(mCurrentCity)
                    mCurrenInfo!!.cityMap[mCurrentProvince] = cityList
                } else {
                    cityList = mCurrenInfo!!.cityMap[mCurrentProvince]!!
                    cityList.add(mCurrentCity)
                    mCurrenInfo!!.cityMap[mCurrentProvince] = cityList
                }
            }
            mTagName = localName!!
        }
 
        override fun characters(ch: CharArray, start: Int, length: Int) {
            super.characters(ch, start, length)
            if (!TextUtils.isEmpty(mTagName)) {
                val data = String(ch, start, length)
                if (mTagName == "district") {
                    var districtList: MutableList<String> = ArrayList()
                    if (mCurrenInfo!!.districtMap[mCurrentCity] == null) {
                        districtList.add(data)
                        mCurrenInfo!!.districtMap[mCurrentCity] = districtList
                    } else {
                        districtList = mCurrenInfo!!.districtMap[mCurrentCity]!!
                        districtList.add(data)
                        mCurrenInfo!!.districtMap[mCurrentCity] = districtList
                    }
                }
            }
        }
 
        override fun endElement(uri: String?, localName: String?, qName: String?) {
            super.endElement(uri, localName, qName)
            if (localName.equals("province")) {
                result!!.add(mCurrenInfo!!)
            }
            this.mTagName = ""
        }
    }
 
    /**
     * 地址实体类
     */
    class AddressInfo {
        var province: String = ""
        var cityMap = HashMap<String, MutableList<String>>()
        var districtMap = HashMap<String, MutableList<String>>()
    }
 
    /**
     * 定义回调接口 ----------------------------------------------------------------------------
     */
    interface ClickCallBack {
        fun cancel()
        fun confirm(jsonObject: JSONObject)
    }
 
    fun setClickCallBack(clickCallBack: ClickCallBack) {
        this.mClickCallBack = clickCallBack
    }
}
相关文章
|
4月前
|
XML Java Android开发
Android Studio App开发中改造已有的控件实战(包括自定义支付宝月份选择器、给翻页栏添加新属性、不滚动的列表视图 附源码)
Android Studio App开发中改造已有的控件实战(包括自定义支付宝月份选择器、给翻页栏添加新属性、不滚动的列表视图 附源码)
42 1
|
Android开发
flutter中实现仿Android端的onResume和onPause方法
flutter中实现仿Android端的onResume和onPause方法
|
28天前
|
Android开发
Android 开发 pickerview 自定义选择器
Android 开发 pickerview 自定义选择器
12 0
|
12月前
|
Java 数据安全/隐私保护 Android开发
Android C++系列:C++最佳实践3继承与访问控制
整个结构还是比较简单的,从类内部到本包到子类到外部包权限越来越小,比较好理解也比较好记忆。但是在C++中访问控制要复杂很多,因为不仅有属性和方法的访问控制,还有继承时的派生列表访问说明符。今天我们着重了解访问控制。
70 0
|
Android开发
Android 封装一个通用的PopupWindow
`PopupWindow`这个类用来实现一个弹出框,可以使用任意布局的`View`作为其内容,这个弹出框是悬浮在当前`Activity`之上的,一般`PopupWindow`的使用
231 0
|
Android开发
Android Studio下载Gradle一直失败,使用正确的下载地址
Android Studio下载Gradle一直失败,使用正确的下载地址
753 0
|
Android开发 容器
Android实现面包屑效果,支持Fragment联动
Android实现面包屑效果,支持Fragment联动
|
Android开发
Android实现连线题效果
Android实现连线题效果
|
Android开发
《手机卫士性能优化方案-Android篇》电子版地址
手机卫士性能优化方案-Android篇
75 0
《手机卫士性能优化方案-Android篇》电子版地址
|
Android开发
Android实现调用系统相机录像及实现录音
Android实现调用系统相机录像及实现录音
584 0