You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
xiaomi_note/ui/DateTimePicker.java

550 lines
19 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui;
import java.text.DateFormatSymbols;
import java.util.Calendar;
import net.micode.notes.R;
import android.content.Context;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.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 String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK]; // 日期显示值
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(); // 日期时间改变回调
}
};
// 小时改变监听器
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) { // 如果不是24小时制
// 判断是否需要调整日期
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 { // 如果是24小时制
// 判断是否需要调整日期
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);
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; // 偏移量初始化为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) { // 如果当前小时大于等于12
mIsAm = false; // 设置为下午
updateAmPmControl(); // 更新上午/下午选择器控件
} else {
mIsAm = true; // 设置为上午
updateAmPmControl(); // 更新上午/下午选择器控件
}
}
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); // 如果是上午减去12小时
} else {
mDate.add(Calendar.HOUR_OF_DAY, HOURS_IN_HALF_DAY); // 如果是下午加上12小时
}
updateAmPmControl(); // 更新上午/下午选择器控件
onDateTimeChanged(); // 日期时间改变回调
}
};
// 日期时间改变监听器接口
public interface OnDateTimeChangedListener {
void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute);
}
// 构造函数根据当前时间初始化DateTimePicker
public DateTimePicker(Context context) {
this(context, System.currentTimeMillis());
}
// 构造函数根据指定时间和是否为24小时制初始化DateTimePicker
public DateTimePicker(Context context, long date) {
this(context, date, DateFormat.is24HourFormat(context));
}
// 构造函数根据指定时间、指定是否为24小时制初始化DateTimePicker
public DateTimePicker(Context context, long date, boolean is24HourView) {
super(context);
mDate = Calendar.getInstance(); // 初始化日历实例
mInitialising = true; // 标记初始化中
mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY; // 根据当前小时是否大于等于12判断是否为上午
inflate(context, R.layout.datetime_picker, this); // 填充布局
// 初始化日期选择器
mDateSpinner = (NumberPicker) findViewById(R.id.date);
mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL);
mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL);
mDateSpinner.setOnValueChangedListener(mOnDateChangedListener);
// 初始化小时选择器
mHourSpinner = (NumberPicker) 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.setOnLongPressUpdateInterval(100);
mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener);
// 初始化上午/下午选择器
String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings();
mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm);
mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL);
mAmPmSpinner.setMaxValue(AMPM_SPINNER_MAX_VAL);
mAmPmSpinner.setDisplayedValues(stringsForAmPm);
mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener);
// 更新控件到初始状态
updateDateControl();
updateHourControl();
updateAmPmControl();
set24HourView(is24HourView); // 设置是否为24小时制
setCurrentDate(date); // 设置当前时间
setEnabled(isEnabled()); // 设置是否可用
// 设置内容描述
mInitialising = false;
}
// 设置DateTimePicker的可用状态
@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;
}
// 获取DateTimePicker的可用状态
@Override
public boolean isEnabled() {
return mIsEnabled;
}
/**
* 获取当前日期的毫秒表示
*
* @return 当前日期的毫秒表示
*/
public long getCurrentDateInTimeMillis() {
return mDate.getTimeInMillis();
}
/**
* 设置当前日期
*
* @param date 当前日期的毫秒表示
*/
public void setCurrentDate(long date) {
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));
}
/**
* 设置当前日期
*
* @param year 年份
* @param month 月份
* @param dayOfMonth 日期
* @param hourOfDay 小时
* @param minute 分钟
*/
public void setCurrentDate(int year, int month,
int dayOfMonth, int hourOfDay, int minute) {
setCurrentYear(year);
setCurrentMonth(month);
setCurrentDay(dayOfMonth);
setCurrentHour(hourOfDay);
setCurrentMinute(minute);
}
/**
* 获取当前年份
*
* @return 当前年份
*/
public int getCurrentYear() {
return mDate.get(Calendar.YEAR);
}
/**
* 设置当前年份
*
* @param year 当前年份
*/
public void setCurrentYear(int year) {
if (!mInitialising && year == getCurrentYear()) {
return;
}
mDate.set(Calendar.YEAR, year);
updateDateControl();
onDateTimeChanged();
}
/**
* 获取当前月份
*
* @return 当前月份
*/
public int getCurrentMonth() {
return mDate.get(Calendar.MONTH);
}
/**
* 设置当前月份
*
* @param month 月份
*/
public void setCurrentMonth(int month) {
if (!mInitialising && month == getCurrentMonth()) {
return;
}
mDate.set(Calendar.MONTH, month);
updateDateControl();
onDateTimeChanged();
}
/**
* 获取当前月份中的日期
*
* @return 当前月份中的日期
*/
public int getCurrentDay() {
return mDate.get(Calendar.DAY_OF_MONTH);
}
/**
* 设置当前月份中的日期
*
* @param dayOfMonth 月份中的日期
*/
public void setCurrentDay(int dayOfMonth) {
if (!mInitialising && dayOfMonth == getCurrentDay()) {
return;
}
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
updateDateControl();
onDateTimeChanged();
}
/**
* 获取24小时制下的当前小时范围为0~23
*
* @return 24小时制下的当前小时
*/
public int getCurrentHourOfDay() {
return mDate.get(Calendar.HOUR_OF_DAY);
}
/**
* 获取当前小时如果为24小时制则返回24小时制下的当前小时否则返回12小时制下的当前小时
* @return 当前小时
*/
private int getCurrentHour() {
if (mIs24HourView){
return getCurrentHourOfDay();
} 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;
}
}
}
/**
* 设置当前小时24小时制下范围为0~23
*
* @param hourOfDay 当前小时
*/
public void setCurrentHour(int hourOfDay) {
// 如果不是初始化状态并且传入的小时等于当前小时,则直接返回
if (!mInitialising && hourOfDay == getCurrentHourOfDay()) {
return;
}
// 设置日期时间中的小时
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
// 如果不是24小时制则更新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;
}
}
updateAmPmControl(); // 更新AM/PM控件
}
mHourSpinner.setValue(hourOfDay); // 更新小时控件显示值
onDateTimeChanged(); // 触发日期时间改变事件
}
/**
* 获取当前分钟
*
* @return 当前分钟
*/
public int getCurrentMinute() {
return mDate.get(Calendar.MINUTE);
}
/**
* 设置当前分钟
*
* @param minute 分钟
*/
public void setCurrentMinute(int minute) {
if (!mInitialising && minute == getCurrentMinute()) {
return;
}
// 设置日期时间中的分钟
mMinuteSpinner.setValue(minute);
mDate.set(Calendar.MINUTE, minute);
onDateTimeChanged(); // 触发日期时间改变事件
}
/**
* 检查是否处于24小时制模式
*
* @return 如果处于24小时制模式返回true否则返回false
*/
public boolean is24HourView() {
return mIs24HourView;
}
/**
* 设置是否处于24小时制模式或AM/PM模式
*
* @param is24HourView true表示处于24小时制模式false表示处于AM/PM模式
*/
public void set24HourView(boolean is24HourView) {
if (mIs24HourView == is24HourView) {
return;
}
// 设置是否为24小时制模式
mIs24HourView = is24HourView;
// 根据是否是24小时制设置AM/PM控件的可见性
mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE);
// 获取当前小时并更新小时控件
int hour = getCurrentHourOfDay();
updateHourControl(); // 更新小时控件
setCurrentHour(hour); // 设置当前小时
updateAmPmControl(); // 更新AM/PM控件
}
/**
* 更新日期控件
*/
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, 1);
mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal);
}
mDateSpinner.setDisplayedValues(mDateDisplayValues);
mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2);
mDateSpinner.invalidate();
}
/**
* 更新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);
}
}
/**
* 更新小时控件
*/
private void updateHourControl() {
if (mIs24HourView) {
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW);
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW);
} else {
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW);
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW);
}
}
/**
* 设置“设置”按钮按下时的回调
*
* @param callback 回调函数如果为null则不执行任何操作
*/
public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback) {
mOnDateTimeChangedListener = callback;
}
/**
* 当日期时间发生改变时的回调函数
*/
private void onDateTimeChanged() {
if (mOnDateTimeChangedListener != null) {
// 触发日期时间改变事件,传递当前年、月、日、小时、分钟
mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(),
getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute());
}
}
}