公司项目里用到了TimePicker和DataPicker,但是因为项目用的版本较低,所以TimePicker和DataPicker显示出来的样式不怎么美观,那种黑白的,实在看不下去,于是自己定义了两个控件,拿出来分享一下
private void onCreat() {
view = LayoutInflater.from(this.getContext()).inflate(R.layout.dialog_picker, this, true);
initView();
}
监听点击事件和输入事件,将接口透出去:
/** * 接口 * imgAdd + * imgMinus — */
public interface OnClickListener {
//加
void add(String inputStr);
//减
void minus(String inputStr);
//输入的内容的监听
void textChange(Editable str);
}
点击事件
//点击事件 加号
imgAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onClickListener != null) {
String inputStr = edInput.getText().toString();
onClickListener.add(inputStr);
}
}
});
//点击事件 减号
imgMinus.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onClickListener != null) {
String inputStr = edInput.getText().toString();
onClickListener.minus(inputStr);
}
}
});
输入事件监听,之前是准备让EditText中的值也可以手动输入,但是这样的话会牵涉到焦点的获取之类的,还有更多的逻辑判断,项目当时有点紧,就没有让EditText设置可输入,有兴趣的小伙伴们可以自己加上去
edInput.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (onClickListener != null) {
onClickListener.textChange(s);
}
}
});
设置输入的长度 xml中设置了最大显示数目
public void setInputLenth(int inputLenth) {
if (inputLenth == 0 || String.valueOf(inputLenth).length() == 0 || "".equals(String.valueOf(inputLenth))) {
edInput.setFilters(new InputFilter[]{new InputFilter.LengthFilter(4)});
} else {
//最大输入长度
edInput.setFilters(new InputFilter[]{new InputFilter.LengthFilter(inputLenth)});
}
}
因为封装的这个控件会分别用到DataPicker和Timeker 中,所以要实用多种情况,控件中间不光是一个EditText,EditText 的右面还有一个TextView,宽度设置自适应,这样就还可以通过代码直接设置显示的情况,从而实现作用于不同的场景
/** * 设置显示的类型 * * @param inputType tvType 显示的值 "年","月","日" */
public void setInputType(String inputType) {
tvType.setText(inputType);
}
设置EditText 中输入的值,一般用来设置默认的显示值
/** * 设置EditText显示的内容 * * @param string EditText要显示的值 */
public void setEdInput(String string) {
edInput.setText(string);
}
获得EditText中输入的值
public String getEdInput() {
return edInput.getText().toString();
}
现在这一部分就基本完成了,接着就要开始封装TimePicker了
因为我们的需求是需要开始时间和结束时间两个时间点,所以我直接把开始时间和结束时间封装在了一起,并且没有区分12时计时法和24时计时法,默认成24时计时法,其实如果想加上的话只需要把定义一个全局变量,把接口透出去,就可以了,这里就不做赘述了
view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_time, null);
hourStart = (MyDatePickerDia) view.findViewById(R.id.date_hour_start);
hourEnd = (MyDatePickerDia) view.findViewById(R.id.date_hour_end);
minuteStart = (MyDatePickerDia) view.findViewById(R.id.date_minute_start);
minuteEnd = (MyDatePickerDia) view.findViewById(R.id.date_minute_end);
tvDate = (TextView) view.findViewById(R.id.tv_date);
tvOk = (TextView) view.findViewById(R.id.ok);
tvOk.setClickable(true);
tvCancle = (TextView) view.findViewById(R.id.cancel);
tvCancle.setClickable(true);
//点击确定的时候把每个之前封装的控件中的值取到,然后用“:”和"-"拼接之后传出去
tvOk.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onClickListener != null) {
int hs = Integer.parseInt(hourStart.getEdInput());
int he = Integer.parseInt(hourEnd.getEdInput());
int ms = Integer.parseInt(minuteStart.getEdInput());
int me = Integer.parseInt(minuteEnd.getEdInput());
String time = String.format(format, hs) + ":" + String.format(format, ms)
+ "-" + String.format(format, he) + ":" + String.format(format, me);
onClickListener.clickOk(time);
}
dismiss();
}
});
//点击取消的时候,将时间设置成默认,这里是将开始时间默认设置为8:00,结束时间默认设置成18:00
tvCancle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onClickListener != null) {
String time = "08:00-18:00";
onClickListener.clickCancle(time);
}
dismiss();
}
});
透出的接口
/** * 接口 */
public interface OnClickListener {
void clickOk(String ok);
void clickCancle(String cancle);
}
设置确定按钮和取消按钮显示的字符串
/** * 设置取消按钮的显示内容 * * @param cancle 显示的内容 */
public void setTextCancle(String cancle) {
tvCancle.setText(cancle);
}
/** * 设置确定按钮的显示内容 * * @param ok */
public void steTextOk(String ok) {
tvOk.setText(ok);
}
设置Dialog的样式,
/** * dialog 的宽高的设置 */
private void resize() {
Window dialogWindow = this.getWindow();
int width = WindowUtils.getScreenWidth(dialogWindow);
WindowManager.LayoutParams p = dialogWindow.getAttributes(); // 获取对话框当前的参数值
p.width = (int) (width * 0.85); // 宽度设置为屏幕的0.85
dialogWindow.setAttributes(p);
}
设置Dialog的标题
/** * 设置标题 */
public void setTittle(String string) {
tvDate.setText(string);
}
准备工作算是基本完成了,现在该开始写逻辑了
上班的时间中的小时的操作
/** * 上班时间 -小时 */
private void hourStartSetting() {
//设置最多显示两位
hourStart.setInputLenth(2);
//不足两位十位补零 默认设置为 08
hourStart.setEdInput(String.format(format, 8));
hourStart.setOnClickListener(new MyDatePickerDia.OnClickListener() {
@Override
public void add(String inputStr) {
hourAdd(true);
}
@Override
public void minus(String inputStr) {
hourMinus(true);
}
@Override
public void textChange(Editable str) {
}
});
}
上班分钟的操作
/** * 上班时间 -分钟 */
private void minuteStartSetting() {
minuteStart.setInputLenth(2);
minuteStart.setEdInput(String.format(format, 0));
minuteStart.setOnClickListener(new MyDatePickerDia.OnClickListener() {
@Override
public void add(String inputStr) {
minuteAdd(true);
}
@Override
public void minus(String inputStr) {
minuteMinus(true);
}
@Override
public void textChange(Editable str) {
}
});
}
下班小时操作
/** * 下班时间 -小时 */
private void hourEndSetting() {
//设置最多显示两位
hourStart.setInputLenth(2);
//不足两位十位补零 默设置为 18
hourEnd.setEdInput(String.format(format, 18));
hourEnd.setOnClickListener(new MyDatePickerDia.OnClickListener() {
@Override
public void add(String inputStr) {
hourAdd(false);
}
@Override
public void minus(String inputStr) {
hourMinus(false);
}
@Override
public void textChange(Editable str) {
}
});
}
下班分钟的操作
/** * 下班时间 -分钟 */
private void minuEndSetting() {
minuteEnd.setInputLenth(2);
minuteEnd.setEdInput(String.format(format, 0));
minuteEnd.setOnClickListener(new MyDatePickerDia.OnClickListener() {
@Override
public void add(String inputStr) {
minuteAdd(false);
}
@Override
public void minus(String inputStr) {
minuteMinus(false);
}
@Override
public void textChange(Editable str) {
}
});
}
小时+
/** * 小时 + * * @param type 类型 true 开始 false 结束 */
private void hourAdd(boolean type) {
int hour = 0;
if (type) {
hour = Integer.parseInt(hourStart.getEdInput());
} else {
hour = Integer.parseInt(hourEnd.getEdInput());
}
if (hour == 23) {
hour = 0;
} else {
hour++;
}
String Hour = String.format(format, hour);
if (type) {
hourStart.setEdInput(Hour);
} else {
hourEnd.setEdInput(Hour);
}
}
小时-
/** * 小时 - * * @param type 类型 true 开始 false 结束 */
private void hourMinus(boolean type) {
int hour = 0;
if (type) {
hour = Integer.parseInt(hourStart.getEdInput());
} else {
hour = Integer.parseInt(hourEnd.getEdInput());
}
if (hour == 0) {
hour = 23;
} else {
hour--;
}
String Hour = String.format(format, hour);
if (type) {
hourStart.setEdInput(Hour);
return;
}
hourEnd.setEdInput(Hour);
}
分钟+
/** * 分钟 + * * @param type 类型 true 开始 false 结束 */
private void minuteAdd(boolean type) {
int minute = 0;
if (type) {
minute = Integer.parseInt(minuteStart.getEdInput());
} else {
minute = Integer.parseInt(minuteEnd.getEdInput());
}
if (minute == 59) {
minute = 0;
if (type) {
hourAdd(true);
} else {
hourAdd(false);
}
} else {
minute++;
}
if (type) {
minuteStart.setEdInput(String.format(format, minute));
return;
}
minuteEnd.setEdInput(String.format(format, minute));
}
分钟-
/** * 分钟减 * * @param type 类型 true 开始 false 结束 */
private void minuteMinus(boolean type) {
int minute = 0;
if (type) {
minute = Integer.parseInt(minuteStart.getEdInput());
} else {
minute = Integer.parseInt(minuteEnd.getEdInput());
}
if (minute == 0) {
minute = 59;
if (type) {
hourMinus(true);
} else {
hourMinus(false);
}
} else {
minute--;
}
if (type) {
minuteStart.setEdInput(String.format(format, minute));
return;
}
minuteEnd.setEdInput(String.format(format, minute));
}
到这里基本的逻辑也就完成的差不多了,TimePickerDialog也就基本完成了
接下来我们接着封装DataPickerDialog
DataPicker相比TimePicker稍微麻烦一点,原因就是DataPicker中牵扯到了闰年平年,以及12个月份每个月的天数不同
同样,首先,我们先 创建Diallog
view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_date, null);
year = (MyDatePickerDia) view.findViewById(R.id.date_year);
month = (MyDatePickerDia) view.findViewById(R.id.date_month);
day = (MyDatePickerDia) view.findViewById(R.id.date_day);
tvDate = (TextView) view.findViewById(R.id.tv_date);
tvOk = (TextView) view.findViewById(R.id.ok);
tvOk.setClickable(true);
tvCancle = (TextView) view.findViewById(R.id.cancel);
tvCancle.setClickable(true);
tvOk.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onClickListener != null) {
onClickListener.clickOk(tittleShow());
}
dismiss();
}
});
tvCancle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onClickListener != null) {
String now = String.valueOf(calendar.get(Calendar.YEAR)) + "年-"
+ String.format(format, calendar.get(Calendar.MONTH) + 1) + "月-"
+ String.format(format, calendar.get(Calendar.DAY_OF_MONTH)) + "日";
onClickListener.clickCancle(now);
}
dismiss();
}
});
与TimePickerDialog差不多,不做赘述
这里主要写逻辑代码
年的设置
/** * 年的设置 */
private void yearSetting() {
year.setInputType("年");
year.setInputLenth(4);
year.setEdInput(String.valueOf(calendar.get(Calendar.YEAR)));
year.setOnClickListener(new MyDatePickerDia.OnClickListener() {
@Override
public void add(String inputStr) {
yearAdd(inputStr);
tittleShow();
}
@Override
public void minus(String inputStr) {
yearMinus(inputStr);
tittleShow();
}
@Override
public void textChange(Editable str) {
tvDate.setText(str);
}
});
}
月的设置
/** * 月的设置 */
private void monthSetting() {
month.setInputType("月");
month.setInputLenth(2);
month.setEdInput(String.format(format, calendar.get(Calendar.MONTH) + 1));
month.setOnClickListener(new MyDatePickerDia.OnClickListener() {
@Override
public void add(String inputStr) {
monthAdd(inputStr);
tittleShow();
}
@Override
public void minus(String inputStr) {
monthMinus(inputStr);
tittleShow();
}
@Override
public void textChange(Editable str) {
}
});
}
天的设置
/** * 天的设置 */
private void daySetting() {
day.setInputType("日");
day.setInputLenth(2);
day.setEdInput(String.format(format, calendar.get(Calendar.DAY_OF_MONTH)));
day.setOnClickListener(new MyDatePickerDia.OnClickListener() {
@Override
public void add(String inputStr) {
dayAdd(inputStr);
tittleShow();
}
@Override
public void minus(String inputStr) {
dayMinus(inputStr);
tittleShow();
}
@Override
public void textChange(Editable str) {
}
});
}
年+
/** * 年 + * * @param add */
private void yearAdd(String add) {
int input = 0;
if (add.length() == 0 || "".equals(add) || Integer.parseInt(add) < 1900) {
add = "1900";
year.setEdInput(add);
} else {
input = Integer.parseInt(add);
input++;
if (input > 2100) {
input = 2100;
}
yearChange(input);
year.setEdInput(String.valueOf(input));
}
}
年-
/** * 年 - * * @param minus */
private void yearMinus(String minus) {
int input = 0;
if (minus.length() == 0 || "".equals(minus) || Integer.parseInt(minus) < 1900) {
minus = "1900";
year.setEdInput(minus);
} else {
input = Integer.parseInt(minus);
if (input > 2101) {
input = 2101;
}
input--;
if (input < 1900) {
input = 1900;
}
yearChange(input);
year.setEdInput(String.valueOf(input));
}
}
月 +
/** * 月 + * * @param add */
private void monthAdd(String add) {
int input = 0;
if ((add.length() == 0) || "".equals(add) || (Integer.parseInt(add) > 12) || (Integer.parseInt(add) < 1)) {
add = String.format(format, calendar.get(Calendar.MONTH));
month.setEdInput(add);
} else {
input = Integer.parseInt(add);
if (input == 12) {
input = 1;
//月份变化对年的影响 +1
yearAdd(year.getEdInput());
} else {
input++;
//月份变化对日的影响
monthChange(input);
}
month.setEdInput(String.format(format, input));
}
}
月-
/** * 月 - * * @param minus */
private void monthMinus(String minus) {
int input = 0;
if ((minus.length() == 0) || "".equals(minus) || (Integer.parseInt(minus) > 12) || (Integer.parseInt(minus) < 1)) {
minus = String.format(format, calendar.get(Calendar.MONTH));
month.setEdInput(minus);
return;
}
input = Integer.parseInt(minus);
if (input == 1) {
input = 12;
//月份变化对年的影响 -1
yearMinus(year.getEdInput());
} else {
input--;
//月份变化对日的影响
monthChange(input);
}
month.setEdInput(String.format(format, input));
}
日+
/**
* 日 +
*
* @param add
*/
private void dayAdd(String add) {
int y = Integer.parseInt(year.getEdInput());
int m = Integer.parseInt(month.getEdInput());
int d = Integer.parseInt(add);
if ("".equals(add) || add.length() == 0 || d > 31 || d < 1) {
month.setEdInput(String.format(format, calendar.get(Calendar.MONTH) + 1));
day.setEdInput(String.format(format, calendar.get(Calendar.DAY_OF_MONTH)));
} else if (d == 31) {
monthAdd(String.format(format, m));
day.setEdInput(String.format(format, 1));
} else if (d == 30) {
if (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12) {
d++;
day.setEdInput(String.format(format, d));
} else {
monthAdd(String.format(format, m));
day.setEdInput(String.format(format, 1));
}
} else if (d == 29) {
if (m == 2) {
monthAdd(String.format(format, m));
day.setEdInput(String.format(format, 1));
} else {
d++;
day.setEdInput(String.format(format, d));
}
} else if (d == 28) {
if (m == 2) {
if (isLeapYear(y)) {
d++;
day.setEdInput(String.format(format, d));
} else {
monthAdd(String.format(format, m));
day.setEdInput(String.format(format, 1));
}
} else {
d++;
day.setEdInput(String.format(format, d));
}
} else {
d++;
day.setEdInput(String.format(format, d));
}
}
日-
/**
* 日 —
*
* @param minus
*/
private void dayMinus(String minus) {
int y = Integer.parseInt(year.getEdInput());
int m = Integer.parseInt(month.getEdInput());
int d = Integer.parseInt(minus);
if ("".equals(minus) || minus.length() == 0 || d > 31 || d < 1) {
day.setEdInput(String.format(format, calendar.get(Calendar.DAY_OF_MONTH)));
} else if (d == 1) {
//4,6,9,11四个月是30天,上一个月一号减1,变成30号
if (m == 5 || m == 7 || m == 10 || m == 12) {
day.setEdInput(String.format(format, 30));
} else if (m == 3) {
if (isLeapYear(y)) {
day.setEdInput(String.format(format, 29));
} else {
day.setEdInput(String.format(format, 28));
}
} else {
day.setEdInput(String.format(format, 31));
}
monthMinus(String.format(format, m));
} else if (d == 31) {
if (m == 2) {
if (isLeapYear(y)) {
day.setEdInput(String.format(format, 29));
} else {
day.setEdInput(String.format(format, 28));
}
} else if (m == 4 || m == 6 || m == 9 || m == 11) {
day.setEdInput(String.format(format, 30));
} else {
d--;
day.setEdInput(String.format(format, d));
}
} else if (d == 30) {
if (m == 2 && !isLeapYear(y)) {
day.setEdInput(String.format(format, 28));
} else {
d--;
day.setEdInput(String.format(format, d));
}
} else {
d--;
day.setEdInput(String.format(format, d));
}
}
不同的月份对天的影响不同
/** * 月份改变对日的影响 * * @param month 月份 */
private void monthChange(int month) {
//2月情况特殊,需分平年闰年,特殊处理
if (month == 2) {
if (isLeapYear(Integer.parseInt(year.getEdInput()))) {
if (Integer.parseInt(day.getEdInput()) > 29) {
day.setEdInput("29");
}
} else {
if (Integer.parseInt(day.getEdInput()) > 28) {
day.setEdInput("28");
}
}
//4,6,9,11一个月最多三十天
} else if (month == 4 || month == 6 || month == 9 || month == 11) {
if (Integer.parseInt(day.getEdInput()) > 30) {
day.setEdInput("30");
}
}
}
不同的年份对天的影响也不一样
/** * 年份改变对日的影响 * * @param year 年份 */
private void yearChange(int year) {
int m = Integer.parseInt(month.getEdInput());
int d = Integer.parseInt(day.getEdInput());
if (m == 2) {
if (isLeapYear(year)) {
if (d > 29) {
day.setEdInput("29");
}
} else {
if (d > 28) {
day.setEdInput("28");
}
}
} else if (m == 4 || m == 6 || m == 9 || m == 11) {
if (d > 30) {
day.setEdInput("30");
}
}
}
基姆拉尔森计算公式 ,根据日期计算星期几
/** * 基姆拉尔森计算公式 Week=(Day + 2*Month + 3*(Month+1)/5 + Year + Year/4 - Year/100 + Year/400) % 7 * * @param y 年 * @param m 月 1,2月需要按13月,14日 * @param d 日 * @return */
private String getWeek(int y, int m, int d) {
String Week = "星期";
if (m == 1) {
m = 13;
}
if (m == 2) {
m = 14;
}
int week = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
switch (week) {
case 0:
Week += "一";
break;
case 1:
Week += "二";
break;
case 2:
Week += "三";
break;
case 3:
Week += "四";
break;
case 4:
Week += "五";
break;
case 5:
Week += "六";
break;
case 6:
Week += "日";
break;
default:
break;
}
return Week;
}
这样基本上DataPickerDialog就完成了,然后就可以使用了