Android 时间选取器
若要为用户提供选择时间的方法,可以使用 TimePicker。 Android 应用通常将 TimePicker
与 TimePickerDialog 一起使用以选择时间值 - 这有助于确保跨设备和应用程序实现一致的接口。 TimePicker
允许用户在 24 小时或 12 小时 AM/PM 模式下选择一天中的时间。
TimePickerDialog
是一个帮助程序类,用于将 TimePicker
封装在对话框中。
概述
新式 Android 应用程序在 DialogFragment 中显示 TimePickerDialog
。 这样,应用程序就可以将 TimePicker
作为弹出对话框显示或嵌入到活动中。 此外,DialogFragment
还管理对话框的生命周期和显示,从而减少必须实现的代码量。
本指南演示如何使用 TimePickerDialog
,它包装在 DialogFragment
中。 当用户单击活动上的按钮时,示例应用程序将 TimePickerDialog
显示为模态对话框。 当用户设置了时间时,对话框会退出,处理程序会在“活动”屏幕上用所选时间更新 TextView
。
要求
本指南的示例应用程序面向 Android 4.1(API 级别 16)或更高版本,但也可用于 Android 3.0(API 级别 11 或更高版本)。 通过向项目添加 Android 支持库 v4 并更改一些代码,可以支持旧版 Android。
使用 TimePicker
此示例扩展了 DialogFragment
;DialogFragment
的子类实现(下面称为 TimePickerFragment
)承载并显示 TimePickerDialog
。 首次启动示例应用时,它会在将用于显示所选时间的 TextView
上方显示“选取时间”按钮:
单击“选取时间”按钮时,示例应用将启动 TimePickerDialog
,如以下屏幕截图所示:
在 TimePickerDialog
中,选择时间并单击“确定”按钮会导致 TimePickerDialog
调用方法 IOnTimeSetListener.OnTimeSet。
此接口由宿主 DialogFragment
(TimePickerFragment
,如下所述)实现。 单击“取消”按钮会导致消除片段和对话框。
DialogFragment
按以下三种方式之一返回宿主活动的选定时间:
调用某个方法或设置某个属性 – 活动可以提供专门用于设置此值的属性或方法。
引发某个事件 –
DialogFragment
可以定义当OnTimeSet
被调用时将引发的事件。使用
Action
–DialogFragment
可以调用Action<DateTime>
来在活动中显示时间。 活动将在实例化DialogFragment
时提供Action<DateTime
。
此示例将使用第三种技术,这要求活动向 DialogFragment
提供 Action<DateTime>
处理程序。
启动应用项目
启动名为 TimePickerDemo 的新 Android 项目(如果不熟悉如何创建 Xamarin.Android 项目,请参阅 Hello, Android 了解如何创建新项目)。
编辑 Resources/layout/Main.axml,并将其内容替换为以下 XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:padding="16dp">
<Button
android:id="@+id/select_button"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="PICK TIME"
android:textSize="20dp" />
<TextView
android:id="@+id/time_display"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:paddingTop="22dp"
android:text="Picked time will be displayed here"
android:textSize="24dp" />
</LinearLayout>
这是一个基本的 LinearLayout,其中包含一个用于显示时间的 TextView 和一个打开 TimePickerDialog
的按钮。 请注意,此布局使用硬编码的字符串和维度使应用更简单、更易于理解 – 生产应用通常使用这些值的资源(如 DatePicker 代码示例中所示)。
编辑 MainActivity.cs,用以下代码替代其内容:
using Android.App;
using Android.Widget;
using Android.OS;
using System;
using Android.Util;
using Android.Text.Format;
namespace TimePickerDemo
{
[Activity(Label = "TimePickerDemo", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
TextView timeDisplay;
Button timeSelectButton;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
timeDisplay = FindViewById<TextView>(Resource.Id.time_display);
timeSelectButton = FindViewById<Button>(Resource.Id.select_button);
}
}
}
生成并运行此示例时,应会看到类似于以下屏幕截图的初始屏幕:
单击“选取时间”按钮不执行任何操作,因为 DialogFragment
尚未实现,无法显示 TimePicker
。
下一步是创建此 DialogFragment
。
扩展 DialogFragment
若要扩展 DialogFragment
以与 TimePicker
一起使用,必须创建派生自 DialogFragment
且实现 TimePickerDialog.IOnTimeSetListener
的子类。 将以下类添加到 MainActivity.cs:
public class TimePickerFragment : DialogFragment, TimePickerDialog.IOnTimeSetListener
{
public static readonly string TAG = "MyTimePickerFragment";
Action<DateTime> timeSelectedHandler = delegate { };
public static TimePickerFragment NewInstance(Action<DateTime> onTimeSelected)
{
TimePickerFragment frag = new TimePickerFragment();
frag.timeSelectedHandler = onTimeSelected;
return frag;
}
public override Dialog OnCreateDialog (Bundle savedInstanceState)
{
DateTime currentTime = DateTime.Now;
bool is24HourFormat = DateFormat.Is24HourFormat(Activity);
TimePickerDialog dialog = new TimePickerDialog
(Activity, this, currentTime.Hour, currentTime.Minute, is24HourFormat);
return dialog;
}
public void OnTimeSet(TimePicker view, int hourOfDay, int minute)
{
DateTime currentTime = DateTime.Now;
DateTime selectedTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, hourOfDay, minute, 0);
Log.Debug(TAG, selectedTime.ToLongTimeString());
timeSelectedHandler (selectedTime);
}
}
这个 TimePickerFragment
类被分为较小的部分,这在下一部分中有说明。
DialogFragment 实现
TimePickerFragment
实现了多种方法:工厂方法、对话框实例化方法和 TimePickerDialog.IOnTimeSetListener
所需的 OnTimeSet
处理程序方法。
TimePickerFragment
必须是DialogFragment
的子类。 它还实现了TimePickerDialog.IOnTimeSetListener
接口(即提供所需的OnTimeSet
方法):public class TimePickerFragment : DialogFragment, TimePickerDialog.IOnTimeSetListener
TAG
出于记录目的被初始化(MyTimePickerFragment 可以更改为要使用的任何字符串)。timeSelectedHandler
操作被初始化到一个空委托,以防止空引用异常:public static readonly string TAG = "MyTimePickerFragment"; Action<DateTime> timeSelectedHandler = delegate { };
NewInstance
工厂方法被调用以实例化新的TimePickerFragment
。 此方法采用用户在TimePickerDialog
中单击“确定”按钮时调用的Action<DateTime>
处理程序:public static TimePickerFragment NewInstance(Action<DateTime> onTimeSelected) { TimePickerFragment frag = new TimePickerFragment(); frag.timeSelectedHandler = onTimeSelected; return frag; }
显示片段时,Android 将调用
DialogFragment
方法 OnCreateDialog。 此方法会创建一个新的TimePickerDialog
对象,并使用活动、回调对象(即TimePickerFragment
的当前实例)和当前时间初始化该对象:public override Dialog OnCreateDialog (Bundle savedInstanceState) { DateTime currentTime = DateTime.Now; bool is24HourFormat = DateFormat.Is24HourFormat(Activity); TimePickerDialog dialog = new TimePickerDialog (Activity, this, currentTime.Hour, currentTime.Minute, is24HourFormat); return dialog; }
当用户更改
TimePicker
对话框中的时间设置时,将调用OnTimeSet
方法。OnTimeSet
会使用当前日期创建一个DateTime
对象,并在用户选择的时间(小时和分钟)合并:public void OnTimeSet(TimePicker view, int hourOfDay, int minute) { DateTime currentTime = DateTime.Now; DateTime selectedTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, hourOfDay, minute, 0);
这个
DateTime
对象会传递到在创建时向TimePickerFragment
对象注册的timeSelectedHandler
。OnTimeSet
调用此处理程序以将活动的时间显示更新为所选时间(此处理程序在下一部分中实现):timeSelectedHandler (selectedTime);
显示 TimePickerFragment
实现 DialogFragment
后,可以使用 NewInstance
工厂方法实例化 DialogFragment
并通过调用 DialogFragment.Show 来显示它:
将以下方法添加到 MainActivity
:
void TimeSelectOnClick (object sender, EventArgs eventArgs)
{
TimePickerFragment frag = TimePickerFragment.NewInstance (
delegate (DateTime time)
{
timeDisplay.Text = time.ToShortTimeString();
});
frag.Show(FragmentManager, TimePickerFragment.TAG);
}
TimeSelectOnClick
实例化 TimePickerFragment
后,它会为匿名方法创建并传入委托,该方法使用传入的时间值更新活动的时间显示。 最后,它会启动 TimePicker
对话框片段(通过 DialogFragment.Show
)向用户显示 TimePicker
。
在 OnCreate
方法末尾,添加以下行以将事件处理程序附加到启动对话框的“选取时间”按钮:
timeSelectButton.Click += TimeSelectOnClick;
单击“选取时间”按钮时,TimeSelectOnClick
将被调用以向用户显示 TimePicker
对话框片段。
尝试一下!
生成并运行应用。 单击“选取时间”按钮时,TimePickerDialog
按活动的默认时间格式显示(在本例中为 12 小时 AM/PM 模式):
在 TimePicker
对话框中单击“确定”时,处理程序会用所选的时间更新活动的 TextView
,然后退出:
接下来,在声明和初始化 is24HourFormat
后立即将以下代码行添加到 OnCreateDialog
:
is24HourFormat = true;
此更改强制使传递给 TimePickerDialog
构造函数的标志为 true
,以便使用 24 小时模式,而不是宿主活动的时间格式。 再次生成并运行应用时,单击“选取时间”按钮,TimePicker
对话框现在以 24 小时格式显示:
由于处理程序调用 DateTime.ToShortTimeString 以将时间打印到活动的 TextView
,因此时间仍以默认的 12 小时 AM/PM 格式打印。
总结
本文介绍了如何通过 Android 活动将 TimePicker
小组件显示为弹出模态对话框。 它提供了一个示例 DialogFragment
实现并讨论了 IOnTimeSetListener
接口。 此示例还演示了 DialogFragment
如何与宿主活动交互以显示所选时间。