Partilhar via


Xamarin.Forms Botão

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 todo Xamarin.Formso . O Button geralmente exibe uma cadeia 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.

Manipulando cliques no botão

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

A página Basic Button Click 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>

O Button tende a ocupar todo o espaço que lhe é permitido. 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-lhe 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. Aqui está o programa em execução em dispositivos iOS e Android e como um aplicativo da Plataforma Universal do Windows (UWP) na área de trabalho do Windows 10:

Clique no botão Básico

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 usa await.

Cada plataforma renderiza o Button de sua 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, por isso inclui FontFamily, FontSizee FontAttributes propriedades.

Criando um botão no código

É comum instanciar um Button em XAML, mas você também pode criar um Button em 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 é funcionalmente equivalente à página Clique no botão básico, mas totalmente 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 turma. 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 deve ser desabilitado Button definindo sua IsEnabled propriedade 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 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 de comando ou interface de comando. Isso consiste em duas propriedades:

Essa abordagem é particularmente adequada em conexão com a vinculação de dados e, particularmente, ao implementar a arquitetura MVVM (Model-View-ViewModel). Esses tópicos são discutidos nos artigos Vinculação de dados, De ligaçõ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 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 nomeado 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 pela metade a Number propriedade.

O arquivo BasicButtonCommand.xaml define como BindingContext uma instância de 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 do botão básico

A vantagem dessa abordagem sobre Clicked os manipuladores é que toda a lógica que envolve a funcionalidade desta página está localizada no viewmodel em vez do arquivo code-behind, obtendo uma melhor separação 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 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 (chamado de canExecute argumento) que retorna true se o Button deve ser habilitado. Aqui está a modificação para o 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 CommandButton ou não. Com essa alteração de código, à medida que o número atinge o limite, o Button é desabilitado:

Comando do botão básico - Modificado

É possível que dois ou mais Button elementos sejam vinculados à mesma ICommand propriedade. Os Button elementos podem ser distinguidos usando a CommandParameter propriedade de Button. Nesse caso, convém usar a classe genérica Command<T> . O CommandParameter objeto é então 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 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 CommandParameter tipo do 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 seu BindingContext para si mesmo. Isso é necessário para que as propriedades no arquivo XAML se associem à 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 botão do dedo ou 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 antes de Button ser liberado, o Clicked evento pode não ocorrer.

Os Pressed eventos e Released não são usados com frequência, mas podem ser usados para fins especiais, como demonstrado na página Pressionar e Botão Liberar . 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 quando Label um Pressed evento ocorre, mas suspende a rotação quando um Released evento ocorre:

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

Pressione e solte o botão

Esse tipo de comportamento tem aplicações para jogos: um dedo segurado 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 e Padding propriedades 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 botão.

Todos os modos de exibição e associações de dados na página Aparência do botão são definidos 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 o FontSize, BorderWidthe CornerRadius propriedades do Button.

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

Aparência do Botão

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

No iOS, você notará que grandes larguras de borda invadem o interior do Button e interferem na exibição de 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 PressedVisualState que pode ser usado para iniciar uma alteração visual no quando pressionado Button pelo usuário, desde que 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 é 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 é lançado, 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 subclassificar Button para que funcione como um interruptor liga-desliga: toque no botão uma vez para ativar o botão e toque nele novamente para desativá-lo.

A classe a seguir ToggleButton deriva de 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 IsToggled valor da propriedade. O OnIsToggledChanged método dispara o Toggled evento.

A última linha do OnIsToggledChanged método chama o método estático VisualStateManager.GoToState com as duas cadeias de 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 do , incluindo a marcação do Gerenciador de ToggleButtonEstado Visual 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 FontAttributesLabel 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:

Botão de alternância Demo

Usando bitmaps com botões

A Button classe define uma ImageSource propriedade que permite exibir uma imagem de bitmap no Button, sozinha 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 incorporado, URI ou fluxo.

Observação

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

Cada plataforma suportada por Xamarin.Forms permite 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 tal forma que o sistema operacional pode 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 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 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 Compilação 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

Estes receberam uma Ação de Compilação 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 receberam uma Ação de Construção de Conteúdo.

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

  • Um membro da ImagePosition enumeração: Left, , TopRight, ou 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 named 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)
};

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 Imagem usa OnPlatform para especificar nomes de arquivos 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 do OnPlatform, será necessário armazenar os bitmaps UWP no diretório raiz do projeto.

O primeiro Button na página Demonstração do botão 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 repetitiva 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

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