Xamarin.Forms Botão

Baixar exemplo Baixar o exemplo

O Botão responde a um toque ou clique que direciona um aplicativo para executar uma tarefa específica.

O Button é o controle interativo mais fundamental em todos os Xamarin.Forms. O Button geralmente exibe uma cadeia de caracteres de texto curta indicando um comando, mas também pode exibir uma imagem de bitmap ou uma combinação de texto e uma imagem. O usuário pressiona o Button com um dedo ou clica nele com um mouse para iniciar esse comando.

A maioria dos tópicos discutidos abaixo corresponde às páginas no exemplo ButtonDemos .

Manipulando cliques de botão

Button define um Clicked evento que é acionado quando o usuário toca no com um dedo ou ponteiro do Button mouse. O evento é acionado quando o botão do dedo ou do mouse é liberado da superfície do Button. O Button deve ter sua IsEnabled propriedade definida true como para que ele responda a toques.

A página Clique no Botão Básico no exemplo ButtonDemos demonstra como instanciar um Button em XAML e manipular seu Clicked evento. O arquivo BasicButtonClickPage.xaml contém um StackLayout com um Label e um Button:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ButtonDemos.BasicButtonClickPage"
             Title="Basic Button Click">
    <StackLayout>

        <Label x:Name="label"
               Text="Click the Button below"
               FontSize="Large"
               VerticalOptions="CenterAndExpand"
               HorizontalOptions="Center" />

        <Button Text="Click to Rotate Text!"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                Clicked="OnButtonClicked" />

    </StackLayout>
</ContentPage>

O Button tende a ocupar todo o espaço permitido para ele. Por exemplo, se você não definir a HorizontalOptions propriedade de como algo diferente Fillde Button , o Button ocupará a largura total de seu pai.

Por padrão, o Button é retangular, mas você pode dar a ele cantos arredondados usando a CornerRadius propriedade , conforme descrito abaixo na seção Aparência do botão.

A propriedade Text especifica o texto exibido no Button. O Clicked evento é definido como um manipulador de eventos chamado OnButtonClicked. Esse manipulador está localizado no arquivo code-behind , BasicButtonClickPage.xaml.cs:

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

    async void OnButtonClicked(object sender, EventArgs args)
    {
        await label.RelRotateTo(360, 1000);
    }
}

Quando o Button é tocado, o método OnButtonClicked é executado. O sender argumento é o Button objeto responsável por esse evento. Você pode usar isso para acessar o Button objeto ou para distinguir entre vários Button objetos que compartilham o mesmo Clicked evento.

Esse manipulador específico Clicked chama uma função de animação que gira os Label 360 graus em 1000 milissegundos. Este é o programa em execução em dispositivos iOS e Android e como um aplicativo Plataforma Universal do Windows (UWP) na área de trabalho do Windows 10:

no Botão Básico Clique no

Observe que o OnButtonClicked método inclui o async modificador porque await é usado dentro do manipulador de eventos. Um Clicked manipulador de eventos requer o async modificador somente se o corpo do manipulador usar await.

Cada plataforma renderiza o Button de maneira específica. Na seção Aparência do botão, você verá como definir cores e tornar a Button borda visível para aparências mais personalizadas. Button implementa a IFontElement interface , portanto, inclui FontFamilyas propriedades , FontSizee FontAttributes .

Criando um botão no código

É comum instanciar um Button em XAML, mas você também pode criar um Button no código. Isso pode ser conveniente quando seu aplicativo precisa criar vários botões com base em dados enumeráveis com um foreach loop.

A página Clique no Botão de Código demonstra como criar uma página funcionalmente equivalente à página Clique no Botão Básico , mas inteiramente em C#:

public class CodeButtonClickPage : ContentPage
{
    public CodeButtonClickPage ()
    {
        Title = "Code Button Click";

        Label label = new Label
        {
            Text = "Click the Button below",
            FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
            VerticalOptions = LayoutOptions.CenterAndExpand,
            HorizontalOptions = LayoutOptions.Center
        };

        Button button = new Button
        {
            Text = "Click to Rotate Text!",
            VerticalOptions = LayoutOptions.CenterAndExpand,
            HorizontalOptions = LayoutOptions.Center
        };
        button.Clicked += async (sender, args) => await label.RelRotateTo(360, 1000);

        Content = new StackLayout
        {
            Children =
            {
                label,
                button
            }
        };
    }
}

Tudo é feito no construtor da classe. Como o Clicked manipulador tem apenas uma instrução longa, ele pode ser anexado ao evento de maneira muito simples:

button.Clicked += async (sender, args) => await label.RelRotateTo(360, 1000);

É claro que você também pode definir o manipulador de eventos como um método separado (assim como o OnButtonClick método em Basic Button Click) e anexar esse método ao evento:

button.Clicked += OnButtonClicked;

Desabilitando o botão

Às vezes, um aplicativo está em um estado específico em que um clique específico Button não é uma operação válida. Nesses casos, o Button deve ser desabilitado definindo sua IsEnabled propriedade falsecomo . O exemplo clássico é um Entry controle para um nome de arquivo acompanhado de um arquivo aberto Button: o Button deve ser habilitado somente se algum texto tiver sido digitado no Entry. Você pode usar um DataTrigger para essa tarefa, conforme mostrado no artigo Gatilhos de Dados .

Usando a interface de comando

É possível que um aplicativo responda a Button toques sem manipular o Clicked evento. O Button implementa um mecanismo de notificação alternativo chamado comando ou interface de comando . Isso consiste em duas propriedades:

Essa abordagem é particularmente adequada em conexão com a associação de dados e, especialmente, ao implementar a arquitetura MVVM (Model-View-ViewModel). Esses tópicos são discutidos nos artigos Associação de Dados, De Associações de Dados a MVVM e MVVM.

Em um aplicativo MVVM, o viewmodel define propriedades do tipo ICommand que são conectadas aos elementos XAML Button com associações de dados. Xamarin.Forms também define Command classes e Command<T> que implementam a ICommand interface e auxiliam o viewmodel na definição de propriedades do tipo ICommand.

Comando é descrito com mais detalhes no artigo A Interface de Comando , mas a página Comando de Botão Básico no exemplo ButtonDemos mostra a abordagem básica.

A CommandDemoViewModel classe é um viewmodel muito simples que define uma propriedade do tipo double chamada Numbere duas propriedades do tipo ICommand denominadas MultiplyBy2Command e DivideBy2Command:

class CommandDemoViewModel : INotifyPropertyChanged
{
    double number = 1;

    public event PropertyChangedEventHandler PropertyChanged;

    public CommandDemoViewModel()
    {
        MultiplyBy2Command = new Command(() => Number *= 2);

        DivideBy2Command = new Command(() => Number /= 2);
    }

    public double Number
    {
        set
        {
            if (number != value)
            {
                number = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Number"));
            }
        }
        get
        {
            return number;
        }
    }

    public ICommand MultiplyBy2Command { private set; get; }

    public ICommand DivideBy2Command { private set; get; }
}

As duas ICommand propriedades são inicializadas no construtor da classe com dois objetos do tipo Command. Os Command construtores incluem uma pequena função (chamada de argumento de execute construtor) que dobra ou reduz pela metade a Number propriedade.

O arquivo BasicButtonCommand.xaml define seu como BindingContext uma instância do CommandDemoViewModel. O Label elemento e dois Button elementos contêm associações às três propriedades em CommandDemoViewModel:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ButtonDemos"
             x:Class="ButtonDemos.BasicButtonCommandPage"
             Title="Basic Button Command">

    <ContentPage.BindingContext>
        <local:CommandDemoViewModel />
    </ContentPage.BindingContext>

    <StackLayout>
        <Label Text="{Binding Number, StringFormat='Value is now {0}'}"
               FontSize="Large"
               VerticalOptions="CenterAndExpand"
               HorizontalOptions="Center" />

        <Button Text="Multiply by 2"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                Command="{Binding MultiplyBy2Command}" />

        <Button Text="Divide by 2"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                Command="{Binding DivideBy2Command}" />
    </StackLayout>
</ContentPage>

À medida que os dois Button elementos são tocados, os comandos são executados e o número altera o valor:

Básico BotãoComando Botão

A vantagem dessa abordagem em relação Clicked aos manipuladores é que toda a lógica que envolve a funcionalidade dessa página está localizada no viewmodel em vez do arquivo code-behind, obtendo uma separação melhor da interface do usuário da lógica de negócios.

Também é possível que os Command objetos controlem a habilitação e a Button desabilitação dos elementos. Por exemplo, suponha que você queira limitar o intervalo de valores numéricos entre 210 e 2 a 10. Você pode adicionar outra função ao construtor (chamado de canExecute argumento ) que retorna true se o Button deve ser habilitado. Aqui está a modificação no CommandDemoViewModel construtor:

class CommandDemoViewModel : INotifyPropertyChanged
{
    ···
    public CommandDemoViewModel()
    {
        MultiplyBy2Command = new Command(
            execute: () =>
            {
                Number *= 2;
                ((Command)MultiplyBy2Command).ChangeCanExecute();
                ((Command)DivideBy2Command).ChangeCanExecute();
            },
            canExecute: () => Number < Math.Pow(2, 10));

        DivideBy2Command = new Command(
            execute: () =>
            {
                Number /= 2;
                ((Command)MultiplyBy2Command).ChangeCanExecute();
                ((Command)DivideBy2Command).ChangeCanExecute();
            },
            canExecute: () => Number > Math.Pow(2, -10));
    }
    ···
}

As chamadas para o ChangeCanExecute método de Command são necessárias para que o Command método possa chamar o canExecute método e determinar se o Button deve ser desabilitado ou não. Com essa alteração de código, à medida que o número atinge o limite, o Button é desabilitado:

Comando Botão Básico – Comando Botão

É possível que dois ou mais Button elementos sejam associados à mesma ICommand propriedade. Os Button elementos podem ser diferenciados usando a CommandParameter propriedade de Button. Nesse caso, você desejará usar a classe genérica Command<T> . Em CommandParameter seguida, o objeto é passado como um argumento para os execute métodos e canExecute . Essa técnica é mostrada em detalhes na seção Comando Básico do artigo Interface de Comando .

O exemplo ButtonDemos também usa essa técnica em sua MainPage classe. O arquivo MainPage.xaml contém um Button para cada página do exemplo:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ButtonDemos"
             x:Class="ButtonDemos.MainPage"
             Title="Button Demos">
    <ScrollView>
        <FlexLayout Direction="Column"
                    JustifyContent="SpaceEvenly"
                    AlignItems="Center">

            <Button Text="Basic Button Click"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:BasicButtonClickPage}" />

            <Button Text="Code Button Click"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:CodeButtonClickPage}" />

            <Button Text="Basic Button Command"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:BasicButtonCommandPage}" />

            <Button Text="Press and Release Button"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:PressAndReleaseButtonPage}" />

            <Button Text="Button Appearance"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:ButtonAppearancePage}" />

            <Button Text="Toggle Button Demo"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:ToggleButtonDemoPage}" />

            <Button Text="Image Button Demo"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:ImageButtonDemoPage}" />

        </FlexLayout>
    </ScrollView>
</ContentPage>

Cada Button uma tem sua Command propriedade associada a uma propriedade chamada NavigateCommande é CommandParameter definida como um Type objeto correspondente a uma das classes de página no projeto.

Essa NavigateCommand propriedade é do tipo ICommand e é definida no arquivo code-behind:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        NavigateCommand = new Command<Type>(async (Type pageType) =>
        {
            Page page = (Page)Activator.CreateInstance(pageType);
            await Navigation.PushAsync(page);
        });

        BindingContext = this;
    }

    public ICommand NavigateCommand { private set; get; }
}

O construtor inicializa a NavigateCommand propriedade para um Command<Type> objeto porque Type é o tipo do CommandParameter objeto definido no arquivo XAML. Isso significa que o execute método tem um argumento do tipo Type que corresponde a esse CommandParameter objeto. A função cria uma instância da página e, em seguida, navega até ela.

Observe que o construtor é concluído definindo-o BindingContext como ele mesmo. Isso é necessário para que as propriedades no arquivo XAML sejam associadas à NavigateCommand propriedade .

Pressionando e liberando o botão

Além de evento Clicked, Button também define eventos Pressed e Released. O Pressed evento ocorre quando um dedo pressiona em um Buttonou um botão do mouse é pressionado com o ponteiro posicionado sobre o Button. O Released evento ocorre quando o dedo ou botão do mouse é liberado. Em geral, um Clicked evento também é disparado ao mesmo tempo que o Released evento, mas se o dedo ou ponteiro do mouse deslizar para longe da superfície do antes de Button ser liberado, o Clicked evento pode não ocorrer.

Os Pressed eventos e Released geralmente não são usados, mas podem ser usados para fins especiais, conforme demonstrado na página Pressionar e Liberar Botão . O arquivo XAML contém um Label e um Button com manipuladores anexados para os Pressed eventos e Released :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ButtonDemos.PressAndReleaseButtonPage"
             Title="Press and Release Button">
    <StackLayout>

        <Label x:Name="label"
               Text="Press and hold the Button below"
               FontSize="Large"
               VerticalOptions="CenterAndExpand"
               HorizontalOptions="Center" />

        <Button Text="Press to Rotate Text!"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                Pressed="OnButtonPressed"
                Released="OnButtonReleased" />

    </StackLayout>
</ContentPage>

O arquivo code-behind anima o Label quando um Pressed evento ocorre, mas suspende a rotação quando ocorre um Released evento:

public partial class PressAndReleaseButtonPage : ContentPage
{
    bool animationInProgress = false;
    Stopwatch stopwatch = new Stopwatch();

    public PressAndReleaseButtonPage ()
    {
        InitializeComponent ();
    }

    void OnButtonPressed(object sender, EventArgs args)
    {
        stopwatch.Start();
        animationInProgress = true;

        Device.StartTimer(TimeSpan.FromMilliseconds(16), () =>
        {
            label.Rotation = 360 * (stopwatch.Elapsed.TotalSeconds % 1);

            return animationInProgress;
        });
    }

    void OnButtonReleased(object sender, EventArgs args)
    {
        animationInProgress = false;
        stopwatch.Stop();
    }
}

O resultado é que o Label só gira enquanto um dedo está em contato com o Buttone para quando o dedo é liberado:

Botão Pressionar e Liberar

Esse tipo de comportamento tem aplicativos para jogos: um dedo mantido em um Button pode fazer com que um objeto na tela se mova em uma direção específica.

Aparência do botão

O Button herda ou define várias propriedades que afetam sua aparência:

Observação

A Button classe também tem Margin propriedades e Padding que controlam o comportamento de layout do Button. Para saber mais, confira Margens e preenchimento.

Os efeitos de seis dessas propriedades (excluindo FontFamily e FontAttributes) são demonstrados na página Aparência do Botão . Outra propriedade, Image, é discutida na seção Usando bitmaps com o botão.

Todas as exibições e associações de dados na página Aparência do Botão são definidas no arquivo XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ButtonDemos"
             x:Class="ButtonDemos.ButtonAppearancePage"
             Title="Button Appearance">
    <StackLayout>
        <Button x:Name="button"
                Text="Button"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                TextColor="{Binding Source={x:Reference textColorPicker},
                                    Path=SelectedItem.Color}"
                BackgroundColor="{Binding Source={x:Reference backgroundColorPicker},
                                          Path=SelectedItem.Color}"
                BorderColor="{Binding Source={x:Reference borderColorPicker},
                                      Path=SelectedItem.Color}" />

        <StackLayout BindingContext="{x:Reference button}"
                     Padding="10">

            <Slider x:Name="fontSizeSlider"
                    Maximum="48"
                    Minimum="1"
                    Value="{Binding FontSize}" />

            <Label Text="{Binding Source={x:Reference fontSizeSlider},
                                  Path=Value,
                                  StringFormat='FontSize = {0:F0}'}"
                   HorizontalTextAlignment="Center" />

            <Slider x:Name="borderWidthSlider"
                    Minimum="-1"
                    Maximum="12"
                    Value="{Binding BorderWidth}" />

            <Label Text="{Binding Source={x:Reference borderWidthSlider},
                                  Path=Value,
                                  StringFormat='BorderWidth = {0:F0}'}"
                   HorizontalTextAlignment="Center" />

            <Slider x:Name="cornerRadiusSlider"
                    Minimum="-1"
                    Maximum="24"
                    Value="{Binding CornerRadius}" />

            <Label Text="{Binding Source={x:Reference cornerRadiusSlider},
                                  Path=Value,
                                  StringFormat='CornerRadius = {0:F0}'}"
                   HorizontalTextAlignment="Center" />

            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>

                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>

                <Grid.Resources>
                    <Style TargetType="Label">
                        <Setter Property="VerticalOptions" Value="Center" />
                    </Style>
                </Grid.Resources>

                <Label Text="Text Color:"
                       Grid.Row="0" Grid.Column="0" />

                <Picker x:Name="textColorPicker"
                        ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
                        ItemDisplayBinding="{Binding FriendlyName}"
                        SelectedIndex="0"
                        Grid.Row="0" Grid.Column="1" />

                <Label Text="Background Color:"
                       Grid.Row="1" Grid.Column="0" />

                <Picker x:Name="backgroundColorPicker"
                        ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
                        ItemDisplayBinding="{Binding FriendlyName}"
                        SelectedIndex="0"
                        Grid.Row="1" Grid.Column="1" />

                <Label Text="Border Color:"
                       Grid.Row="2" Grid.Column="0" />

                <Picker x:Name="borderColorPicker"
                        ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
                        ItemDisplayBinding="{Binding FriendlyName}"
                        SelectedIndex="0"
                        Grid.Row="2" Grid.Column="1" />
            </Grid>
        </StackLayout>
    </StackLayout>
</ContentPage>

O Button na parte superior da página tem suas três Color propriedades associadas a Picker elementos na parte inferior da página. Os itens nos Picker elementos são cores da NamedColor classe incluída no projeto. Três Slider elementos contêm associações bidirecionais para as FontSizepropriedades , BorderWidthe CornerRadius do Button.

Este programa permite que você experimente combinações de todas essas propriedades:

Aparência do botão Aparência

Para ver a Button borda, você precisará definir um BorderColor como algo diferente Defaultde e para BorderWidth um valor positivo.

No iOS, você observará que grandes larguras de borda se intrometem no interior do Button e interferem na exibição do texto. Se você optar por usar uma borda com um iOS Button, provavelmente desejará começar e terminar a Text propriedade com espaços para manter sua visibilidade.

Na UWP, selecionar um CornerRadius que excede metade da altura do Button gera uma exceção.

Estados visuais de botão

Button tem um PressedVisualState que pode ser usado para iniciar uma alteração visual no Button quando pressionado pelo usuário, desde que ele esteja habilitado.

O exemplo XAML a seguir mostra como definir um estado visual para o Pressed estado:

<Button Text="Click me!"
        ...>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">
            <VisualState x:Name="Normal">
                <VisualState.Setters>
                    <Setter Property="Scale"
                            Value="1" />
                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="Pressed">
                <VisualState.Setters>
                    <Setter Property="Scale"
                            Value="0.8" />
                </VisualState.Setters>
            </VisualState>

        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Button>

O PressedVisualState especifica que, quando o Button for pressionado, sua Scale propriedade será alterada de seu valor padrão de 1 para 0,8. O NormalVisualState especifica que, quando o Button estiver em um estado normal, sua Scale propriedade será definida como 1. Portanto, o efeito geral é que, quando o Button é pressionado, ele é redimensionado para ser um pouco menor e, quando o Button é liberado, ele é redimensionado para seu tamanho padrão.

Para obter mais informações sobre estados visuais, consulte O Xamarin.Forms Visual State Manager.

Criando um botão de alternância

É possível subclasse Button para que funcione como uma opção ativada: toque no botão uma vez para ativar o botão e toque novamente para desativar o botão.

ToggleButton A classe a seguir deriva de Button e define um novo evento chamado Toggled e uma propriedade booliana chamada IsToggled. Essas são as mesmas duas propriedades definidas pelo Xamarin.FormsSwitch:

class ToggleButton : Button
{
    public event EventHandler<ToggledEventArgs> Toggled;

    public static BindableProperty IsToggledProperty =
        BindableProperty.Create("IsToggled", typeof(bool), typeof(ToggleButton), false,
                                propertyChanged: OnIsToggledChanged);

    public ToggleButton()
    {
        Clicked += (sender, args) => IsToggled ^= true;
    }

    public bool IsToggled
    {
        set { SetValue(IsToggledProperty, value); }
        get { return (bool)GetValue(IsToggledProperty); }
    }

    protected override void OnParentSet()
    {
        base.OnParentSet();
        VisualStateManager.GoToState(this, "ToggledOff");
    }

    static void OnIsToggledChanged(BindableObject bindable, object oldValue, object newValue)
    {
        ToggleButton toggleButton = (ToggleButton)bindable;
        bool isToggled = (bool)newValue;

        // Fire event
        toggleButton.Toggled?.Invoke(toggleButton, new ToggledEventArgs(isToggled));

        // Set the visual state
        VisualStateManager.GoToState(toggleButton, isToggled ? "ToggledOn" : "ToggledOff");
    }
}

O ToggleButton construtor anexa um manipulador ao Clicked evento para que ele possa alterar o valor da IsToggled propriedade. O OnIsToggledChanged método aciona o Toggled evento.

A última linha do OnIsToggledChanged método chama o método estático VisualStateManager.GoToState com as duas cadeias de texto "ToggledOn" e "ToggledOff". Você pode ler sobre esse método e como seu aplicativo pode responder aos estados visuais no artigo The Xamarin.Forms Visual State Manager.

Como ToggleButton faz a chamada para VisualStateManager.GoToState, a classe em si não precisa incluir nenhuma instalação adicional para alterar a aparência do botão com base em seu IsToggled estado. Essa é a responsabilidade do XAML que hospeda o ToggleButton.

A página Demo de Botão de Alternância contém duas instâncias do ToggleButton, incluindo a marcação do Visual State Manager que define o Text, BackgroundColore TextColor o botão com base no estado visual:

<?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:local="clr-namespace:ButtonDemos"
             x:Class="ButtonDemos.ToggleButtonDemoPage"
             Title="Toggle Button Demo">

    <ContentPage.Resources>
        <Style TargetType="local:ToggleButton">
            <Setter Property="VerticalOptions" Value="CenterAndExpand" />
            <Setter Property="HorizontalOptions" Value="Center" />
        </Style>
    </ContentPage.Resources>

    <StackLayout Padding="10, 0">
        <local:ToggleButton Toggled="OnItalicButtonToggled">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="ToggleStates">
                    <VisualState Name="ToggledOff">
                        <VisualState.Setters>
                            <Setter Property="Text" Value="Italic Off" />
                            <Setter Property="BackgroundColor" Value="#C0C0C0" />
                            <Setter Property="TextColor" Value="Black" />
                        </VisualState.Setters>
                    </VisualState>

                    <VisualState Name="ToggledOn">
                        <VisualState.Setters>
                            <Setter Property="Text" Value=" Italic On " />
                            <Setter Property="BackgroundColor" Value="#404040" />
                            <Setter Property="TextColor" Value="White" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </local:ToggleButton>

        <local:ToggleButton Toggled="OnBoldButtonToggled">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="ToggleStates">
                    <VisualState Name="ToggledOff">
                        <VisualState.Setters>
                            <Setter Property="Text" Value="Bold Off" />
                            <Setter Property="BackgroundColor" Value="#C0C0C0" />
                            <Setter Property="TextColor" Value="Black" />
                        </VisualState.Setters>
                    </VisualState>

                    <VisualState Name="ToggledOn">
                        <VisualState.Setters>
                            <Setter Property="Text" Value=" Bold On " />
                            <Setter Property="BackgroundColor" Value="#404040" />
                            <Setter Property="TextColor" Value="White" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </local:ToggleButton>

        <Label x:Name="label"
               Text="Just a little passage of some sample text that can be formatted in italic or boldface by toggling the two buttons."
               FontSize="Large"
               HorizontalTextAlignment="Center"
               VerticalOptions="CenterAndExpand" />

    </StackLayout>
</ContentPage>

Os Toggled manipuladores de eventos estão no arquivo code-behind. Eles são responsáveis por definir a FontAttributes propriedade do Label com base no estado dos botões:

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

    void OnItalicButtonToggled(object sender, ToggledEventArgs args)
    {
        if (args.Value)
        {
            label.FontAttributes |= FontAttributes.Italic;
        }
        else
        {
            label.FontAttributes &= ~FontAttributes.Italic;
        }
    }

    void OnBoldButtonToggled(object sender, ToggledEventArgs args)
    {
        if (args.Value)
        {
            label.FontAttributes |= FontAttributes.Bold;
        }
        else
        {
            label.FontAttributes &= ~FontAttributes.Bold;
        }
    }
}

Aqui está o programa em execução no iOS, Android e UWP:

Demo de botão de alternância de botão de

Usando bitmaps com botões

A Button classe define uma ImageSource propriedade que permite exibir uma imagem de bitmap no Button, sozinho ou em combinação com texto. Você também pode especificar como o texto e a imagem são organizados.

A ImageSource propriedade é do tipo ImageSource, o que significa que os bitmaps podem ser carregados de um arquivo, recurso inserido, URI ou fluxo.

Observação

Embora um Button possa carregar um GIF animado, ele exibirá apenas o primeiro quadro do GIF.

Cada plataforma compatível com Xamarin.Forms permite que as imagens sejam armazenadas em vários tamanhos para resoluções de pixel diferentes dos vários dispositivos em que o aplicativo pode ser executado. Esses vários bitmaps são nomeados ou armazenados de forma que o sistema operacional possa escolher a melhor correspondência para a resolução de vídeo do dispositivo.

Para um bitmap em um Button, o melhor tamanho geralmente é entre 32 e 64 unidades independentes de dispositivo, dependendo do tamanho que você deseja que ele seja. As imagens usadas neste exemplo são baseadas em um tamanho de 48 unidades independentes de dispositivo.

No projeto do iOS, a pasta Recursos contém três tamanhos desta imagem:

  • Um bitmap quadrado de 48 pixels armazenado como /Resources/MonkeyFace.png
  • Um bitmap quadrado de 96 pixels armazenado como /Resource/MonkeyFace@2x.png
  • Um bitmap quadrado de 144 pixels armazenado como /Resource/MonkeyFace@3x.png

Todos os três bitmaps receberam uma Ação de Build de BundleResource.

Para o projeto android, todos os bitmaps têm o mesmo nome, mas são armazenados em subpastas diferentes da pasta Recursos :

  • Um bitmap quadrado de 72 pixels armazenado como /Resources/drawable-hdpi/MonkeyFace.png
  • Um bitmap quadrado de 96 pixels armazenado como /Resources/drawable-xhdpi/MonkeyFace.png
  • Um bitmap quadrado de 144 pixels armazenado como /Resources/drawable-xxhdpi/MonkeyFace.png
  • Um bitmap quadrado de 192 pixels armazenado como /Resources/drawable-xxxhdpi/MonkeyFace.png

Eles receberam uma Ação de Build do AndroidResource.

No projeto UWP, os bitmaps podem ser armazenados em qualquer lugar do projeto, mas geralmente são armazenados em uma pasta personalizada ou na pasta Ativos existente. O projeto UWP contém estes bitmaps:

  • Um bitmap quadrado de 48 pixels armazenado como /Assets/MonkeyFace.scale-100.png
  • Um bitmap quadrado de 96 pixels armazenado como /Assets/MonkeyFace.scale-200.png
  • Um bitmap quadrado de 192 pixels armazenado como /Assets/MonkeyFace.scale-400.png

Todos eles receberam uma Ação de Build de Conteúdo.

Você pode especificar como as propriedades e ImageSource são organizadas no Button usando a ContentLayout propriedade de Button.Text Essa propriedade é do tipo ButtonContentLayout, que é uma classe inserida em Button. O construtor tem dois argumentos:

  • Um membro da ImagePosition enumeração: Left, Top, Rightou Bottom indicando como o bitmap aparece em relação ao texto.
  • Um double valor para o espaçamento entre o bitmap e o texto.

Os padrões são Left e 10 unidades. Duas propriedades somente leitura de ButtonContentLayout nomeado Position e Spacing fornecem os valores dessas propriedades.

No código, você pode criar um Button e definir a ContentLayout propriedade da seguinte maneira:

Button button = new Button
{
    Text = "button text",
    ImageSource = new FileImageSource
    {
        File = "image filename"
    },
    ContentLayout = new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Right, 20)
};

No XAML, você precisa especificar apenas o membro de enumeração ou o espaçamento ou ambos em qualquer ordem separada por vírgulas:

<Button Text="button text"
        ImageSource="image filename"
        ContentLayout="Right, 20" />

A página Demonstração do Botão de Imagem usa OnPlatform para especificar nomes de arquivo diferentes para os arquivos bitmap iOS, Android e UWP. Se você quiser usar o mesmo nome de arquivo para cada plataforma e evitar o uso de OnPlatform, precisará armazenar os bitmaps UWP no diretório raiz do projeto.

O primeiro Button na página Demonstração do Botão de Imagem define a Image propriedade, mas não a Text propriedade :

<Button>
    <Button.ImageSource>
        <OnPlatform x:TypeArguments="ImageSource">
            <On Platform="iOS, Android" Value="MonkeyFace.png" />
            <On Platform="UWP" Value="Assets/MonkeyFace.png" />
        </OnPlatform>
    </Button.ImageSource>
</Button>

Se os bitmaps UWP forem armazenados no diretório raiz do projeto, essa marcação poderá ser consideravelmente simplificada:

<Button ImageSource="MonkeyFace.png" />

Para evitar muita marcação repetitious no arquivo ImageButtonDemo.xaml , um implícito Style também é definido para definir a ImageSource propriedade. Isso Style é aplicado automaticamente a cinco outros Button elementos. Aqui está o arquivo XAML completo:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ButtonDemos.ImageButtonDemoPage">

    <FlexLayout Direction="Column"
                JustifyContent="SpaceEvenly"
                AlignItems="Center">

        <FlexLayout.Resources>
            <Style TargetType="Button">
                <Setter Property="ImageSource">
                    <OnPlatform x:TypeArguments="ImageSource">
                        <On Platform="iOS, Android" Value="MonkeyFace.png" />
                        <On Platform="UWP" Value="Assets/MonkeyFace.png" />
                    </OnPlatform>
                </Setter>
            </Style>
        </FlexLayout.Resources>

        <Button>
            <Button.ImageSource>
                <OnPlatform x:TypeArguments="ImageSource">
                    <On Platform="iOS, Android" Value="MonkeyFace.png" />
                    <On Platform="UWP" Value="Assets/MonkeyFace.png" />
                </OnPlatform>
            </Button.ImageSource>
        </Button>

        <Button Text="Default" />

        <Button Text="Left - 10"
                ContentLayout="Left, 10" />

        <Button Text="Top - 10"
                ContentLayout="Top, 10" />

        <Button Text="Right - 20"
                ContentLayout="Right, 20" />

        <Button Text="Bottom - 20"
                ContentLayout="Bottom, 20" />
    </FlexLayout>
</ContentPage>

Os quatro Button elementos finais usam a ContentLayout propriedade para especificar uma posição e espaçamento do texto e do bitmap:

Demonstração do botão Imagem de Demonstração do Botão imagem imagem

Agora você viu as várias maneiras de lidar com Button eventos e alterar a Button aparência.