Compartilhar via


Xamarin.Forms Slider

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

A 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 associação padrão de , o que significa que ela é adequada como uma fonte de BindingMode.TwoWayassociação em um aplicativo que usa a arquitetura MVVM (Model-View-ViewModel).

Aviso

Internamente, o Slider garante que Minimum é menor que Maximum. Se Minimum ou Maximum forem definidos de forma que Minimum não seja inferior Maximuma , uma exceção será gerada. Consulte a seção Precauções abaixo para obter mais informações sobre como definir as Minimum propriedades e Maximum .

O Slider coage a Value propriedade para que fique entre Minimum e Maximum, inclusive. Se a Minimum propriedade for definida como um valor maior que a Value propriedade, o Slider definirá a Value propriedade como Minimum. Da mesma forma, if Maximum é definido como um valor menor que Value, define Slider a Value propriedade como Maximum.

Slider define um ValueChanged evento que é acionado quando as Value alterações, seja por meio da manipulação do Slider usuário do ou quando o programa define a Value propriedade diretamente. Um ValueChanged evento também é acionado 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 é disparado, 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 por meio 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, Start, ou End com Slider. No Android e na UWP, o Slider colapso é uma barra de comprimento zero e, no iOS, a barra é muito curta. Mantenha a configuração padrão HorizontalOptions de Fille 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 forem definidas, a ThumbImageSource propriedade terá precedência.

Código básico do controle deslizante e marcação

O exemplo 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 associação de dados no arquivo XAML.

Criando um Slider no código

A página Código do controle deslizante básico mostra show para criar 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 Value propriedade do slider objeto para definir a Rotation propriedade do primeiro Label e usa o String.Format método com a NewValue propriedade dos argumentos do 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:

Código básico do controle deslizante

O segundo Label exibe o texto "(não inicializado)" até que o Slider seja manipulado, o 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 Slider e são discutidas posteriormente neste artigo na seção Diferenças de implementação da plataforma.

Criando um controle deslizante em XAML

A página XAML do Controle Deslizante Básico é funcionalmente a mesma que o Código do Controle 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 do 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);
    }
}

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 receber um nome no arquivo XAML com um x:Name atributo (por exemplo, "slider"), o manipulador de eventos poderá fazer referência a esse objeto diretamente:

double value = slider.Value;

Vinculação de dados do controle deslizante

A página Associações Básicas de Controle Deslizante mostra como escrever um programa quase equivalente que elimina o manipulador de eventos usando a Value Associaçã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á ligada à Value propriedade do Slider, assim como a Text propriedade do segundo Label com uma StringFormat especificação. A página Associações Básicas do Controle Deslizante funciona de maneira um pouco diferente das duas páginas anteriores: quando a página aparece pela primeira vez, a segunda Label exibe a cadeia de caracteres de texto com o valor. Esse é um benefício do uso da associação de dados. Para exibir texto sem associação de dados, você precisaria inicializar especificamente a Text propriedade do Label ou simular um disparo ValueChanged do evento chamando o manipulador de eventos do construtor de classe.

Precauções

O valor da Minimum propriedade deve ser sempre menor que o Maximum valor da propriedade. O snippet 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 que o valor padrão Minimum de 0. Quando Minimum é definido, o valor é menor que o Maximum valor de 20.

O mesmo problema existe no 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 como números negativos, mas apenas em uma ordem em Minimum que é 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á forçado a estar dentro do intervalo, mas nenhuma exceção será gerada. Por exemplo, este código não gerará uma exceção:

Slider slider = new Slider
{
    Value = 10
};

Em vez disso, a Value propriedade é forçada 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, então Value também é definido como 10.

Se um ValueChanged manipulador de eventos tiver sido anexado no momento em que a Value propriedade for forçada a algo diferente de seu valor padrão de 0, um ValueChanged evento será disparado. 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 os valores de outros elementos na página. Ou você pode definir o manipulador de ValueChanged eventos depois que os Slider valores forem inicializados.

Diferenças de implementação da plataforma

As capturas de tela mostradas anteriormente exibem o Slider valor do 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 como tendo um Minimum de 0 e um Maximum de 5000, à medida que o Slider for manipulado, a Value propriedade terá valores de 0, 5, 10, 15 e assim por diante.

A implementação da UWP

A implementação UWP de Slider é baseada no controle UWP Slider . A StepFrequency propriedade da UWP Slider é definida como a diferença das Maximum propriedades and Minimum dividida 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. À medida que 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. Quando a diferença entre as Maximum propriedades e Minimum for 10 ou maior, então StepFrequency é definido como 1 e a Value propriedade tem valores integrais.

A solução StepSlider

Uma mais versátil StepSlider é discutida no Capítulo 27. Renderizadores personalizados do livro Criando aplicativos móveis com Xamarin.Forms. O é semelhante aSlider, StepSlider 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 do exemplo usam três Slider instâncias para seleção de cores. A primeira página lida com todas as interações no arquivo code-behind, enquanto a segunda página mostra como usar a associação de dados com um ViewModel.

Manipulando controles deslizantes no arquivo code-behind

A página Controles deslizantes de cores RGB instancia a 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 dá a Style 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 instâncias como uma cadeia de caracteres de texto curta indicando o valor do Slider hexadecimal em in. Em seguida, todas as três Slider instâncias são acessadas para criar um Color valor a partir dos componentes RGB:

Controles deslizantes de cores RGB

Vinculando o controle deslizante a um ViewModel

A página HSL Color Sliders 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 interface são discutidos INotifyPropertyChanged no artigo Associaçã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 sejam associados a 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 Label são atualizados a partir do ViewModel:

Controles deslizantes de cores HSL

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. Esse é um resultado direto da implementação da UWP Slider , conforme descrito acima na seção Diferenças de implementação da plataforma.