Xamarin.Forms Control deslizante

Download SampleDescargar el ejemplo

Use un control deslizante para seleccionar entre un intervalo de valores continuos.

Xamarin.FormsSlider es una barra horizontal que el usuario puede manipular para seleccionar un double valor de un intervalo continuo.

Slider Define tres propiedades de tipo double:

  • Minimum es el valor mínimo del rango, con un valor predeterminado de 0.
  • Maximum es el máximo del intervalo, con un valor predeterminado de 1.
  • Value es el valor del control deslizante, que puede oscilar entre Minimum y Maximum y tiene un valor predeterminado de 0.

Los objetos respaldan BindableProperty las tres propiedades. La Value propiedad tiene un modo de enlace predeterminado de BindingMode.TwoWay, lo que significa que es adecuado como origen de enlace en una aplicación que usa la arquitectura Model-View-ViewModel (MVVM).

Advertencia

Internamente, Slider garantiza que Maximum sea menor que Minimum. Si Minimum o Maximum se establecen alguna vez para que Maximum no sea menor que Minimum, se genera una excepción. Consulte la sección Precauciones a continuación para obtener más información sobre cómo establecer las Minimum propiedades y Maximum .

El Slider reprime la propiedad Value para que esté entre Minimum y Maximum, ambos inclusive. Si la propiedad Minimum se establece en un valor mayor que la propiedad Value, Slider establece la propiedad Value en Minimum. Del mismo modo, si Maximum se establece en un valor menor que Value, Slider establece la propiedad Value en Maximum.

Slider define un ValueChanged evento que se desencadena cuando cambia Value , ya sea a través de la manipulación del usuario de Slider o cuando el programa establece la Value propiedad directamente. También se desencadena un ValueChanged evento cuando la Value propiedad se coercite como se describe en el párrafo anterior.

El ValueChangedEventArgs objeto que acompaña al ValueChanged evento tiene dos propiedades, de tipo double: OldValue y NewValue. En el momento en que se desencadena el evento, el valor de es el mismo que NewValue la Value propiedad del Slider objeto .

Slider también define y DragStartedDragCompleted eventos, que se activan al principio y al final de la acción de arrastrar. A diferencia del ValueChanged evento , los DragStarted eventos y DragCompleted solo se desencadenan a través de la Slidermanipulación del usuario de . Cuando se desencadena el evento DragStarted, se ejecuta DragStartedCommand de tipo ICommand. Del mismo modo, cuando se desencadena el evento DragCompleted, se ejecuta DragCompletedCommand de tipo ICommand.

Advertencia

No uses opciones de diseño horizontal sin restricciones de Center, Start o End con Slider. Tanto en Android como en UWP, el Slider se contrae a una barra de longitud cero y, en iOS, la barra es muy corta. Mantén la configuración predeterminada HorizontalOptions de Fill y no uses un ancho de Auto al colocar Slider en un diseño Grid.

También Slider define varias propiedades que afectan a su apariencia:

Nota:

Las propiedades ThumbColor y ThumbImageSource se excluyen mutuamente. Si se establecen ambas propiedades, la propiedad ThumbImageSource tendrá precedencia.

Código y marcado básicos del control deslizante

El ejemplo SliderDemos comienza con tres páginas que son funcionalmente idénticas, pero se implementan de maneras diferentes. La primera página usa solo código de C#, el segundo usa XAML con un controlador de eventos en el código y el tercero puede evitar el controlador de eventos mediante el enlace de datos en el archivo XAML.

Creación de un control deslizante en el código

La página Código de control deslizante básico del ejemplo SliderDemos muestra mostrar para crear un Slider objeto y dos Label objetos en el código:

public class BasicSliderCodePage : ContentPage
{
    public BasicSliderCodePage()
    {
        Label rotationLabel = new Label
        {
            Text = "ROTATING TEXT",
            FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };

        Label displayLabel = new Label
        {
            Text = "(uninitialized)",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };

        Slider slider = new Slider
        {
            Maximum = 360
        };
        slider.ValueChanged += (sender, args) =>
        {
            rotationLabel.Rotation = slider.Value;
            displayLabel.Text = String.Format("The Slider value is {0}", args.NewValue);
        };

        Title = "Basic Slider Code";
        Padding = new Thickness(10, 0);
        Content = new StackLayout
        {
            Children =
            {
                rotationLabel,
                slider,
                displayLabel
            }
        };
    }
}

Slider se inicializa para tener una Maximum propiedad de 360. El ValueChanged controlador de Slider utiliza la Value propiedad del slider objeto para establecer la Rotation propiedad del primero Label y usa el String.Format método con la NewValue propiedad de los argumentos de evento para establecer la Text propiedad del segundo Label. Estos dos enfoques para obtener el valor actual de Slider son intercambiables.

Este es el programa que se ejecuta en dispositivos iOS y Android:

Basic Slider Code

El segundo Label muestra el texto "(sin inicializar)" hasta Slider que se manipula , lo que hace que se desencadene el primer ValueChanged evento. Observe que el número de posiciones decimales que se muestran es diferente para cada plataforma. Estas diferencias están relacionadas con las implementaciones de la plataforma de Slider y se describen más adelante en este artículo en la sección Diferencias de implementación de la plataforma.

Crear un control deslizante en XAML

La página XAML de control deslizante básico es funcionalmente la misma que el código deslizante básico, pero se implementa principalmente en XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SliderDemos.BasicSliderXamlPage"
             Title="Basic Slider XAML"
             Padding="10, 0">
    <StackLayout>
        <Label x:Name="rotatingLabel"
               Text="ROTATING TEXT"
               FontSize="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Slider Maximum="360"
                ValueChanged="OnSliderValueChanged" />

        <Label x:Name="displayLabel"
               Text="(uninitialized)"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

El archivo de código subyacente contiene el controlador para el evento ValueChanged:

public partial class BasicSliderXamlPage : ContentPage
{
    public BasicSliderXamlPage()
    {
        InitializeComponent();
    }

    void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
    {
        double value = args.NewValue;
        rotatingLabel.Rotation = value;
        displayLabel.Text = String.Format("The Slider value is {0}", value);
    }
}

También es posible que el controlador de eventos obtenga el Slider que desencadena el evento a través del argumento sender. La propiedad Value contiene el valor actual:

double value = ((Slider)sender).Value;

Si el objeto Slider recibió un nombre en el archivo XAML con un atributo x:Name (por ejemplo, "slider"), el controlador de eventos podría hacer referencia directamente a ese objeto:

double value = slider.Value;

Enlace de datos al control deslizante

En la página Enlaces deslizantes básicos se muestra cómo escribir un programa casi equivalente que elimina el controlador de eventos mediante el Value enlace de datos:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SliderDemos.BasicSliderBindingsPage"
             Title="Basic Slider Bindings"
             Padding="10, 0">
    <StackLayout>
        <Label Text="ROTATING TEXT"
               Rotation="{Binding Source={x:Reference slider},
                                  Path=Value}"
               FontSize="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Slider x:Name="slider"
                Maximum="360" />

        <Label x:Name="displayLabel"
               Text="{Binding Source={x:Reference slider},
                              Path=Value,
                              StringFormat='The Slider value is {0:F0}'}"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

La Rotation propiedad del primero Label está enlazada a la Value propiedad de Slider, tal como es la Text propiedad del segundo Label con una StringFormat especificación . La página Enlaces deslizantes básicos funciona de forma ligeramente diferente de las dos páginas anteriores: cuando aparece la página por primera vez, la segunda Label muestra la cadena de texto con el valor . Esta es una ventaja de usar el enlace de datos. Para mostrar texto sin enlace de datos, tendrías que inicializar específicamente la propiedad Text de Label o simular una activación del evento ValueChanged mediante una llamada al controlador de eventos desde el constructor de clase.

Precauciones

El valor de la propiedad Minimum debe ser siempre inferior que el valor de la propiedad Maximum. El siguiente fragmento de código hace que Slider genere una excepción:

// Throws an exception!
Slider slider = new Slider
{
    Minimum = 10,
    Maximum = 20
};

El compilador de C# genera código que establece estas dos propiedades en secuencia y, cuando la propiedad Minimum se establece en 10, es mayor que el valor predeterminado Maximum de 1. Puedes evitar la excepción en este caso estableciendo primero la propiedad Maximum:

Slider slider = new Slider
{
    Maximum = 20,
    Minimum = 10
};

Establecer Maximum en 20 no es un problema porque es mayor que el valor predeterminado Minimum de 0. Cuando Minimum se establece, el valor es menor que el valor Maximum de 20.

El mismo problema existe en XAML. Establece las propiedades en un orden que garantice que Maximum siempre sea mayor que Minimum:

<Slider Maximum="20"
        Minimum="10" ... />

Luego, puedes establecer los valores Minimum y Maximum en números negativos, pero solo en un orden donde Minimum siempre sea menor que Maximum:

<Slider Minimum="-20"
        Maximum="-10" ... />

La propiedad Value siempre es mayor o igual que el valor Minimum y menor o igual que Maximum. Si Value se establece en un valor fuera de ese intervalo, el valor se reprimirá para que se encuentre dentro del intervalo, pero no se genera ninguna excepción. Por ejemplo, este código no generará una excepción:

Slider slider = new Slider
{
    Value = 10
};

En su lugar, la propiedad Value se convierte en el valor Maximum de 1.

Este es un fragmento de código que se muestra anteriormente:

Slider slider = new Slider
{
    Maximum = 20,
    Minimum = 10
};

Cuando Minimum se establece en 10, Value también se establece en 10.

Si un ValueChanged controlador de eventos se ha adjuntado en el momento en que la Value propiedad está coercedida a algo distinto de su valor predeterminado de 0, se desencadena un ValueChanged evento. Este es un fragmento de código XAML:

<Slider ValueChanged="OnSliderValueChanged"
        Maximum="20"
        Minimum="10" />

Cuando Minimum se establece en 10, Value también se establece en 10 y el ValueChanged evento se desencadena. Esto puede ocurrir antes de que se haya construido el resto de la página y el controlador podría intentar hacer referencia a otros elementos de la página que aún no se han creado. Es posible que desees agregar código al controlador ValueChanged que comprueba si hay valores null de otros elementos en la página. O bien, puedes establecer el controlador de eventos ValueChanged después de inicializar los valores Slider.

Diferencias de implementación de la plataforma

Las capturas de pantalla mostradas anteriormente muestran el valor de Slider con un número diferente de puntos decimales. Esto se relaciona con cómo se implementa en Slider las plataformas Android y UWP.

Implementación de Android

La implementación de Android de Slider se basa en Android SeekBar y siempre establece la Max propiedad en 1000. Esto significa que en Slider Android solo tiene 1001 valores discretos. Si establece que Slider tiene un Minimum de 0 y un Maximum de 5000, a Slider medida que se manipula, la Value propiedad tiene valores de 0, 5, 10, 15, etc.

Implementación de UWP

La implementación de UWP de Slider se basa en el control de UWP Slider . La StepFrequency propiedad de UWP Slider se establece en la diferencia de las Maximum propiedades y Minimum divididas por 10, pero no mayores que 1.

Por ejemplo, para el intervalo predeterminado de 0 a 1, la StepFrequency propiedad se establece en 0,1. Slider A medida que se manipula, la Value propiedad está restringida a 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 y 1.0. (Esto es evidente en la última página del Ejemplo SliderDemos ). Cuando la diferencia entre las Maximum propiedades y Minimum es 10 o superior, StepFrequency se establece en 1 y la Value propiedad tiene valores enteros.

La solución StepSlider

Se analiza un elemento más versátil StepSlider en el capítulo 27. Representadores personalizados del libro Creación de aplicaciones móviles con Xamarin.Forms. StepSlider es similar a Slider pero agrega una Steps propiedad para especificar el número de valores entre Minimum y Maximum.

Controles deslizantes para la selección de colores

Las dos páginas finales del ejemplo SliderDemos usan tres Slider instancias para la selección de colores. La primera página controla todas las interacciones del archivo de código subyacente, mientras que la segunda página muestra cómo usar el enlace de datos con un ViewModel.

Control de controles deslizantes en el archivo de código subyacente

La página Controles deslizantes de color RGB crea una instancia BoxView de para mostrar un color, tres Slider instancias para seleccionar los componentes rojo, verde y azul del color, y tres Label elementos para mostrar esos valores de color:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SliderDemos.RgbColorSlidersPage"
             Title="RGB Color Sliders">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Slider">
                <Setter Property="Maximum" Value="255" />
            </Style>

            <Style TargetType="Label">
                <Setter Property="HorizontalTextAlignment" Value="Center" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout Margin="10">
        <BoxView x:Name="boxView"
                 Color="Black"
                 VerticalOptions="FillAndExpand" />

        <Slider x:Name="redSlider"
                ValueChanged="OnSliderValueChanged" />

        <Label x:Name="redLabel" />

        <Slider x:Name="greenSlider"
                ValueChanged="OnSliderValueChanged" />

        <Label x:Name="greenLabel" />

        <Slider x:Name="blueSlider"
                ValueChanged="OnSliderValueChanged" />

        <Label x:Name="blueLabel" />
    </StackLayout>
</ContentPage>

Un Style proporciona a los tres Slider elementos un intervalo de 0 a 255. Los Slider elementos comparten el mismo ValueChanged controlador, que se implementa en el archivo de código subyacente:

public partial class RgbColorSlidersPage : ContentPage
{
    public RgbColorSlidersPage()
    {
        InitializeComponent();
    }

    void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
    {
        if (sender == redSlider)
        {
            redLabel.Text = String.Format("Red = {0:X2}", (int)args.NewValue);
        }
        else if (sender == greenSlider)
        {
            greenLabel.Text = String.Format("Green = {0:X2}", (int)args.NewValue);
        }
        else if (sender == blueSlider)
        {
            blueLabel.Text = String.Format("Blue = {0:X2}", (int)args.NewValue);
        }

        boxView.Color = Color.FromRgb((int)redSlider.Value,
                                      (int)greenSlider.Value,
                                      (int)blueSlider.Value);
    }
}

La primera sección establece la Text propiedad de una de las Label instancias en una cadena de texto corta que indica el valor de Slider en hexadecimal. A continuación, se accede a las tres Slider instancias para crear un Color valor a partir de los componentes RGB:

RGB Color Sliders

Enlazar el control deslizante a un ViewModel

En la página Controles deslizantes de color HSL se muestra cómo usar un ViewModel para realizar los cálculos utilizados para crear un Color valor a partir de valores de tono, saturación y luminosidad. Al igual que todos los ViewModels, la HSLColorViewModel clase implementa la INotifyPropertyChanged interfaz y desencadena un PropertyChanged evento cada vez que una de las propiedades cambia:

public class HslColorViewModel : INotifyPropertyChanged
{
    Color color;

    public event PropertyChangedEventHandler PropertyChanged;

    public double Hue
    {
        set
        {
            if (color.Hue != value)
            {
                Color = Color.FromHsla(value, color.Saturation, color.Luminosity);
            }
        }
        get
        {
            return color.Hue;
        }
    }

    public double Saturation
    {
        set
        {
            if (color.Saturation != value)
            {
                Color = Color.FromHsla(color.Hue, value, color.Luminosity);
            }
        }
        get
        {
            return color.Saturation;
        }
    }

    public double Luminosity
    {
        set
        {
            if (color.Luminosity != value)
            {
                Color = Color.FromHsla(color.Hue, color.Saturation, value);
            }
        }
        get
        {
            return color.Luminosity;
        }
    }

    public Color Color
    {
        set
        {
            if (color != value)
            {
                color = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Hue"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Saturation"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Luminosity"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));
            }
        }
        get
        {
            return color;
        }
    }
}

ViewModels y la INotifyPropertyChanged interfaz se describen en el artículo Enlace de datos.

El archivo HslColorSlidersPage.xaml crea una instancia de HslColorViewModel y lo establece en la propiedad de BindingContext la página. Esto permite que todos los elementos del archivo XAML se enlacen a las propiedades de ViewModel:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SliderDemos"
             x:Class="SliderDemos.HslColorSlidersPage"
             Title="HSL Color Sliders">

    <ContentPage.BindingContext>
        <local:HslColorViewModel Color="Chocolate" />
    </ContentPage.BindingContext>

    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Label">
                <Setter Property="HorizontalTextAlignment" Value="Center" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout Margin="10">
        <BoxView Color="{Binding Color}"
                 VerticalOptions="FillAndExpand" />

        <Slider Value="{Binding Hue}" />
        <Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />

        <Slider Value="{Binding Saturation}" />
        <Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />

        <Slider Value="{Binding Luminosity}" />
        <Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
    </StackLayout>
</ContentPage>

A medida que se manipulan los Slider elementos , los BoxView elementos y Label se actualizan desde viewModel:

HSL Color Sliders

El StringFormat componente de la Binding extensión de marcado se establece para un formato de "F2" para mostrar dos posiciones decimales. (El formato de cadena en los enlaces de datos se describe en el artículo Formato de cadena). Sin embargo, la versión de UWP del programa se limita a los valores de 0, 0.1, 0.2, ... 0.9 y 1.0. Este es un resultado directo de la implementación de la UWP Slider como se ha descrito anteriormente en la sección Diferencias de implementación de la plataforma.