Вот версия, которую я написал. Это код на C #, потому что я использую Xamarin, но я надеюсь, что никому не будет сложнее перевести его на Java, чем мне, а выполнять перевод наоборот, когда мне нужно скопировать кусок кода Java.
Он немного отличается от стандартного TimePicker тем, что его верхняя и нижняя границы не являются непрерывными, но это недостаток, который некоторые люди сочтут незначительным.
Я мог бы лучше справиться с задачей упростить настройку пользовательского интервала минут и не сделать жестким кодирование значений интервалов в реализации, но я считаю, что вы можете отшлифовать это решение, если хотите очень быстро!
HourPickerMapper.cs
public class HourPickerMapper
{
public HourPickerMapper() { }
public int MapValue(int hour)
{
return hour;
}
public int MapNumber(int number)
{
return number;
}
public void InitNumberPicker(NumberPicker numberPicker)
{
int[] numbers = new int[24];
for (var i = 0; i < numbers.Length; i++)
{
numbers[i] = i;
}
var displayed = numbers.Select(_ => $"{_:00}").ToArray();
numberPicker.SetDisplayedValues(displayed);
numberPicker.MinValue = 0;
numberPicker.MaxValue = displayed.Length - 1;
}
}
MinutePickerMapper.cs
public class MinutePickerMapper
{
public MinutePickerMapper() { }
public int MapValue(int value)
{
return (int)Math.Floor(value / 10.0);
}
public int MapNumber(int number)
{
return number * 10;
}
public void InitNumberPicker(NumberPicker numberPicker)
{
int[] numbers = new int[6];
for (var i = 0; i < numbers.Length; i++)
{
numbers[i] = i * 10;
}
var displayed = numbers.Select(_ => _.ToString()).ToArray();
numberPicker.SetDisplayedValues(displayed);
numberPicker.MinValue = 0;
numberPicker.MaxValue = displayed.Length - 1;
}
}
А вот пример использования: DialogFragment
public class CustomDateTimePickerDialogFragment : Android.Support.V4.App.DialogFragment
{
private DateTime _dt;
private NumberPicker _datePicker, _hourPicker, _minutePicker;
private DatePickerMapper _datePickerMapper;
private HourPickerMapper _hourPickerMapper;
private MinutePickerMapper _minutePickerMapper;
public event EventHandler<DateTimeSetEventArgs> DateTimeSetEvent;
public CustomDateTimePickerDialogFragment()
{
_dt = DateTime.Now + new TimeSpan(24, 0, 0); // now + 1 day
}
public CustomDateTimePickerDialogFragment(DateTime dt)
{
_dt = dt;
if (dt == null)
{
_dt = DateTime.Now + new TimeSpan(24, 0, 0); // now + 1 day
}
}
public override Dialog OnCreateDialog(Bundle savedInstanceState)
{
AlertDialog.Builder builder = new AlertDialog.Builder(Context);
builder.SetNeutralButton(Resource.String.dialog_datetime_now, (sender, e) =>
{
var eventArgs = new DateTimeSetEventArgs();
DateTimeSetEvent.Invoke(this, eventArgs);
});
builder.SetPositiveButton(Resource.String.dialog_ok, (sender, e) =>
{
var hour = _hourPickerMapper.MapNumber(_hourPicker.Value);
var minute = _minutePickerMapper.MapNumber(_minutePicker.Value);
var date = _datePickerMapper.MapNumber(_datePicker.Value);
var eventArgs = new DateTimeSetEventArgs(new DateTime(date.Year, date.Month, date.Day, hour, minute, 0));
DateTimeSetEvent.Invoke(this, eventArgs);
Dismiss();
});
var dialog = builder.Create();
dialog.SetView(createDateTimeView(dialog.LayoutInflater));
_datePicker.Value = _datePickerMapper.MapValue(_dt);
_hourPicker.Value = _hourPickerMapper.MapValue(_dt.Hour);
_minutePicker.Value = _minutePickerMapper.MapValue(_dt.Minute);
return dialog;
}
private View createDateTimeView(LayoutInflater inflater)
{
View view = inflater.Inflate(Resource.Layout.dialog_custom_datetime_picker, null);
_datePicker = view.FindViewById<NumberPicker>(Resource.Id.datePicker);
_datePickerMapper = new DatePickerMapper(DateTime.Now, 10);
_datePickerMapper.InitNumberPicker(_datePicker);
var now = DateTime.Now;
_datePicker.Value = _datePickerMapper.MapValue(now);
_minutePicker = view.FindViewById<NumberPicker>(Resource.Id.minutePicker);
_minutePickerMapper = new MinutePickerMapper();
_minutePickerMapper.InitNumberPicker(_minutePicker);
_minutePicker.Value = _minutePickerMapper.MapValue(now.Minute);
_hourPicker = view.FindViewById<NumberPicker>(Resource.Id.hourPicker);
_hourPickerMapper = new HourPickerMapper();
_hourPickerMapper.InitNumberPicker(_hourPicker);
_hourPicker.Value = _hourPickerMapper.MapValue(now.Hour);
return view;
}
public class DateTimeSetEventArgs : EventArgs
{
public DateTimeSetEventArgs(DateTime dt)
{
IsNow = false;
DT = dt;
}
public DateTimeSetEventArgs()
{
IsNow = true;
}
public DateTime DT { get; }
public bool IsNow { get; }
}
}
dialog_custom_datetime_picker.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/dialog_padding"
>
<!-- Layout for the DatePicker -->
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
>
<NumberPicker
android:id="@+id/datePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" "
/>
<NumberPicker
android:id="@+id/hourPicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=":"
/>
<NumberPicker
android:id="@+id/minutePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>