今天自定义了一个时间选择器,继承popupWindow实现的,代码很简单,使用也简单,效果图如下
先看下使用方法
在activity的使用如上图,show()方法用于从底部弹出时间选择器,ClickCallBack为回调方法,用于接收左右两边的两个按钮的点击事件,confirm回调方法中返回的还是一个json对象,方便使用。
默认是显示年月日时分秒,可以通过构造方法传入的type值来设置要显示的日期格式,如type为2的话,显示的是年月日时分,没有秒,具体看完整代码中的解释,备注很清楚。
还有选择器是使用了NumberPicker来实现的,也还是比较简单。
另外代码中还提供了两个方法用于修改左右两个两个TextView的文本内容,完整代码如下:
package com.example.testproject.widget;
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.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 java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
public class TimeSelector extends PopupWindow {
private DivNumberPicker mYearPicker;
private DivNumberPicker mMonthPicker;
private DivNumberPicker mDayPicker;
private DivNumberPicker mHourPicker;
private DivNumberPicker mMinutePicker;
private DivNumberPicker mSecondPicker;
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 Context mContext;
private ClickCallBack mClickCallBack;
private String mStrLeft = "取消";
private String mStrRight = "确认";
private int mType = 1;//1.年月日时分秒,2.年月日时分 3.年月日时,4.年月日,5.时分秒,6.时分
public TimeSelector(Context context) {
super(context);
mContext = context;
initView(context);
}
public TimeSelector(Context context, int mType) {
super(context);
mContext = context;
this.mType = mType;
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);
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);
llContent.addView(rlTitle);
llContent.addView(llDataSel);
this.setContentView(llContent);
initData(mType);
initListener();
}
/**
* 添加监听方法
*/
private void initListener() {
mTvConfirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mClickCallBack != null)
mClickCallBack.confirm(getResult());
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);
}
});
}
/**
* 显示时间选择器
*
* @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);
}
/**
* 设置选中后的返回数据,以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); //禁止输入
}
/**
* 自定义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;
}
}
}
}
/**
* 定义回调接口 ----------------------------------------------------------------------
*/
public interface ClickCallBack {
void cancel();
void confirm(JSONObject jsonObject);
}
public void setmClickCallBack(ClickCallBack mClickCallBack) {
this.mClickCallBack = mClickCallBack;
}
}