From 480eadedd37bb24e9b7456c06e8ed2e3fdf11dad Mon Sep 17 00:00:00 2001 From: mxvwfs5gq <2694470752@qq.com> Date: Thu, 12 Jun 2025 21:38:32 +0800 Subject: [PATCH] Update DateTimePicker.java --- java/net/micode/notes/ui/DateTimePicker.java | 627 ++++++++++++------- 1 file changed, 413 insertions(+), 214 deletions(-) diff --git a/java/net/micode/notes/ui/DateTimePicker.java b/java/net/micode/notes/ui/DateTimePicker.java index 496b0cd..9b9a325 100644 --- a/java/net/micode/notes/ui/DateTimePicker.java +++ b/java/net/micode/notes/ui/DateTimePicker.java @@ -16,22 +16,46 @@ package net.micode.notes.ui; -import java.text.DateFormatSymbols; -import java.util.Calendar; - -import net.micode.notes.R; - - import android.content.Context; +import android.os.Build; import android.text.format.DateFormat; +import android.util.AttributeSet; +import android.util.Log; import android.view.View; import android.widget.FrameLayout; import android.widget.NumberPicker; +import android.widget.Toast; + +import net.micode.notes.R; +import java.text.DateFormatSymbols; +import java.util.Calendar; +import java.util.Locale; + +/** + * 日期时间选择器控件 - 提供完整的日期和时间选择功能 + * + * 功能增强: + * 1. 支持日期范围限制 (设置最小/最大日期) + * 2. 添加星期名称本地化处理 + * 3. 支持日期格式化定制 + * 4. 增加日期验证和错误提示 + * 5. 改进时间滚动逻辑 + * 6. 支持深色模式 + * 7. 添加无障碍支持 + * + * 修复问题: + * 1. 修复12/24小时转换逻辑错误 + * 2. 解决日期显示越界问题 + * 3. 优化AM/PM切换处理 + * 4. 改进初始状态标记处理 + */ public class DateTimePicker extends FrameLayout { - private static final boolean DEFAULT_ENABLE_STATE = true; + private static final String TAG = "DateTimePicker"; + // 配置常量 + 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; @@ -41,130 +65,114 @@ public class DateTimePicker extends FrameLayout { 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 MINUTE_SPINNER_MIN_VAL = 0; + private static final int MINUTE_SPINNER_MAX_VAL = 59; private static final int AMPM_SPINNER_MIN_VAL = 0; private static final int AMPM_SPINNER_MAX_VAL = 1; - + + // 状态常量 + private static final int MODE_INITIALIZING = 0; + private static final int MODE_NORMAL = 1; + + // 范围限制 (默认无限制) + private long mMinDate = Long.MIN_VALUE; + private long mMaxDate = Long.MAX_VALUE; + + // UI组件 private final NumberPicker mDateSpinner; private final NumberPicker mHourSpinner; private final NumberPicker mMinuteSpinner; private final NumberPicker mAmPmSpinner; + + // 数据模型 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 int mState = MODE_INITIALIZING; - 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); + /** + * 日期变更监听器 + */ + private final NumberPicker.OnValueChangeListener mOnDateChangedListener = + (picker, oldVal, newVal) -> { + // 计算日期变化差值 + int dayDiff = newVal - oldVal; + mDate.add(Calendar.DAY_OF_YEAR, dayDiff); + + // 验证日期范围 + if (!isDateInRange()) { + revertDateChange(); + showDateRangeWarning(); + return; + } + updateDateControl(); onDateTimeChanged(); - } - }; - - private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() { - @Override - public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - boolean isDateChanged = false; - Calendar cal = Calendar.getInstance(); - if (!mIs24HourView) { - 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) { - 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(); - } - } else { - 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) { - cal.setTimeInMillis(mDate.getTimeInMillis()); - cal.add(Calendar.DAY_OF_YEAR, -1); - isDateChanged = true; - } - } - int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY); + }; + + /** + * 小时变更监听器 + */ + private final NumberPicker.OnValueChangeListener mOnHourChangedListener = + (picker, oldVal, newVal) -> { + int newHour = computeNewHour(oldVal, newVal); mDate.set(Calendar.HOUR_OF_DAY, newHour); onDateTimeChanged(); - if (isDateChanged) { - setCurrentYear(cal.get(Calendar.YEAR)); - setCurrentMonth(cal.get(Calendar.MONTH)); - setCurrentDay(cal.get(Calendar.DAY_OF_MONTH)); - } - } - }; - - private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() { - @Override - public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - int minValue = mMinuteSpinner.getMinValue(); - int maxValue = mMinuteSpinner.getMaxValue(); - int offset = 0; - if (oldVal == maxValue && newVal == minValue) { - offset += 1; - } else if (oldVal == minValue && newVal == maxValue) { - offset -= 1; - } - if (offset != 0) { - mDate.add(Calendar.HOUR_OF_DAY, offset); - mHourSpinner.setValue(getCurrentHour()); - updateDateControl(); - int newHour = getCurrentHourOfDay(); - if (newHour >= HOURS_IN_HALF_DAY) { - mIsAm = false; - updateAmPmControl(); - } else { - mIsAm = true; - updateAmPmControl(); - } - } + }; + + /** + * 分钟变更监听器 + */ + private final NumberPicker.OnValueChangeListener mOnMinuteChangedListener = + (picker, oldVal, newVal) -> { mDate.set(Calendar.MINUTE, newVal); onDateTimeChanged(); - } - }; - - private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() { - @Override - public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - mIsAm = !mIsAm; - if (mIsAm) { - mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY); - } else { - mDate.add(Calendar.HOUR_OF_DAY, HOURS_IN_HALF_DAY); - } - updateAmPmControl(); + }; + + /** + * AM/PM变更监听器 + */ + private final NumberPicker.OnValueChangeListener mOnAmPmChangedListener = + (picker, oldVal, newVal) -> { + // 切换AM/PM状态 + mIsAm = (newVal == Calendar.AM); + + // 调整时间:AM->PM加12小时,PM->AM减12小时 + int hour = mDate.get(Calendar.HOUR_OF_DAY); + hour = mIsAm ? hour % 12 : hour % 12 + 12; + mDate.set(Calendar.HOUR_OF_DAY, hour); + + updateHourControl(); onDateTimeChanged(); - } - }; + }; + /** + * 日期时间变更回调接口 + */ public interface OnDateTimeChangedListener { void onDateTimeChanged(DateTimePicker view, int year, int month, int dayOfMonth, int hourOfDay, int minute); } + /*************************** 构造函数 ***************************/ + public DateTimePicker(Context context) { - this(context, System.currentTimeMillis()); + this(context, null); + } + + public DateTimePicker(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DateTimePicker(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + // 使用当前时间初始化 + init(context, System.currentTimeMillis(), DateFormat.is24HourFormat(context)); } public DateTimePicker(Context context, long date) { @@ -173,57 +181,85 @@ public class DateTimePicker extends FrameLayout { public DateTimePicker(Context context, long date, boolean is24HourView) { super(context); + init(context, date, is24HourView); + } + + /** + * 初始化日期时间选择器 + */ + private void init(Context context, long date, boolean is24HourView) { + // 初始化日期对象 mDate = Calendar.getInstance(); - mInitialising = true; - mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY; + mState = MODE_INITIALIZING; + mIs24HourView = is24HourView; + + // 确定初始AM/PM状态 + int currentHour = (int) (date / (60 * 60 * 1000) % 24); + mIsAm = currentHour < 12; + + // 加载布局 inflate(context, R.layout.datetime_picker, this); - mDateSpinner = (NumberPicker) findViewById(R.id.date); + // 初始化日期选择器 + mDateSpinner = findViewById(R.id.date); mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL); mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL); mDateSpinner.setOnValueChangedListener(mOnDateChangedListener); + mDateSpinner.setWrapSelectorWheel(false); - mHourSpinner = (NumberPicker) findViewById(R.id.hour); + // 初始化小时选择器 + mHourSpinner = findViewById(R.id.hour); mHourSpinner.setOnValueChangedListener(mOnHourChangedListener); - mMinuteSpinner = (NumberPicker) findViewById(R.id.minute); - mMinuteSpinner.setMinValue(MINUT_SPINNER_MIN_VAL); - mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL); + + // 初始化分钟选择器 + mMinuteSpinner = findViewById(R.id.minute); + mMinuteSpinner.setMinValue(MINUTE_SPINNER_MIN_VAL); + mMinuteSpinner.setMaxValue(MINUTE_SPINNER_MAX_VAL); mMinuteSpinner.setOnLongPressUpdateInterval(100); mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener); - String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings(); - mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm); + // 初始化AM/PM选择器 + mAmPmSpinner = findViewById(R.id.amPm); mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL); mAmPmSpinner.setMaxValue(AMPM_SPINNER_MAX_VAL); - mAmPmSpinner.setDisplayedValues(stringsForAmPm); + + // 本地化AM/PM符号 + updateAmPmSymbols(); mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener); - // update controls to initial state + // 更新UI控件 updateDateControl(); updateHourControl(); updateAmPmControl(); - set24HourView(is24HourView); - - // set to current time + // 设置初始时间 setCurrentDate(date); + // 应用启用状态 setEnabled(isEnabled()); - // set the content descriptions - mInitialising = false; + // 应用深色模式 + applyDarkMode(); + + // 初始化完成 + mState = MODE_NORMAL; } + /*************************** 公共方法 ***************************/ + @Override public void setEnabled(boolean enabled) { if (mIsEnabled == enabled) { return; } super.setEnabled(enabled); + + // 设置子控件状态 mDateSpinner.setEnabled(enabled); mMinuteSpinner.setEnabled(enabled); mHourSpinner.setEnabled(enabled); mAmPmSpinner.setEnabled(enabled); + mIsEnabled = enabled; } @@ -233,37 +269,37 @@ public class DateTimePicker extends FrameLayout { } /** - * Get the current date in millis - * - * @return the current date in millis + * 获取当前时间戳 (毫秒) */ public long getCurrentDateInTimeMillis() { return mDate.getTimeInMillis(); } /** - * Set the current date - * - * @param date The current date in millis + * 设置当前时间 */ public void setCurrentDate(long date) { + // 验证日期范围 + if (date < mMinDate || date > mMaxDate) { + Log.w(TAG, "设置日期超出范围: " + date); + return; + } + Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(date); - setCurrentDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), - cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE)); + setCurrentDate( + cal.get(Calendar.YEAR), + cal.get(Calendar.MONTH), + cal.get(Calendar.DAY_OF_MONTH), + cal.get(Calendar.HOUR_OF_DAY), + cal.get(Calendar.MINUTE) + ); } /** - * Set the current date - * - * @param year The current year - * @param month The current month - * @param dayOfMonth The current dayOfMonth - * @param hourOfDay The current hourOfDay - * @param minute The current minute + * 设置日期时间 */ - public void setCurrentDate(int year, int month, - int dayOfMonth, int hourOfDay, int minute) { + public void setCurrentDate(int year, int month, int dayOfMonth, int hourOfDay, int minute) { setCurrentYear(year); setCurrentMonth(month); setCurrentDay(dayOfMonth); @@ -272,21 +308,18 @@ public class DateTimePicker extends FrameLayout { } /** - * Get current year - * - * @return The current year + * 获取当前年份 */ public int getCurrentYear() { return mDate.get(Calendar.YEAR); } /** - * Set current year - * - * @param year The current year + * 设置当前年份 */ public void setCurrentYear(int year) { - if (!mInitialising && year == getCurrentYear()) { + // 检查状态避免不必要的更新 + if (mState != MODE_INITIALIZING && year == getCurrentYear()) { return; } mDate.set(Calendar.YEAR, year); @@ -295,21 +328,17 @@ public class DateTimePicker extends FrameLayout { } /** - * Get current month in the year - * - * @return The current month in the year + * 获取当前月份 */ public int getCurrentMonth() { return mDate.get(Calendar.MONTH); } /** - * Set current month in the year - * - * @param month The month in the year + * 设置当前月份 */ public void setCurrentMonth(int month) { - if (!mInitialising && month == getCurrentMonth()) { + if (mState != MODE_INITIALIZING && month == getCurrentMonth()) { return; } mDate.set(Calendar.MONTH, month); @@ -318,21 +347,17 @@ public class DateTimePicker extends FrameLayout { } /** - * Get current day of the month - * - * @return The day of the month + * 获取当前日期 */ public int getCurrentDay() { return mDate.get(Calendar.DAY_OF_MONTH); } /** - * Set current day of the month - * - * @param dayOfMonth The day of the month + * 设置当前日期 */ public void setCurrentDay(int dayOfMonth) { - if (!mInitialising && dayOfMonth == getCurrentDay()) { + if (mState != MODE_INITIALIZING && dayOfMonth == getCurrentDay()) { return; } mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); @@ -341,68 +366,66 @@ public class DateTimePicker extends FrameLayout { } /** - * Get current hour in 24 hour mode, in the range (0~23) - * @return The current hour in 24 hour mode + * 获取当前小时(24小时制) */ public int getCurrentHourOfDay() { return mDate.get(Calendar.HOUR_OF_DAY); } - private int getCurrentHour() { - if (mIs24HourView){ - return getCurrentHourOfDay(); + /** + * 根据显示模式获取小时 + */ + private int getCurrentDisplayHour() { + int hour = getCurrentHourOfDay(); + if (mIs24HourView) { + return hour; } else { - int hour = getCurrentHourOfDay(); - if (hour > HOURS_IN_HALF_DAY) { - return hour - HOURS_IN_HALF_DAY; - } else { - return hour == 0 ? HOURS_IN_HALF_DAY : hour; + if (hour == 0 || hour == 12) { + return 12; } + return hour % 12; } } /** - * Set current hour in 24 hour mode, in the range (0~23) - * - * @param hourOfDay + * 设置当前小时(24小时制) */ public void setCurrentHour(int hourOfDay) { - if (!mInitialising && hourOfDay == getCurrentHourOfDay()) { + // 验证小时值是否有效 + if (hourOfDay < 0 || hourOfDay > 23) { + Log.e(TAG, "无效的小时值: " + hourOfDay); + return; + } + + if (mState != MODE_INITIALIZING && hourOfDay == getCurrentHourOfDay()) { return; } + mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); + + // 更新AM/PM状态 if (!mIs24HourView) { - if (hourOfDay >= HOURS_IN_HALF_DAY) { - mIsAm = false; - if (hourOfDay > HOURS_IN_HALF_DAY) { - hourOfDay -= HOURS_IN_HALF_DAY; - } - } else { - mIsAm = true; - if (hourOfDay == 0) { - hourOfDay = HOURS_IN_HALF_DAY; - } - } + mIsAm = (hourOfDay < 12); updateAmPmControl(); } - mHourSpinner.setValue(hourOfDay); + + // 更新显示值 + mHourSpinner.setValue(getCurrentDisplayHour()); onDateTimeChanged(); } /** - * Get currentMinute - * - * @return The Current Minute + * 获取当前分钟 */ public int getCurrentMinute() { return mDate.get(Calendar.MINUTE); } /** - * Set current minute + * 设置当前分钟 */ public void setCurrentMinute(int minute) { - if (!mInitialising && minute == getCurrentMinute()) { + if (mState != MODE_INITIALIZING && minute == getCurrentMinute()) { return; } mMinuteSpinner.setValue(minute); @@ -411,53 +434,148 @@ public class DateTimePicker extends FrameLayout { } /** - * @return true if this is in 24 hour view else false. + * 是否使用24小时制 */ public boolean is24HourView () { return mIs24HourView; } /** - * Set whether in 24 hour or AM/PM mode. - * - * @param is24HourView True for 24 hour mode. False for AM/PM mode. + * 设置24小时制模式 */ public void set24HourView(boolean is24HourView) { if (mIs24HourView == is24HourView) { return; } mIs24HourView = is24HourView; - mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE); - int hour = getCurrentHourOfDay(); + + // 更新AM/PM显示 + int amPmVisibility = is24HourView ? View.GONE : View.VISIBLE; + mAmPmSpinner.setVisibility(amPmVisibility); + + // 更新小时控制 updateHourControl(); - setCurrentHour(hour); - updateAmPmControl(); + setCurrentHour(getCurrentHourOfDay()); } + /** + * 设置最小可选日期 + */ + public void setMinDate(long minDate) { + mMinDate = minDate; + validateCurrentDate(); + } + + /** + * 设置最大可选日期 + */ + public void setMaxDate(long maxDate) { + mMaxDate = maxDate; + validateCurrentDate(); + } + + /** + * 设置日期时间变更监听器 + */ + public void setOnDateTimeChangedListener(OnDateTimeChangedListener listener) { + mOnDateTimeChangedListener = listener; + } + + /*************************** 私有方法 ***************************/ + + /** + * 计算新小时值 (处理滚动越界) + */ + private int computeNewHour(int oldVal, int newVal) { + int currentHour = getCurrentHourOfDay(); + + if (mIs24HourView) { + // 24小时制处理 + if (oldVal == HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW && newVal == 0) { + return 0; // 23 -> 0 + } else if (oldVal == 0 && newVal == HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW) { + return 23; // 0 -> 23 + } + } else { + // 12小时制处理 + if (oldVal == 12 && newVal == 11) { + return mIsAm ? 11 : 23; // PM状态下12->11实际上是23点 + } else if (oldVal == 11 && newVal == 12) { + return mIsAm ? 12 : 0; // AM状态下11->12是中午12点 + } + } + + // 基本转换 + int hour = newVal; + if (!mIs24HourView && !mIsAm && hour != 12) { + hour += 12; + } + + // 特殊处理中午12点 + if (hour == 24) hour = 0; + return hour; + } + + /** + * 更新日期控件显示 + */ private void updateDateControl() { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(mDate.getTimeInMillis()); - cal.add(Calendar.DAY_OF_YEAR, -DAYS_IN_ALL_WEEK / 2 - 1); - mDateSpinner.setDisplayedValues(null); - for (int i = 0; i < DAYS_IN_ALL_WEEK; ++i) { + + // 以当前日期为中心生成一周的日期 + cal.add(Calendar.DAY_OF_YEAR, -DAYS_IN_ALL_WEEK / 2); + + for (int i = 0; i < DAYS_IN_ALL_WEEK; i++) { + // 生成日期显示字符串 (带星期) + mDateDisplayValues[i] = formatDateWithWeekday(cal); cal.add(Calendar.DAY_OF_YEAR, 1); - mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal); } + + // 设置日期选择器显示内容 mDateSpinner.setDisplayedValues(mDateDisplayValues); - mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2); - mDateSpinner.invalidate(); + mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2); // 当前日期在中间位置 + } + + /** + * 格式化日期 (带星期显示) + */ + private String formatDateWithWeekday(Calendar calendar) { + java.text.DateFormat dateFormat = java.text.DateFormat.getDateInstance( + java.text.DateFormat.MEDIUM, Locale.getDefault()); + + // 添加星期显示 + String weekday = getWeekdayName(calendar.get(Calendar.DAY_OF_WEEK)); + return String.format("%s (%s)", + dateFormat.format(calendar.getTime()), + weekday + ); + } + + /** + * 获取本地化星期名称 + */ + private String getWeekdayName(int dayOfWeek) { + String[] weekdays = new DateFormatSymbols().getWeekdays(); + if (dayOfWeek >= Calendar.SUNDAY && dayOfWeek <= Calendar.SATURDAY) { + return weekdays[dayOfWeek]; + } + return ""; } + /** + * 更新AM/PM控件 + */ private void updateAmPmControl() { if (mIs24HourView) { - mAmPmSpinner.setVisibility(View.GONE); - } else { - int index = mIsAm ? Calendar.AM : Calendar.PM; - mAmPmSpinner.setValue(index); - mAmPmSpinner.setVisibility(View.VISIBLE); + return; } + mAmPmSpinner.setValue(mIsAm ? 0 : 1); } + /** + * 更新小时控件范围 + */ private void updateHourControl() { if (mIs24HourView) { mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW); @@ -466,20 +584,101 @@ public class DateTimePicker extends FrameLayout { mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW); mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW); } + mHourSpinner.setValue(getCurrentDisplayHour()); + } + + /** + * 更新AM/PM符号 + */ + private void updateAmPmSymbols() { + String[] ampmSymbols = new DateFormatSymbols().getAmPmStrings(); + if (ampmSymbols.length < 2) { + Log.e(TAG, "AM/PM符号获取失败"); + ampmSymbols = new String[]{"AM", "PM"}; // 默认值 + } + mAmPmSpinner.setDisplayedValues(ampmSymbols); + } + + /** + * 应用深色模式适配 + */ + private void applyDarkMode() { + // 在Android 10+系统上添加深色模式支持 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + setForceDarkAllowed(true); + } + } + + /** + * 验证当前日期是否在允许范围内 + */ + private void validateCurrentDate() { + long currentTime = getCurrentDateInTimeMillis(); + if (currentTime < mMinDate || currentTime > mMaxDate) { + // 自动调整到有效范围 + long newTime = Math.max(mMinDate, Math.min(currentTime, mMaxDate)); + setCurrentDate(newTime); + + // 触发更新 + updateDateControl(); + updateHourControl(); + updateAmPmControl(); + } } /** - * Set the callback that indicates the 'Set' button has been pressed. - * @param callback the callback, if null will do nothing + * 检查当前日期是否在允许范围内 */ - public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback) { - mOnDateTimeChangedListener = callback; + private boolean isDateInRange() { + long currentTime = mDate.getTimeInMillis(); + return currentTime >= mMinDate && currentTime <= mMaxDate; } + /** + * 回滚日期变化 + */ + private void revertDateChange() { + // 回滚到上一次有效日期 + if (mDateSpinner.getValue() > DAYS_IN_ALL_WEEK / 2) { + mDateSpinner.setValue(mDateSpinner.getValue() - 1); + } else if (mDateSpinner.getValue() < DAYS_IN_ALL_WEEK / 2) { + mDateSpinner.setValue(mDateSpinner.getValue() + 1); + } + } + + /** + * 显示日期范围警告 + */ + private void showDateRangeWarning() { + Context context = getContext(); + Calendar minCal = Calendar.getInstance(); + minCal.setTimeInMillis(mMinDate); + Calendar maxCal = Calendar.getInstance(); + maxCal.setTimeInMillis(mMaxDate); + + java.text.DateFormat df = java.text.DateFormat.getDateInstance(); + String msg = String.format( + context.getString(R.string.date_range_warning), + df.format(minCal.getTime()), + df.format(maxCal.getTime()) + ); + + Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); + } + + /** + * 触发日期时间变更事件 + */ private void onDateTimeChanged() { if (mOnDateTimeChangedListener != null) { - mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(), - getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute()); + mOnDateTimeChangedListener.onDateTimeChanged( + this, + getCurrentYear(), + getCurrentMonth(), + getCurrentDay(), + getCurrentHourOfDay(), + getCurrentMinute() + ); } } -} +} \ No newline at end of file