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.
Dome/src1/net/micode/notes/ui/DateTimePicker.java

631 lines
23 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;
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();
// 判断是否为24小时制
if (!mIs24HourView) {
// 判断是否为上午
if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) {
// 如果当前时间是上午11点并且选择的时间是下午12点则日期加1天
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) {
// 如果当前时间是下午12点并且选择的时间是上午11点则日期减1天
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1);
isDateChanged = true;
}
// 判断是否跨过12点
if (oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY ||
oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
// 跨过12点则上午和下午互换
mIsAm = !mIsAm;
updateAmPmControl();
}
} else {
// 判断是否跨过24点
if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) {
// 如果当前时间是23点并且选择的时间是0点则日期加1天
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true;
} else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {
// 如果当前时间是0点并且选择的时间是23点则日期减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;
// 如果旧值等于最大值且新值等于最小值则偏移量为1
if (oldVal == maxValue && newVal == minValue) {
offset += 1;
// 如果旧值等于最小值且新值等于最大值,则偏移量为-1
} else if (oldVal == minValue && newVal == maxValue) {
offset -= 1;
}
// 如果偏移量不为0则更新日期和时间
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();
}
}
// 设置新分钟值
mDate.set(Calendar.MINUTE, newVal);
// 日期时间改变
onDateTimeChanged();
}
};
// 定义一个NumberPicker的值改变监听器
private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 切换AM/PM
mIsAm = !mIsAm;
// 如果是AM则将时间减去12小时
if (mIsAm) {
mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY);
// 如果是PM则将时间加上12小时
} else {
mDate.add(Calendar.HOUR_OF_DAY, HOURS_IN_HALF_DAY);
}
// 更新AM/PM控制
updateAmPmControl();
// 日期时间改变
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());
}
// 构造方法,使用指定时间作为日期时间
public DateTimePicker(Context context, long date) {
this(context, date, DateFormat.is24HourFormat(context));
}
public DateTimePicker(Context context, long date, boolean is24HourView) {
super(context);
// 获取当前日期
mDate = Calendar.getInstance();
mInitialising = true;
// 判断当前小时是否大于等于12
mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY;
// 加载布局文件
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);
// update controls to initial state
updateDateControl();
updateHourControl();
updateAmPmControl();
set24HourView(is24HourView);
// set to current time
setCurrentDate(date);
setEnabled(isEnabled());
// set the content descriptions
mInitialising = false;
}
@Override
// 重写setEnabled方法
public void setEnabled(boolean enabled) {
// 如果当前状态和传入的状态相同,则直接返回
if (mIsEnabled == enabled) {
return;
}
// 调用父类的setEnabled方法
super.setEnabled(enabled);
// 设置日期选择器是否可用
mDateSpinner.setEnabled(enabled);
// 设置分钟选择器是否可用
mMinuteSpinner.setEnabled(enabled);
// 设置小时选择器是否可用
mHourSpinner.setEnabled(enabled);
// 设置上午/下午选择器是否可用
mAmPmSpinner.setEnabled(enabled);
// 更新当前状态
mIsEnabled = enabled;
}
@Override
public boolean isEnabled() {
// 返回mIsEnabled的值
return mIsEnabled;
}
/**
* 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) {
// 获取当前日期
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));
}
/**
* 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) {
// 设置当前年份
setCurrentYear(year);
// 设置当前月份
setCurrentMonth(month);
// 设置当前日期
setCurrentDay(dayOfMonth);
// 设置当前小时
setCurrentHour(hourOfDay);
// 设置当前分钟
setCurrentMinute(minute);
}
/**
* 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()) {
return;
}
// 设置当前年份
mDate.set(Calendar.YEAR, year);
// 更新日期控件
updateDateControl();
// 日期时间改变
onDateTimeChanged();
}
/**
* 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()) {
return;
}
// 设置当前月份
mDate.set(Calendar.MONTH, month);
// 更新日期控件
updateDateControl();
// 日期改变回调
onDateTimeChanged();
}
/**
* 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()) {
return;
}
// 设置当前日期
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
// 更新日期控件
updateDateControl();
// 日期改变时触发
onDateTimeChanged();
}
/**
* Get current hour in 24 hour mode, in the range (0~23)
* @return The current hour in 24 hour mode
*/
// 获取当前小时
public int getCurrentHourOfDay() {
return mDate.get(Calendar.HOUR_OF_DAY);
}
// 获取当前小时
private int getCurrentHour() {
// 如果是24小时制
if (mIs24HourView){
// 获取当前小时
return getCurrentHourOfDay();
} else {
// 获取当前小时
int hour = getCurrentHourOfDay();
// 如果当前小时大于12
if (hour > HOURS_IN_HALF_DAY) {
// 返回当前小时减去12
return hour - HOURS_IN_HALF_DAY;
} else {
// 如果当前小时等于0返回12
return hour == 0 ? HOURS_IN_HALF_DAY : hour;
}
}
}
/**
* Set current hour in 24 hour mode, in the range (0~23)
*
* @param hourOfDay
*/
// 设置当前小时
public void setCurrentHour(int hourOfDay) {
// 如果当前正在初始化,或者当前小时和要设置的小时相同,则直接返回
if (!mInitialising && hourOfDay == getCurrentHourOfDay()) {
return;
}
// 设置当前小时
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
// 如果不是24小时制
if (!mIs24HourView) {
// 如果当前小时大于等于12
if (hourOfDay >= HOURS_IN_HALF_DAY) {
// 设置为下午
mIsAm = false;
// 如果当前小时大于12
if (hourOfDay > HOURS_IN_HALF_DAY) {
// 当前小时减去12
hourOfDay -= HOURS_IN_HALF_DAY;
}
} else {
// 设置为上午
mIsAm = true;
// 如果当前小时为0
if (hourOfDay == 0) {
// 当前小时设置为12
hourOfDay = HOURS_IN_HALF_DAY;
}
}
// 更新上午/下午控制
updateAmPmControl();
}
// 设置小时选择器的值
mHourSpinner.setValue(hourOfDay);
// 日期时间改变
onDateTimeChanged();
}
/**
* Get currentMinute
*
* @return The Current Minute
*/
// 获取当前分钟
public int getCurrentMinute() {
return mDate.get(Calendar.MINUTE);
}
/**
* Set current minute
*/
public void setCurrentMinute(int minute) {
// 如果mInitialising为false且minute等于getCurrentMinute(),则直接返回
if (!mInitialising && minute == getCurrentMinute()) {
return;
}
// 设置mMinuteSpinner的值为minute
mMinuteSpinner.setValue(minute);
// 设置mDate的分钟为minute
mDate.set(Calendar.MINUTE, minute);
// 调用onDateTimeChanged()方法
onDateTimeChanged();
}
/**
* @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.
*/
public void set24HourView(boolean is24HourView) {
// 如果当前时间格式和传入的时间格式相同,则直接返回
if (mIs24HourView == is24HourView) {
return;
}
// 更新时间格式
mIs24HourView = is24HourView;
// 如果是24小时制则隐藏上午/下午选择器
mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE);
// 获取当前小时数
int hour = getCurrentHourOfDay();
// 更新小时选择器
updateHourControl();
// 设置当前小时数
setCurrentHour(hour);
// 更新上午/下午选择器
updateAmPmControl();
}
private void updateDateControl() {
// 获取当前日期
Calendar cal = Calendar.getInstance();
// 将当前日期设置为mDate的时间
cal.setTimeInMillis(mDate.getTimeInMillis());
// 将当前日期向前推DAYS_IN_ALL_WEEK / 2 - 1天
cal.add(Calendar.DAY_OF_YEAR, -DAYS_IN_ALL_WEEK / 2 - 1);
// 清空mDateSpinner的显示值
mDateSpinner.setDisplayedValues(null);
// 循环DAYS_IN_ALL_WEEK次
for (int i = 0; i < DAYS_IN_ALL_WEEK; ++i) {
// 将当前日期加1天
cal.add(Calendar.DAY_OF_YEAR, 1);
// 将当前日期格式化为"MM.dd EEEE"的字符串
mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal);
}
// 将mDateSpinner的显示值设置为mDateDisplayValues
mDateSpinner.setDisplayedValues(mDateDisplayValues);
// 将mDateSpinner的值设置为DAYS_IN_ALL_WEEK / 2
mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2);
// 使mDateSpinner无效
mDateSpinner.invalidate();
}
private void updateAmPmControl() {
// 如果是24小时制则隐藏上午/下午选择器
if (mIs24HourView) {
mAmPmSpinner.setVisibility(View.GONE);
} else {
// 如果是上午,则选择上午,否则选择下午
int index = mIsAm ? Calendar.AM : Calendar.PM;
mAmPmSpinner.setValue(index);
// 显示上午/下午选择器
mAmPmSpinner.setVisibility(View.VISIBLE);
}
}
// 更新小时控件
private void updateHourControl() {
// 如果是24小时制
if (mIs24HourView) {
// 设置小时选择器的最小值为24小时制最小值
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW);
// 设置小时选择器的最大值为24小时制最大值
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW);
} else {
// 设置小时选择器的最小值为12小时制最小值
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW);
// 设置小时选择器的最大值为12小时制最大值
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW);
}
}
/**
* 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 void onDateTimeChanged() {
// 如果日期时间改变监听器不为空
if (mOnDateTimeChangedListener != null) {
// 调用日期时间改变监听器的onDateTimeChanged方法并传入当前日期时间
mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(),
getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute());
}
}
}