Xamarin.Forms Slider

Download Sample Baixe o exemplo

Use um controle deslizante para selecionar a partir de um intervalo de valores contínuos.

O Xamarin.FormsSlider é uma barra horizontal que pode ser manipulada pelo usuário para selecionar um double valor de um intervalo contínuo.

O Slider define três propriedades do tipo double:

  • Minimum é o mínimo do intervalo, com um valor padrão de 0.
  • Maximum é o máximo do intervalo, com um valor padrão de 1.
  • Value é o valor do controle deslizante, que pode variar entre Minimum e Maximum e tem um valor padrão de 0.

Todas as três propriedades são apoiadas por BindableProperty objetos. A Value propriedade tem um modo de vinculação padrão de BindingMode.TwoWay, o que significa que ela é adequada como uma fonte de vinculação em um aplicativo que usa a arquitetura MVVM (Model-View-ViewModel).

Aviso

Internamente, a Slider garantia é menor que MinimumMaximum. Se Minimum ou Maximum alguma vez forem definidos de modo que Minimum não seja inferior a , uma exceção é levantada Maximum. Consulte a seção Precauções abaixo para obter mais informações sobre como definir as Minimum propriedades e Maximum .

O Slider coage o Value imóvel para que ele fique entre Minimum e Maximum, inclusive. Se a Minimum propriedade for definida como um valor maior que a Value propriedade, a Slider propriedade será definida Value como Minimum. Da mesma forma, se Maximum for definido como um valor menor que Value, defina Slider a Value propriedade como Maximum.

Slider Define um ValueChanged evento que é acionado quando as Value alterações, por meio da manipulação do Slider usuário do ou quando o programa define a Value propriedade diretamente. Um ValueChanged evento também é disparado quando a Value propriedade é coagida conforme descrito no parágrafo anterior.

O ValueChangedEventArgs objeto que acompanha o ValueChanged evento tem duas propriedades, ambas do tipo double: OldValue e NewValue. No momento em que o evento é acionado, o valor de NewValue é o mesmo que a Value propriedade do Slider objeto.

Slider também define DragStarted e DragCompleted eventos, que são disparados no início e no final da ação de arrastar. Ao contrário do ValueChanged evento, os DragStarted eventos e DragCompleted só são disparados através da manipulação do usuário do Slider. Quando o DragStarted evento é acionado, o DragStartedCommand, do tipo ICommand, é executado. Da mesma forma, quando o DragCompleted evento é acionado, o DragCompletedCommand, do tipo ICommand, é executado.

Aviso

Não use opções de layout horizontal irrestrito de Center, Startou End com Slider. Tanto no Android quanto na UWP, a Slider barra é reduzida para uma barra de comprimento zero e, no iOS, a barra é muito curta. Mantenha a configuração padrão HorizontalOptions de Fill, e não use uma largura de Auto ao colocar Slider um Grid layout.

O Slider também define várias propriedades que afetam sua aparência:

Observação

As ThumbColor propriedades e ThumbImageSource são mutuamente exclusivas. Se ambas as propriedades estiverem definidas, a ThumbImageSource propriedade terá precedência.

Código e marcação básicos do Slider

O exemplo SliderDemos começa com três páginas que são funcionalmente idênticas, mas são implementadas de maneiras diferentes. A primeira página usa apenas código C#, a segunda usa XAML com um manipulador de eventos no código e a terceira é capaz de evitar o manipulador de eventos usando a vinculação de dados no arquivo XAML.

Criando um controle deslizante no código

A página Código Deslizante Básico no exemplo SliderDemos mostra a criação de um Slider e dois Label objetos no 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
            }
        };
    }
}

O Slider é inicializado para ter uma Maximum propriedade de 360. O ValueChanged manipulador do Slider usa a sliderValue propriedade do objeto para definir a Rotation propriedade do primeiro Label e usa o String.Format método com a NewValue propriedade dos argumentos de evento para definir a Text propriedade do segundo Label. Essas duas abordagens para obter o valor atual do Slider são intercambiáveis.

Aqui está o programa em execução em dispositivos iOS e Android:

Basic Slider Code

O segundo Label exibe o texto "(não inicializado)" até que o seja manipulado, o Slider que faz com que o primeiro ValueChanged evento seja disparado. Observe que o número de casas decimais exibidas é diferente para cada plataforma. Essas diferenças estão relacionadas às implementações de plataforma do e são discutidas posteriormente neste artigo na seção Diferenças de implementação de Slider plataforma.

Criando um controle deslizante em XAML

A página XAML do Controle Deslizante Básico é funcionalmente igual ao Código Deslizante Básico, mas implementada principalmente em 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>

O arquivo code-behind contém o manipulador para o ValueChanged evento:

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);
    }
}

Também é possível que o manipulador de eventos obtenha o Slider que está disparando o evento por meio do sender argumento. A Value propriedade contém o valor atual:

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

Se o Slider objeto recebeu um nome no arquivo XAML com um x:Name atributo (por exemplo, "slider"), o manipulador de eventos poderia fazer referência a esse objeto diretamente:

double value = slider.Value;

Vinculação de dados ao controle deslizante

A página Ligações Deslizantes Básicas mostra como escrever um programa quase equivalente que elimina o manipulador de eventos usando a Value Vinculação de Dados:

<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>

A Rotation propriedade do primeiro Label está vinculada à Value propriedade do Slider, assim como a Text propriedade do segundo Label com uma StringFormat especificação. A página Basic Slider Bindings funciona de forma um pouco diferente das duas páginas anteriores: quando a página aparece pela primeira vez, a segunda Label exibe a cadeia de texto com o valor. Esse é um benefício do uso da vinculação de dados. Para exibir texto sem associação de dados, você precisaria inicializar especificamente a Text propriedade do Label ou simular um disparo do ValueChanged evento chamando o manipulador de eventos do construtor de classe.

Precauções

O valor do Minimum imóvel deve ser sempre menor que o valor do Maximum imóvel. O trecho de código a seguir faz com que o Slider gere uma exceção:

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

O compilador C# gera código que define essas duas propriedades em sequência e, quando a Minimum propriedade é definida como 10, ela é maior que o valor padrão Maximum de 1. Você pode evitar a exceção nesse caso definindo a Maximum propriedade primeiro:

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

Definir Maximum como 20 não é um problema porque é maior do que o valor padrão Minimum de 0. Quando Minimum é definido, o valor é menor que o Maximum valor de 20.

O mesmo problema existe em XAML. Defina as propriedades em uma ordem que garanta que Maximum seja sempre maior que Minimum:

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

Você pode definir os Minimum valores e Maximum para números negativos, mas somente em uma ordem em que Minimum é sempre menor que Maximum:

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

A Value propriedade é sempre maior ou igual ao Minimum valor e menor ou igual a Maximum. Se Value for definido como um valor fora desse intervalo, o valor será coagido a ficar dentro do intervalo, mas nenhuma exceção será gerada. Por exemplo, esse código não gerará uma exceção:

Slider slider = new Slider
{
    Value = 10
};

Em vez disso, a Value propriedade é coagida ao Maximum valor de 1.

Aqui está um trecho de código mostrado acima:

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

Quando Minimum é definido como 10, em seguida Value , também é definido como 10.

Se um ValueChanged manipulador de eventos tiver sido anexado no momento em que a Value propriedade for coagida a algo diferente de seu valor padrão de 0, um ValueChanged evento será acionado. Aqui está um trecho de XAML:

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

Quando Minimum é definido como 10, Value também é definido como 10 e o ValueChanged evento é disparado. Isso pode ocorrer antes que o restante da página tenha sido construído, e o manipulador pode tentar fazer referência a outros elementos na página que ainda não foram criados. Talvez você queira adicionar algum código ao ValueChanged manipulador que verifica null valores de outros elementos na página. Ou, você pode definir o ValueChanged manipulador de eventos depois que os Slider valores foram inicializados.

Diferenças de implementação da plataforma

As capturas de tela mostradas anteriormente exibem o valor do Slider com um número diferente de pontos decimais. Isso está relacionado a como o Slider é implementado nas plataformas Android e UWP.

A implementação do Android

A implementação do Slider Android é baseada no Android SeekBar e sempre define a Max propriedade como 1000. Isso significa que o Slider no Android tem apenas 1.001 valores discretos. Se você definir o Slider para ter um Minimum de 0 e um Maximum de 5000, então como o Slider é manipulado, a Value propriedade tem valores de 0, 5, 10, 15 e assim por diante.

A implementação da UWP

A implementação da UWP é Slider baseada no controle UWP Slider . A StepFrequency propriedade da UWP Slider é definida como a diferença das Maximum propriedades e Minimum divididas por 10, mas não maior que 1.

Por exemplo, para o intervalo padrão de 0 a 1, a StepFrequency propriedade é definida como 0,1. Como o Slider é manipulado, a Value propriedade é restrita a 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 e 1.0. (Isso fica evidente na última página do Exemplo de SliderDemos .) Quando a diferença entre as Maximum propriedades e Minimum é 10 ou maior, então StepFrequency é definido como 1 e a Value propriedade tem valores integrais.

A solução StepSlider

Um mais versátil StepSlider é discutido no capítulo 27. Renderizadores personalizados do livro Criando aplicativos móveis com Xamarin.Formso . O StepSlider é semelhante a Slider , mas adiciona uma Steps propriedade para especificar o número de valores entre Minimum e Maximum.

Controles deslizantes para seleção de cores

As duas páginas finais no exemplo SliderDemos usam três Slider instâncias para seleção de cores. A primeira página manipula todas as interações no arquivo code-behind, enquanto a segunda página mostra como usar a vinculação de dados com um ViewModel.

Manipulando controles deslizantes no arquivo code-behind

A página Controles Deslizantes de Cores RGB instancia um BoxView para exibir uma cor, três Slider instâncias para selecionar os componentes vermelho, verde e azul da cor e três Label elementos para exibir esses valores de cor:

<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>

A Style dá a todos os três Slider elementos um intervalo de 0 a 255. Os Slider elementos compartilham o mesmo ValueChanged manipulador, que é implementado no arquivo code-behind:

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);
    }
}

A primeira seção define a Text propriedade de uma das Label ocorrências como uma cadeia de caracteres de texto curto indicando o valor do Slider hexadecimal in. Em seguida, todas as três Slider instâncias são acessadas para criar um Color valor a partir dos componentes RGB:

RGB Color Sliders

Vinculando o controle deslizante a um ViewModel

A página Controles deslizantes de cores HSL mostra como usar um ViewModel para executar os cálculos usados para criar um Color valor a partir de valores de matiz, saturação e luminosidade. Como todos os ViewModels, a classe implementa HSLColorViewModel a INotifyPropertyChanged interface e dispara um PropertyChanged evento sempre que uma das propriedades é alterada:

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 e a INotifyPropertyChanged interface são discutidos no artigo Vinculação de dados.

O arquivo HslColorSlidersPage.xaml instancia o HslColorViewModel e o define como a propriedade da BindingContext página. Isso permite que todos os elementos no arquivo XAML se associem às propriedades no 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>

À medida que os Slider elementos são manipulados, os BoxView elementos e são Label atualizados a partir do ViewModel:

HSL Color Sliders

O StringFormat componente da extensão de Binding marcação é definido para um formato de "F2" para exibir duas casas decimais. (A formatação de cadeia de caracteres em associações de dados é discutida no artigo Formatação de cadeia de caracteres.) No entanto, a versão UWP do programa é limitada a valores de 0, 0.1, 0.2, ... 0,9 e 1,0. Isso é um resultado direto da implementação da UWP Slider , conforme descrito acima na seção Diferenças de implementação da plataforma.