You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现间隔为30分钟的Xamarin Forms Timepicker?

实现30分钟间隔的Xamarin Forms TimePicker

嘿,很高兴你已经搞定了把TimePicker改成Spinner模式,还有15分钟间隔的版本!要改成30分钟间隔其实非常简单,咱们基于你现有的代码调整就行,我给你一步步拆解:

第一步:自定义带间隔属性的TimePicker控件

先创建一个继承自TimePicker的自定义控件,添加一个Interval属性,这样不仅能实现30分钟间隔,以后要改其他间隔也更灵活:

using Xamarin.Forms;

namespace YourAppNamespace.Controls
{
    public class CustomTimePicker : TimePicker
    {
        public static readonly BindableProperty IntervalProperty =
            BindableProperty.Create(
                nameof(Interval), 
                typeof(int), 
                typeof(CustomTimePicker), 
                defaultValue: 30, // 默认30分钟间隔
                propertyChanged: OnIntervalChanged);

        public int Interval
        {
            get => (int)GetValue(IntervalProperty);
            set => SetValue(IntervalProperty, value);
        }

        private static void OnIntervalChanged(BindableObject bindable, object oldValue, object newValue)
        {
            // 可选:添加间隔值的合法性校验,比如必须是60的约数
            if (newValue is int interval && (interval <= 0 || 60 % interval != 0))
            {
                throw new ArgumentException("Interval must be a positive divisor of 60");
            }
        }
    }
}

第二步:Android端自定义渲染器

Android端需要手动修改Spinner的分钟选项列表,你之前实现15分钟间隔时应该已经有类似逻辑,现在把间隔改成30就行:

using Android.Content;
using Android.Widget;
using YourAppNamespace.Controls;
using YourAppNamespace.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(CustomTimePicker), typeof(CustomTimePickerRenderer))]
namespace YourAppNamespace.Droid.Renderers
{
    public class CustomTimePickerRenderer : TimePickerRenderer
    {
        public CustomTimePickerRenderer(Context context) : base(context)
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
        {
            base.OnElementChanged(e);

            if (Control == null || !(Element is CustomTimePicker customPicker)) return;

            // 确保保持Spinner模式(你之前已经实现这部分,这里再确认下)
            Control.SetIs24HourView(Java.Lang.Boolean.True);
            var androidTimePicker = (Android.Widget.TimePicker)Control;

            // 针对不同Android版本设置Spinner模式(你之前的代码应该已经覆盖了)
            if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.M)
            {
                androidTimePicker.SetInputType(Android.Text.InputTypes.Null);
            }
            else
            {
                try
                {
                    var delegateField = androidTimePicker.Class.GetDeclaredField("mTimePickerDelegate");
                    delegateField.Accessible = true;
                    var spinnerDelegateClass = Java.Lang.Class.ForName("android.widget.TimePickerSpinnerDelegate");
                    if (delegateField.Get(androidTimePicker).Class != spinnerDelegateClass)
                    {
                        var constructor = spinnerDelegateClass.GetConstructor(typeof(Android.Widget.TimePicker), typeof(Context));
                        delegateField.Set(androidTimePicker, constructor.NewInstance(androidTimePicker, Context));
                        androidTimePicker.CurrentHour = Java.Lang.Integer.ValueOf(DateTime.Now.Hour);
                        androidTimePicker.CurrentMinute = Java.Lang.Integer.ValueOf(DateTime.Now.Minute);
                    }
                }
                catch (Exception ex)
                {
                    // 可选:记录日志
                }
            }

            // 核心:设置30分钟间隔的分钟选项
            var minutePicker = androidTimePicker.FindViewById<NumberPicker>(Resources.GetIdentifier("minute", "id", "android"));
            if (minutePicker == null) return;

            int interval = customPicker.Interval;
            var minuteOptions = new List<int>();
            // 生成0、30两个选项(30分钟间隔)
            for (int i = 0; i < 60; i += interval)
            {
                minuteOptions.Add(i);
            }

            minutePicker.MinValue = 0;
            minutePicker.MaxValue = minuteOptions.Count - 1;
            minutePicker.DisplayedValues = minuteOptions.Select(m => m.ToString("D2")).ToArray();

            // 初始化选中最接近当前时间的选项
            int currentMinute = customPicker.Time.Minute;
            int closestMinute = minuteOptions.OrderBy(m => Math.Abs(m - currentMinute)).First();
            minutePicker.Value = minuteOptions.IndexOf(closestMinute);
        }
    }
}

第三步:iOS端自定义渲染器

iOS端更简单,直接设置UIDatePicker的MinuteInterval属性就行:

using YourAppNamespace.Controls;
using YourAppNamespace.iOS.Renderers;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(CustomTimePicker), typeof(CustomTimePickerRenderer))]
namespace YourAppNamespace.iOS.Renderers
{
    public class CustomTimePickerRenderer : TimePickerRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
        {
            base.OnElementChanged(e);

            if (Control == null || !(Element is CustomTimePicker customPicker)) return;

            var datePicker = (UIDatePicker)Control.InputView;
            datePicker.DatePickerMode = UIDatePickerMode.Time;
            datePicker.MinuteInterval = customPicker.Interval; // 直接设置为30
        }
    }
}

第四步:在XAML中使用

最后在你的XAML页面里引用这个自定义控件,设置Interval="30"即可:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:YourAppNamespace.Controls"
             x:Class="YourAppNamespace.Views.YourPage">

    <StackLayout>
        <!-- 30分钟间隔的TimePicker -->
        <controls:CustomTimePicker Interval="30" />
    </StackLayout>
</ContentPage>

这样就搞定啦!本质上就是把15分钟间隔的选项列表从4个(0、15、30、45)改成2个(0、30),其他逻辑和你之前实现的15分钟版本几乎一致。

内容的提问来源于stack exchange,提问作者RMSPereira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:25:14