Xamarin.Forms Botão

O Button responde a um toque ou clique que direciona um aplicativo para realizar 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 com o mouse para iniciar esse comando.

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 dedo ou o botão do mouse é liberado da superfície do Button. O Button deve ter sua IsEnabled propriedade definida como true para responder a toques.

A página Clique no Botão Básico no exemplo demonstra como instanciar um Button em XAML e manipular seu Clicked evento. O arquivo BasicButtonClickPage.xaml contém um StackLayout com a 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>

Eles Button tendem a ocupar todo o espaço que é permitido para isso. Por exemplo, se você não definir a HorizontalOptions propriedade de para algo diferente Fillde Button , o Button ocupará toda a largura de seu pai.

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

A propriedade Text especifica o texto exibido no Button. O evento Clicked está definido para 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 argumento sender é o Button objeto responsável por esse evento. Você pode usar isso para acessar o objeto Button ou para distinguir entre vários objetos Button que compartilham o mesmo evento Clicked.

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

Clique de botão básico

Observe que o OnButtonClicked método inclui o async modificador porque await é usado no 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 sua própria 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 FontFamily, FontSize, e propriedades 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 que seja 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, ele pode ser anexado ao evento de forma muito simples:

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

Claro, 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;

Desativando 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 propriedade IsEnabled como false. O exemplo clássico é um Entry controle para um nome de arquivo acompanhado por um arquivo aberto Button: O Button deve ser habilitado somente se algum texto tiver sido digitado Entryno . Você pode usar a 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 interface de comando ou comandos. Isso consiste em duas propriedades:

Essa abordagem é particularmente adequada em conexão com a associação de dados e, particularmente, 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 ao 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 e Command<T> classes que implementam a ICommand interface e auxiliam o viewmodel na definição de propriedades do tipo ICommand.

O comando é descrito com mais detalhes no artigo A interface de comando, mas a página Comando de botão básico no exemplo mostra a abordagem básica.

A CommandDemoViewModel classe é um viewmodel muito simples que define uma propriedade do tipo double chamado Number, e duas propriedades do tipo ICommand chamado 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 do execute construtor) que dobra ou reduz a Number propriedade pela metade.

O arquivo BasicButtonCommand.xaml define sua BindingContext instância como CommandDemoViewModel. O Label elemento e dois Button elementos contêm ligações para as 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 muda de valor:

Comando de botão básico

A vantagem dessa abordagem sobre os manipuladores Clicked é que toda a lógica que envolve a funcionalidade dessa página está localizada no viewmodel e não no arquivo code-behind, conseguindo uma melhor separação entre a interface do usuário e a lógica de negócios.

Também é possível que os Command objetos controlem a ativação e desativação dos Button elementos. Por exemplo, suponha que você queira limitar o intervalo de valores numéricos entre 2 10 e 2–10. Você pode adicionar outra função ao construtor (chamada 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 são necessárias para que o Command método possa chamar o canExecute método e determinar se o deve ser desabilitado Command Button ou não. Com essa alteração de código, à medida que o número atinge o limite, o Button é desabilitado:

Comando de botão básico - Modificado

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

A amostra 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 um tem sua Command propriedade vinculada a uma propriedade chamada NavigateCommand, e o CommandParameter é definido 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 instancia a página e, em seguida, navega até ela.

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

Pressionando e soltando o botão

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

Os Pressed eventos and Released não são usados com frequência, mas podem ser usados para fins especiais, conforme demonstrado na página Botão Pressionar e Soltar. O arquivo XAML contém a Label e a Button com manipuladores anexados para os Pressed eventos and 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 ocorre um evento Pressed, mas suspende a rotação quando ocorre um evento Released:

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 only gira Label enquanto um dedo está em contato com o Button, e para quando o dedo é liberado:

Pressione e solte o botão

Esse tipo de comportamento tem aplicações para jogos: um dedo pressionado em um Button pode fazer um objeto na tela se mover 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 do 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 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 vinculadas 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 ligaçõ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

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

No iOS, você notará 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 exceda a metade da altura do Button gera uma exceção.

Estados visuais Button

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

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

<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 Pressed VisualState especifica que, quando o Button for pressionado, sua Scale propriedade será alterada de seu valor padrão de 1 para 0,8. O Normal VisualState especifica que quando o Button estiver em estado normal, sua propriedade Scale 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 Gerenciador de Estado Visual.

Criando um botão de alternância

É possível criar uma subclasse Button para que funcione como um botão liga-desliga: Toque no botão uma vez para ativar o botão e toque novamente para desativá-lo.

A classe a seguir ToggleButton deriva Button e define um novo evento chamado Toggled e uma propriedade booleana chamada IsToggled. Estas 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 método chama o método estático VisualStateManager.GoToState com as duas cadeias de OnIsToggledChanged caracteres de texto "ToggledOn" e "ToggledOff". Você pode ler sobre esse método e como seu aplicativo pode responder a estados visuais no artigo O Xamarin.Forms Gerenciador de Estado Visual.

Como ToggleButton faz a chamada para VisualStateManager.GoToState, a classe em si não precisa incluir nenhum recurso 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 Demonstração do botão de alternância contém duas instâncias de ToggleButton, incluindo a marcação do Visual State Manager que define o Text, BackgroundColore TextColor do 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 Label propriedade do 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:

Alternar Botão Demo

Usando bitmaps com botões

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

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

Observação

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

Cada plataforma suportada permite Xamarin.Forms que as imagens sejam armazenadas em vários tamanhos para diferentes resoluções de pixel 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 exibiçã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 desejado. As imagens usadas neste exemplo são baseadas em um tamanho de 48 unidades independentes de dispositivo.

No projeto iOS, a pasta Resources 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 Resources :

  • 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 de 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 existente do Assets . 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 Construção de Conteúdo.

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

  • Um membro da enumeração ImagePosition: Left, Top, Right ou Bottom indicando como o bitmap aparece em relação ao texto.
  • Um valor double 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 named Position e Spacing fornecem os valores dessas propriedades.

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

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

Em 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 é usada OnPlatform para especificar nomes de arquivo diferentes para os arquivos de 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 Imagem define a propriedade, Image 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 muitas marcações repetitivas 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 de imagem

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