53

Clearable Time Picker in Xamarin Forms

 2 years ago
source link: https://xamgirl.com/clearable-time-picker-in-xamarin-forms/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Clearable Time Picker in Xamarin Forms

May 5, 2021No Comments

A time ago I did an article on how to create a Clearable Date Picker, recently someone asked me to do the same but with a Time Picker. So why not?

In this article, I’m going to show you how to create a Time Picker that can be cleared and set to a null date.

Let’s start

1. In your XF Project create a NullableTimePicker class that extends from TimePicker

This class will have two main bindable properties:

  • NullableTime: To bind our nullable TimeSpan.
  • PlaceHolder: The value that will be visible when the picker is null, by default it will be “/ . /”.

The code inside is quite simple, a method to clear the NullableTime property and another method to update the time format depending on whether the value is null or not.

public class NullableTimePicker : TimePicker { public NullableTimePicker() { Format = _originalFormat = "hh:mm tt"; }

public static readonly BindableProperty PlaceHolderProperty = BindableProperty.Create(nameof(PlaceHolder), typeof(string), typeof(NullableTimePicker), "/ . /"); public static readonly BindableProperty NullableTimeProperty = BindableProperty.Create(nameof(NullableTime), typeof(TimeSpan?), typeof(NullableTimePicker), null, defaultBindingMode: BindingMode.TwoWay);

public string PlaceHolder { get => (string)GetValue(PlaceHolderProperty); set => SetValue(PlaceHolderProperty, value); }

public TimeSpan? NullableTime { get => (TimeSpan?)GetValue(NullableTimeProperty); set { SetValue(NullableTimeProperty, value); UpdateTimeFormat(); } }

public string _originalFormat { get; private set; } = null;

public void ClearTime() { NullableTime = null; UpdateTimeFormat(); }

protected override void OnBindingContextChanged() { base.OnBindingContextChanged(); if (BindingContext != null) { _originalFormat = Format; UpdateTimeFormat(); } }

protected override void OnPropertyChanged(string propertyName = null) { base.OnPropertyChanged(propertyName);

if (propertyName == TimeProperty.PropertyName || (propertyName == IsFocusedProperty.PropertyName && !IsFocused)) { NullableTime = Time; UpdateTimeFormat(); } }

private void UpdateTimeFormat() { if (NullableTime != null) { Format = _originalFormat; } else { Format = PlaceHolder; } } }

2. In your iOS project create a NullableTimePickerRenderer

Use this renderer to add a Clear button to the iOS TimePicker.

[assembly: ExportRenderer(typeof(NullableTimePicker.Controls.NullableTimePicker), typeof(NullableTimePickerRenderer))] namespace NullableTimePicker.iOS { public class NullableTimePickerRenderer : TimePickerRenderer { protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e) { base.OnElementChanged(e);

if (e.NewElement != null && this.Control != null) { AddClearButton(); } }

private void AddClearButton() { var originalToolbar = this.Control.InputAccessoryView as UIToolbar;

if (originalToolbar != null && originalToolbar.Items.Length <= 2) { var clearButton = new UIBarButtonItem("Clear", UIBarButtonItemStyle.Plain, ((sender, ev) => { Element.Unfocus(); Element.Time = TimeSpan.Zero; (this.Element as NullableTimePicker.Controls.NullableTimePicker).ClearTime(); }));

var newItems = new List<UIBarButtonItem>(); foreach (var item in originalToolbar.Items) { newItems.Add(item); }

newItems.Insert(0, clearButton);

originalToolbar.Items = newItems.ToArray(); } } } }

3. In your Android project create a NullableTimePickerRenderer

Use this renderer to create a TimePicker view that contains a Clear button.

[assembly: ExportRenderer(typeof(NullableTimePicker.Controls.NullableTimePicker), typeof(NullableTimePickerRenderer))] namespace NullableTimePicker.Droid { public class NullableTimePickerRenderer : ViewRenderer<Controls.NullableTimePicker, EditText> { TimePickerDialog _dialog;

public NullableTimePickerRenderer(Context context) : base(context){ }

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

SetNativeControl(new Android.Widget.EditText(Context));

if (Control == null || e.NewElement == null) return; Control.Click += OnPickerClick; Control.KeyListener = null; Control.FocusChange += OnPickerFocusChange; Control.Enabled = Element.IsEnabled; Control.Text = !Element.NullableTime.HasValue ? Element.PlaceHolder : DateTime.Today.Add(Element.NullableTime.Value).ToString(Element.Format); }

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == Xamarin.Forms.TimePicker.TimeProperty.PropertyName || e.PropertyName == Xamarin.Forms.TimePicker.FormatProperty.PropertyName) { if (Element.Format == Element.PlaceHolder) { this.Control.Text = Element.PlaceHolder; return; } } if (e.PropertyName == NullableTimePicker.Controls.NullableTimePicker.NullableTimeProperty.PropertyName && Control != null && Element != null) { Control.Text = !Element.NullableTime.HasValue ? Element.PlaceHolder : DateTime.Today.Add(Element.NullableTime.Value).ToString(Element.Format); }

base.OnElementPropertyChanged(sender, e); }

void OnPickerFocusChange(object sender, Android.Views.View.FocusChangeEventArgs e) { if (e.HasFocus) { ShowTimePicker(); } }

protected override void Dispose(bool disposing) { if (Control != null) { Control.Click -= OnPickerClick; Control.FocusChange -= OnPickerFocusChange;

if (_dialog != null) { _dialog.Hide(); _dialog.Dispose(); _dialog = null; } }

base.Dispose(disposing); }

void OnPickerClick(object sender, EventArgs e) { ShowTimePicker(); }

void ShowTimePicker() { CreateTimePickerDialog(Element.NullableTime.HasValue? Element.NullableTime.Value.Hours : 0, Element.NullableTime.HasValue ? Element.NullableTime.Value.Minutes : 0, false); _dialog.Show(); }

void CreateTimePickerDialog(int hours, int minutes, bool is24HourView) { _dialog = new TimePickerDialog(Context, (o, e) => { SetTime(new TimeSpan(e.HourOfDay, e.Minute, 0)); ((IElementController)Element).SetValueFromRenderer(VisualElement.IsFocusedProperty, false); Control.ClearFocus();

_dialog = null; }, hours, minutes, is24HourView);

_dialog.SetButton2("Clear", (sender, e) => { this.Element.ClearTime(); Control.Text = this.Element.Format; }); }

void SetTime(TimeSpan time) { Element.Format = this.Element._originalFormat; Control.Text = DateTime.Today.Add(time).ToString(Element.Format); Element.Time = time; } } }

4. Use the control

To use it just add the control in your view and instead of binding the ViewModel property to the Time property, bind it to the NullableTime property instead.

public TimeSpan? MyTime { get; set; }

<?xml version="1.0" encoding="utf-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="NullableTimePicker.MainPage" xmlns:local="clr-namespace:NullableTimePicker.Controls"> <StackLayout VerticalOptions="CenterAndExpand"> <local:NullableTimePicker NullableTime="{Binding MyTime}"/> </StackLayout> </ContentPage>

Result

  • ezgif.com-gif-maker-18.gif?resize=507%2C1024&ssl=1
  • ezgif.com-gif-maker-19.gif?resize=491%2C1024&ssl=1

You can check the full sample source code here.

Happy coding! 

Like this:

Loading...

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Comment

Name *

Email *

Website

Notify me of follow-up comments by email.

Notify me of new posts by email.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK