Twitter Facebook RSS Feed

sábado, 18 de julio de 2020 a las 23:51hs por Gustavo Cantero (The Wolf)

Hace unas semanas escribí el artículo «Placeholder en DatePicker de Xamarin Forms con Visual Material en iOS y Android» donde, obviamente, explicaba como crear un renderer para agregar un Placeholder al DatePicker, ya que los controles propios de Xamarin Forms no trae esta propiedad.
En este artículo explico lo mismo pero para el TimePicker, que tiene el mismo problema.
Por suerte los controles nativos de Android e iOS tienen esta propiedad, por lo cual, sólo tenemos que crear un control que herede del TimePicker original y crear un renderer para cada plataforma.

Empezamos creando el control que herede del TimePicker de Xamarin Forms, para agregar la nueva propiedad:

using Xamarin.Forms;

namespace MiProyecto.Controls
{
    public class MyTimePicker : Xamarin.Forms.TimePicker
    {
        public static readonly BindableProperty EnterTextProperty =
            BindableProperty.Create(propertyName: nameof(Placeholder), returnType: typeof(string), declaringType: typeof(TimePicker), defaultValue: default(string));

        public string Placeholder { get; set; }
    }
}

Este control lo podemos utilizar de la siguiente forma:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:controls="clr-namespace:MiProyecto.Controls"
             mc:Ignorable="d">
    <controls:MyTimePicker Placeholder="Hora de inicio"
                           Visual="Material"
                           VerticalOptions="Center" />
</ContentPage>

Ahora deberemos crear el Renderer en cada plataforma. Nótese que nosotros utilizamos el Visual Material, con lo cual, deberemos heredar de la clase MaterialTimePickerRenderer.

Android

Primero crearemos el renderer para Android, cuyo control nativo, el TextInputLayout, tiene la propiedad Hint para que hace lo mismo que el Placeholder.
Este renderer tendremos que crearlo en el proyecto de Android, para poder tener acceso a los controles nativos.

using Android.App;
using Android.Content;
using Android.OS;
using Android.Text.Format;
using Xamarin.Forms;
using Xamarin.Forms.Material.Android;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(MyTimePicker), typeof(MiProyecto.Droid.Renderer.TimePickerRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
namespace MiProyecto.Droid.Renderer
{
    class TimePickerRenderer : MaterialTimePickerRenderer
    {
        public TimePickerRenderer(Context context) : base(context) { }

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

            //Placeholder
            if (Element is Controls.TimePicker picker && !string.IsNullOrWhiteSpace(picker.Placeholder))
            {
                Control.HintEnabled = true;
                Control.Hint = picker.Placeholder;
            }
        }

        bool Is24HourView
        {
            get => (DateFormat.Is24HourFormat(Context) && Element.Format == (string)TimePicker.FormatProperty.DefaultValue)
                   || Element.Format == "HH:mm";
        }

        protected override TimePickerDialog CreateTimePickerDialog(int hours, int minutes)
        {
            var dialog = new TimePickerDialog(Context, Resource.Style.AppCompatDialogStyle, this, hours, minutes, Is24HourView);
            if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
                dialog.CancelEvent += (s, e) => Element.Unfocus();

            return dialog;
        }
    }
}

iOS

Ahora tenemos que hacer lo mismo, pero para iOS. En este caso, el control también debe heredar de la interfaz IMaterialEntryRenderer, que tiene las propiedades para mostrar el placeholder.
Al igual que con Android, este renderer tendremos que crearlo en el proyecto de iOS.

using Xamarin.Forms;
using Xamarin.Forms.Material.iOS;

[assembly: ExportRenderer(typeof(MyTimePicker), typeof(MiProyecto.iOS.Renderer.TimePickerRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
namespace MiProyecto.iOS.Renderer
{
    class TimePickerRenderer : MaterialTimePickerRenderer, IMaterialEntryRenderer
    {
        public TimePickerRenderer() : base() { }

        string IMaterialEntryRenderer.Placeholder
        {
            get
            {
                if (Element is MyTimePicker picker && !string.IsNullOrWhiteSpace(picker.Placeholder))
                    return picker.Placeholder;
                return string.Empty;
            }
        }
    }
}

Con estos renderers, veremos el TimePicker en iOS 13.5 y Android 10.0 como se muestra a continuación.

Espero les sirva este artículo.
¡Suerte!

0 comentarios »

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.