今天自定义了一个选择器,可以选择是时间还是地址,使用起来很方便,继承popupWindow实现的,代码很简单,使用也简单,效果图如下
先看下使用方法
时间选择器的使用
默认是显示年月日时分秒,可以通过构造方法传入的type值来设置要显示的日期格式,如type为2的话,显示的是年月日时分,没有秒,具体看完整代码中的解释,备注很清楚。
地址选择器的使用
关于地址选择器,如果使用xml文件引入地址信息,在这里使用的是SAX方法对xml进行了解析,至于xml地址资源,可自行去网上寻找,很容易找到,这里截个图个大家看一下,主要一点要注意一下,标签名跟格式要一致,即使网上找到的标签名不一样,手动修改一下就好,截图如下:
可以看到时间选择器跟地址选择器在使用上的区别在于调用不同的构造方法,在这个自定义组件中,提供了三个构造方法,备注很清晰
选择器是使用了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
}
}