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.
ReadMiNotes/代码标注/DateTimePicker.java

516 lines
20 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() { // 创建一个NumberPicker.OnValueChangeListener的匿名内部类用于监听NumberPicker的值改变
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal); // 计算新旧值之间的差值并将其加到mDate中
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) {
if (mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) { // 如果当前是上午且当前小时是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) { // 如果当前是下午且当前小时是half day则设置当前时间为上午
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 || // 如果当前是上午且当前小时是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) { // 如果当前是24小时制且当前小时是all day则设置当前时间为次日
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true;
}
else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) { // 如果当前是24小时制且当前小时是all day则设置当前时间为次日
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;
if (oldVal == maxValue && newVal == minValue) { // 如果旧的值是最大值新的值是最小值则偏移量加1
offset += 1;
} else if (oldVal == minValue && newVal == maxValue) { // 如果旧的值是最小值新的值是最大值则偏移量减1
offset -= 1;
}
if (offset != 0) { // 如果偏移量不等于0则添加偏移量
mDate.add(Calendar.HOUR_OF_DAY, offset); // 添加偏移量
mHourSpinner.setValue(getCurrentHour()); // 设置小时数字选择器的值
updateDateControl(); // 更新日期控件
int newHour = getCurrentHourOfDay(); // 获取当前的小时
if (newHour >= HOURS_IN_HALF_DAY) { // 如果当前的小时大于等于12则设置AM为false
mIsAm = false;
updateAmPmControl(); // 更新AM/PM控件
} else { // 否则设置AM为true
mIsAm = true;
updateAmPmControl(); // 更新AM/PM控件
}
}
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控制
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) { // 创建一个DateTimePicker对象参数为context和datedateFormat默认为24小时制
this(context, date, DateFormat.is24HourFormat(context));
}
public DateTimePicker(Context context, long date, boolean is24HourView) { // 创建DateTimePicker对象传入上下文、日期和是否24小时视图
super(context);
mDate = Calendar.getInstance();
mInitialising = true;
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(); // 设置AM/PM选择器
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(); // 更新AM/PM控制
set24HourView(is24HourView); // 设置24小时视图
setCurrentDate(date); // 设置当前日期
setEnabled(isEnabled()); // 设置是否可用
mInitialising = false;
}
@Override
public void setEnabled(boolean enabled) {
if (mIsEnabled == enabled) { // 判断当前状态是否和传入的参数一致
return;
}
super.setEnabled(enabled); // 调用父类的setEnabled方法
mDateSpinner.setEnabled(enabled); // 设置日期选择器是否可用
mMinuteSpinner.setEnabled(enabled); // 设置分钟选择器是否可用
mHourSpinner.setEnabled(enabled); // 设置小时选择器是否可用
mAmPmSpinner.setEnabled(enabled); // 设置上午/下午选择器是否可用
mIsEnabled = enabled; // 更新状态
}
@Override
public boolean isEnabled() {
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() {
if (mIs24HourView){ // 24小时模式
return getCurrentHourOfDay();
} else { // 12小时模式
int hour = getCurrentHourOfDay();
if (hour > HOURS_IN_HALF_DAY) { // 当前小时大于12小时返回当前小时减去12小时
return hour - HOURS_IN_HALF_DAY;
} else { // 当前小时小于等于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); //设置当前小时
if (!mIs24HourView) { //如果不是24小时制
if (hourOfDay >= HOURS_IN_HALF_DAY) { //如果传入的参数大于等于12
mIsAm = false; //设置AM为false
if (hourOfDay > HOURS_IN_HALF_DAY) { //如果传入的参数大于12
hourOfDay -= HOURS_IN_HALF_DAY; //减去12
}
} else {
mIsAm = true; //设置AM为true
if (hourOfDay == 0) { //如果传入的参数等于0
hourOfDay = HOURS_IN_HALF_DAY; //设置为12
}
}
updateAmPmControl(); //更新AM/PM控制
}
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) { //设置当前分钟
if (!mInitialising && minute == getCurrentMinute()) { //如果初始化未完成,且分钟数相同,则返回
return;
}
mMinuteSpinner.setValue(minute); //设置分钟数
mDate.set(Calendar.MINUTE, minute); //设置日期
onDateTimeChanged(); //更新时间
}
/**
* @return true if this is in 24 hour view else false.
*/
public boolean is24HourView () { //获取是否是24小时视图
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) { //设置24小时视图
if (mIs24HourView == is24HourView) {
return;
}
mIs24HourView = is24HourView;
mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE); //设置时间控制条的可见性
int hour = getCurrentHourOfDay(); //获取当前的小时
updateHourControl(); //更新小时控制条
setCurrentHour(hour); //设置当前的小时
updateAmPmControl(); //更新上午/下午控制条
}
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();
}
private void updateAmPmControl() {
if (mIs24HourView) { // 如果24小时视图是可见的则隐藏AM/PM控制
mAmPmSpinner.setVisibility(View.GONE);
} else {
int index = mIsAm ? Calendar.AM : Calendar.PM; // 否则如果当前是AM则设置索引为Calendar.AM否则设置为Calendar.PM
mAmPmSpinner.setValue(index);
mAmPmSpinner.setVisibility(View.VISIBLE);
}
}
private void updateHourControl() {
if (mIs24HourView) { // 根据mIs24HourView的值来更新mHourSpinner的值
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);
}
}
/**
* 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) { // 当日期时间改变时调用
mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(),
getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute());
}
}
}