|
|
|
|
@ -28,85 +28,123 @@ import android.view.View;
|
|
|
|
|
import android.widget.FrameLayout;
|
|
|
|
|
import android.widget.NumberPicker;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 自定义日期时间选择器控件
|
|
|
|
|
* 组合使用多个NumberPicker实现日期和时间选择功能
|
|
|
|
|
*/
|
|
|
|
|
public class DateTimePicker extends FrameLayout {
|
|
|
|
|
|
|
|
|
|
// 默认启用状态
|
|
|
|
|
private static final boolean DEFAULT_ENABLE_STATE = true;
|
|
|
|
|
|
|
|
|
|
private static final int HOURS_IN_HALF_DAY = 12;
|
|
|
|
|
private static final int HOURS_IN_ALL_DAY = 24;
|
|
|
|
|
private static final int DAYS_IN_ALL_WEEK = 7;
|
|
|
|
|
private static final int DATE_SPINNER_MIN_VAL = 0;
|
|
|
|
|
private static final int DATE_SPINNER_MAX_VAL = DAYS_IN_ALL_WEEK - 1;
|
|
|
|
|
private static final int HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW = 0;
|
|
|
|
|
private static final int HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW = 23;
|
|
|
|
|
private static final int HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW = 1;
|
|
|
|
|
private static final int HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW = 12;
|
|
|
|
|
private static final int MINUT_SPINNER_MIN_VAL = 0;
|
|
|
|
|
private static final int MINUT_SPINNER_MAX_VAL = 59;
|
|
|
|
|
private static final int AMPM_SPINNER_MIN_VAL = 0;
|
|
|
|
|
private static final int AMPM_SPINNER_MAX_VAL = 1;
|
|
|
|
|
|
|
|
|
|
private final NumberPicker mDateSpinner;
|
|
|
|
|
private final NumberPicker mHourSpinner;
|
|
|
|
|
private final NumberPicker mMinuteSpinner;
|
|
|
|
|
private final NumberPicker mAmPmSpinner;
|
|
|
|
|
private Calendar mDate;
|
|
|
|
|
|
|
|
|
|
// 时间相关常量
|
|
|
|
|
private static final int HOURS_IN_HALF_DAY = 12; // 半天的小时数
|
|
|
|
|
private static final int HOURS_IN_ALL_DAY = 24; // 全天的小时数
|
|
|
|
|
private static final int DAYS_IN_ALL_WEEK = 7; // 一周的天数
|
|
|
|
|
|
|
|
|
|
// NumberPicker范围常量
|
|
|
|
|
private static final int DATE_SPINNER_MIN_VAL = 0; // 日期选择器最小值
|
|
|
|
|
private static final int DATE_SPINNER_MAX_VAL = DAYS_IN_ALL_WEEK - 1; // 日期选择器最大值
|
|
|
|
|
private static final int HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW = 0; // 24小时制小时最小值
|
|
|
|
|
private static final int HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW = 23; // 24小时制小时最大值
|
|
|
|
|
private static final int HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW = 1; // 12小时制小时最小值
|
|
|
|
|
private static final int HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW = 12; // 12小时制小时最大值
|
|
|
|
|
private static final int MINUT_SPINNER_MIN_VAL = 0; // 分钟最小值
|
|
|
|
|
private static final int MINUT_SPINNER_MAX_VAL = 59; // 分钟最大值
|
|
|
|
|
private static final int AMPM_SPINNER_MIN_VAL = 0; // AM/PM选择器最小值
|
|
|
|
|
private static final int AMPM_SPINNER_MAX_VAL = 1; // AM/PM选择器最大值
|
|
|
|
|
|
|
|
|
|
// UI组件
|
|
|
|
|
private final NumberPicker mDateSpinner; // 日期选择器(显示为相对日期,如今天/明天)
|
|
|
|
|
private final NumberPicker mHourSpinner; // 小时选择器
|
|
|
|
|
private final NumberPicker mMinuteSpinner; // 分钟选择器
|
|
|
|
|
private final NumberPicker mAmPmSpinner; // AM/PM选择器(12小时制时使用)
|
|
|
|
|
|
|
|
|
|
private Calendar mDate; // 当前选择的日期时间对象
|
|
|
|
|
|
|
|
|
|
// 日期显示值(如"今天"、"明天"、"周日"等)
|
|
|
|
|
private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK];
|
|
|
|
|
|
|
|
|
|
private boolean mIsAm;
|
|
|
|
|
|
|
|
|
|
private boolean mIs24HourView;
|
|
|
|
|
|
|
|
|
|
private boolean mIsEnabled = DEFAULT_ENABLE_STATE;
|
|
|
|
|
|
|
|
|
|
private boolean mInitialising;
|
|
|
|
|
// 时间状态
|
|
|
|
|
private boolean mIsAm; // 是否为上午
|
|
|
|
|
private boolean mIs24HourView; // 是否使用24小时制
|
|
|
|
|
private boolean mIsEnabled = DEFAULT_ENABLE_STATE; // 控件启用状态
|
|
|
|
|
private boolean mInitialising; // 是否正在初始化
|
|
|
|
|
|
|
|
|
|
// 日期时间变更监听器
|
|
|
|
|
private OnDateTimeChangedListener mOnDateTimeChangedListener;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 日期变更监听器
|
|
|
|
|
* 当用户更改日期时触发
|
|
|
|
|
*/
|
|
|
|
|
private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
|
|
|
|
|
// 计算日期差值并更新日历对象
|
|
|
|
|
mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal);
|
|
|
|
|
// 更新日期控件显示
|
|
|
|
|
updateDateControl();
|
|
|
|
|
// 通知日期时间变更
|
|
|
|
|
onDateTimeChanged();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 小时变更监听器
|
|
|
|
|
* 处理12小时制和24小时制的特殊边界逻辑
|
|
|
|
|
*/
|
|
|
|
|
private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
|
|
|
|
|
boolean isDateChanged = false;
|
|
|
|
|
boolean isDateChanged = false; // 标记日期是否变更
|
|
|
|
|
Calendar cal = Calendar.getInstance();
|
|
|
|
|
|
|
|
|
|
// 12小时制特殊处理
|
|
|
|
|
if (!mIs24HourView) {
|
|
|
|
|
// 处理PM时段从11→12时(实际是23→0时,需要增加一天)
|
|
|
|
|
if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) {
|
|
|
|
|
cal.setTimeInMillis(mDate.getTimeInMillis());
|
|
|
|
|
cal.add(Calendar.DAY_OF_YEAR, 1);
|
|
|
|
|
isDateChanged = true;
|
|
|
|
|
} else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
|
|
|
|
|
}
|
|
|
|
|
// 处理AM时段从12→11时(实际是0→23时,需要减少一天)
|
|
|
|
|
else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
|
|
|
|
|
cal.setTimeInMillis(mDate.getTimeInMillis());
|
|
|
|
|
cal.add(Calendar.DAY_OF_YEAR, -1);
|
|
|
|
|
isDateChanged = true;
|
|
|
|
|
}
|
|
|
|
|
if (oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY ||
|
|
|
|
|
oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
|
|
|
|
|
mIsAm = !mIsAm;
|
|
|
|
|
updateAmPmControl();
|
|
|
|
|
|
|
|
|
|
// 处理AM/PM切换点(12↔11时)
|
|
|
|
|
if ((oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) ||
|
|
|
|
|
(oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1)) {
|
|
|
|
|
mIsAm = !mIsAm; // 切换AM/PM状态
|
|
|
|
|
updateAmPmControl(); // 更新AM/PM控件
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
}
|
|
|
|
|
// 24小时制特殊处理
|
|
|
|
|
else {
|
|
|
|
|
// 处理23→00时(增加一天)
|
|
|
|
|
if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) {
|
|
|
|
|
cal.setTimeInMillis(mDate.getTimeInMillis());
|
|
|
|
|
cal.add(Calendar.DAY_OF_YEAR, 1);
|
|
|
|
|
isDateChanged = true;
|
|
|
|
|
} else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {
|
|
|
|
|
}
|
|
|
|
|
// 处理00→23时(减少一天)
|
|
|
|
|
else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {
|
|
|
|
|
cal.setTimeInMillis(mDate.getTimeInMillis());
|
|
|
|
|
cal.add(Calendar.DAY_OF_YEAR, -1);
|
|
|
|
|
isDateChanged = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新实际小时值(12小时制需要转换为24小时制)
|
|
|
|
|
int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY);
|
|
|
|
|
mDate.set(Calendar.HOUR_OF_DAY, newHour);
|
|
|
|
|
|
|
|
|
|
// 通知变更
|
|
|
|
|
onDateTimeChanged();
|
|
|
|
|
|
|
|
|
|
// 如果日期变更,更新日历控件
|
|
|
|
|
if (isDateChanged) {
|
|
|
|
|
setCurrentYear(cal.get(Calendar.YEAR));
|
|
|
|
|
setCurrentMonth(cal.get(Calendar.MONTH));
|
|
|
|
|
@ -114,6 +152,7 @@ public class DateTimePicker extends FrameLayout {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() {
|
|
|
|
|
@Override
|
|
|
|
|
|