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.
java/ui/DateTimePicker.java

519 lines
15 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;
//日期选择器的值变化监听器
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:59变成00:00增加一天
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) {
// 如果从00:00变成11:59减少一天
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1);
isDateChanged = true;
}
// 如果小时从11:59变成00:00或从00:00变成11:59切换上午/下午
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) {
// 如果从23:59变成00:00增加一天
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true;
} else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {
// 如果从00:00变成23:59减少一天
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) {
// 如果从59变为00增加一个小时
offset += 1;
} else if (oldVal == minValue && newVal == maxValue) {
// 如果从00变为59减少一个小时
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();
}
}
// 设置新的分钟值
mDate.set(Calendar.MINUTE, newVal);
// 通知监听器日期时间已改变
onDateTimeChanged();
}
};
//AM/PM选择器的值变化监听器
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();
// 通知监听器日期时间已改变
onDateTimeChanged();
}
};
public interface OnDateTimeChangedListener {
/**
* 当日期时间发生变化时调用。
* @param view 触发变化的DateTimePicker视图。
* @param year 年份。
* @param month 月份0-11
* @param dayOfMonth 月份中的日期。
* @param hourOfDay 一天中的小时0-23
* @param minute 分钟0-59
*/
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;
// 初始化上午/下午标志
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);
// 初始化AM/PM选择器
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();
// 设置是否为24小时视图
set24HourView(is24HourView);
// 设置当前日期
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 当前日期的时间戳。
*/
/**
* 获取当前日期的时间戳(毫秒为单位)。
* @return 当前日期的时间戳。
*/
public long getCurrentDateInTimeMillis() {
return mDate.getTimeInMillis();
}
/**
* 设置当前日期。
* 接受一个时间戳(毫秒为单位)或通过年、月、日、小时、分钟来设置日期。
* @param date 当前日期的时间戳(毫秒为单位)。
*/
public void setCurrentDate(long date) {
// 创建一个Calendar实例并设置其时间戳
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(date);
// 调用更详细的setCurrentDate方法来设置日期
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 当前月份0-11
* @param dayOfMonth 当前日期。
* @param hourOfDay 当前小时0-23
* @param minute 当前分钟0-59
*/
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 当前月份0-11
*/
public int getCurrentMonth() {
return mDate.get(Calendar.MONTH);
}
/**
* 设置当前年份中的月份。
* 如果月份没有变化,则不会触发任何更新。
* @param month 当前月份0-11
*/
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小时制下的当前小时。
* @return 24小时制下的当前小时0-23
*/
public int getCurrentHourOfDay() {
return mDate.get(Calendar.HOUR_OF_DAY);
}
/**
* 获取当前的小时。
* 根据是否为24小时视图返回适当的小时值。
* @return 当前的小时0-11或者0-23
*/
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小时制下的当前小时。
* 如果小时没有变化,则不会触发任何更新。
* @param hourOfDay 24小时制下的当前小时0-23
*/
/**
* 获取当前的分钟数。
* @return 当前的分钟数0-59
*/
public int getCurrentMinute() {
return mDate.get(Calendar.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;
}
mIs24HourView = is24HourView;
// 根据24小时视图设置AM/PM选择器的可见性
mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE);
// 更新小时选择器以适应新的视图
updateHourControl();
// 设置当前小时以适应新的视图
setCurrentHour(getCurrentHourOfDay());
// 更新AM/PM控制
updateAmPmControl();
}
/**
* 更新日期控制器的显示。
*/
private void updateDateControl() {
// 创建一个Calendar实例并将时间设置为当前日期减去一周的一半
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() {
// 如果为24小时视图则隐藏AM/PM选择器
if (mIs24HourView) {
mAmPmSpinner.setVisibility(View.GONE);
} else {
// 设置AM/PM选择器的值
int index = mIsAm ? Calendar.AM : Calendar.PM;
mAmPmSpinner.setValue(index);
// 显示AM/PM选择器
mAmPmSpinner.setVisibility(View.VISIBLE);
}
}
/**
* 更新小时控制器的显示。
*/
private void updateHourControl() {
if (mIs24HourView) {
// 如果为24小时视图设置小时选择器的最小和最大值
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW);
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW);
} else {
// 如果为AM/PM视图设置小时选择器的最小和最大值
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());
}
}