Partilhar via


Botão

A UI do aplicativo multiplataforma .NET (.NET MAUI) Button exibe texto e responde a um toque ou clique que direciona o aplicativo para realizar uma tarefa. Um Button geralmente exibe uma pequena sequência de texto indicando um comando, mas também pode exibir uma imagem bitmap ou uma combinação de texto e uma imagem. Quando o Button é pressionado com o dedo ou clicado com o mouse, ele inicia esse comando.

Button define as propriedades a seguir:

  • BorderColor, do tipo Color, descreve a cor da borda do botão.
  • BorderWidth, do tipo double, define a largura da borda do botão.
  • CharacterSpacing, do tipo double, define o espaçamento entre os caracteres do texto do botão.
  • Command, do tipo ICommand, define o comando que é executado quando o botão é tocado.
  • CommandParameter, do tipo object, é o parâmetro passado para Command.
  • ContentLayout, do tipo ButtonContentLayout, define o objeto que controla a posição da imagem do botão e o espaçamento entre a imagem e o texto do botão.
  • CornerRadius, do tipo int, descreve o raio do canto da borda do botão.
  • FontAttributes, do tipo FontAttributes, determina o estilo de texto.
  • FontAutoScalingEnabled, do tipo bool, define se o texto do botão refletirá as preferências de escala definidas no sistema operacional. O valor padrão dessa propriedade é true.
  • FontFamily, do tipo string, define a família da fonte.
  • FontSize, do tipo double, define o tamanho da fonte.
  • ImageSource, do tipo ImageSource, especifica uma imagem bitmap a ser exibida como o conteúdo do botão.
  • LineBreakMode, do tipo LineBreakMode, determina como o texto deve ser tratado quando não pode caber em uma linha.
  • Padding, do tipo Thickness, determina o preenchimento do botão.
  • Text, do tipo string, define o texto exibido como o conteúdo do botão.
  • TextColor, do tipo Color, descreve a cor do texto do botão.
  • TextTransform, do tipo TextTransform, define a caixa do texto do botão.

Essas propriedades são apoiadas por objetos BindableProperty, o que significa que podem ser alvos de associações de dados e ser estilizada.

Observação

Embora Button defina uma propriedade ImageSource, que permite exibir uma imagem no Button, esta propriedade deve ser usada ao exibir um pequeno ícone próximo ao texto Button.

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

Importante

Um Button deve ter sua propriedade IsEnabled definida como true para responder aos toques.

Crie um botão

Para criar um botão, crie um objeto Button e manipule seu evento Clicked.

O exemplo XAML a seguir mostra como criar um Button:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ButtonDemos.BasicButtonClickPage"
             Title="Basic Button Click">
    <StackLayout>
        <Button Text="Click to Rotate Text!"
                VerticalOptions="Center"
                HorizontalOptions="Center"
                Clicked="OnButtonClicked" />
        <Label x:Name="label"
               Text="Click the Button above"
               FontSize="18"
               VerticalOptions="Center"
               HorizontalOptions="Center" />
    </StackLayout>
</ContentPage>

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:

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

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

Nesse exemplo, quando 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. O manipulador Clicked chama uma função de animação que gira Label 360 graus em 1000 milissegundos:

Captura de tela de um botão.

O código C# equivalente para criar um Button é:

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

Use a interface de comando

Um aplicativo pode responder a toques Button sem manipular o evento Clicked. 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 ligação de dados e, particularmente, ao implementar o padrão Model-View-ViewModel (MVVM). Em uma aplicação MVVM, o viewmodel define propriedades do tipo ICommand que são então conectadas a Button objetos com ligações de dados. O .NET MAUI também define as classes Command e Command<T> que implementam a interface ICommand e auxiliam o viewmodel na definição de propriedades do tipo ICommand. Para obter mais informações sobre os comandos, consulte Comando.

O exemplo a seguir mostra uma classe viewmodel muito simples que define uma propriedade do tipo double nomeado Number e duas propriedades do tipo ICommand nomeado MultiplyBy2Command e DivideBy2Command:

public class CommandDemoViewModel : INotifyPropertyChanged
{
    double number = 1;

    public event PropertyChangedEventHandler PropertyChanged;

    public ICommand MultiplyBy2Command { get; private set; }
    public ICommand DivideBy2Command { get; private set; }

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

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

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

O exemplo XAML a seguir consome a classe CommandDemoViewModel:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             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="18"
               VerticalOptions="Center"
               HorizontalOptions="Center" />
        <Button Text="Multiply by 2"
                VerticalOptions="Center"
                HorizontalOptions="Center"
                Command="{Binding MultiplyBy2Command}" />
        <Button Text="Divide by 2"
                VerticalOptions="Center"
                HorizontalOptions="Center"
                Command="{Binding DivideBy2Command}" />
    </StackLayout>
</ContentPage>

Nesse exemplo, o elemento Label e dois objetos Button contêm ligações às três propriedades na classe CommandDemoViewModel. À medida que os dois objetos Button são tocados, os comandos são executados e o número muda de valor. 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 objetos Command controlem a habilitação e desabilitação dos objetos Button. 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 canExecute argumento) que retorna true se o Button deve ser habilitado:

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

Nesse exemplo, as chamadas para o método ChangeCanExecute de Command são necessárias para que o método Command possa chamar o método canExecute e determinar se Button deve ser desabilitado ou não. Com essa mudança de código, conforme o número atinge o limite, o Button fica desabilitado.

Também é possível que dois ou mais elementos Button sejam vinculados à mesma propriedade ICommand. 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. Para obter mais informações, veja Comandandos.

Pressione e solte o botão

O evento Pressed é gerado quando um dedo pressiona um Button ou um botão do mouse é pressionado com o ponteiro posicionado sobre Button. O evento Released é gerado quando o dedo ou o botão do mouse é liberado. Geralmente, um evento Clicked também é acionado ao mesmo tempo que o evento Released, mas se o dedo ou o ponteiro do mouse deslizar para fora da superfície do Button antes de ser liberado, o evento Clicked poderá não ocorrer.

O exemplo XAML a seguir mostra um Label e um Button com manipuladores anexados para os eventos Pressed e Released:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ButtonDemos.PressAndReleaseButtonPage"
             Title="Press and Release Button">
    <StackLayout>
        <Button Text="Press to Rotate Text!"
                VerticalOptions="Center"
                HorizontalOptions="Center"
                Pressed="OnButtonPressed"
                Released="OnButtonReleased" />
        <Label x:Name="label"
               Text="Press and hold the Button above"
               FontSize="18"
               VerticalOptions="Center"
               HorizontalOptions="Center" />
    </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
{
    IDispatcherTimer timer;
    Stopwatch stopwatch = new Stopwatch();

    public PressAndReleaseButtonPage()
    {
        InitializeComponent();

        timer = Dispatcher.CreateTimer();
        timer.Interval = TimeSpan.FromMilliseconds(16);
        timer.Tick += (s, e) =>
        {
            label.Rotation = 360 * (stopwatch.Elapsed.TotalSeconds % 1);
        };
    }

    void OnButtonPressed(object sender, EventArgs args)
    {
        stopwatch.Start();
        timer.Start();
    }

    void OnButtonReleased(object sender, EventArgs args)
    {
        stopwatch.Stop();
        timer.Stop();
    }
}

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

Estados visuais Button

Button possui um Pressed VisualState que pode ser usado para iniciar uma mudança visual no Button quando pressionado, 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>
        <VisualStateGroupList>
            <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>
                <VisualState x:Name="PointerOver" />            
            </VisualStateGroup>
        </VisualStateGroupList>
    </VisualStateManager.VisualStateGroups>
</Button>

Nesse exemplo, Pressed VisualState especifica que quando Button for pressionado, sua propriedade Scale 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.

Importante

Para que um Button retorne ao seu estado Normal, o VisualStateGroup também deve definir um estado PointerOver. Se usar os estilos ResourceDictionary criados pelo modelo de projeto de aplicativo .NET MAUI, você já terá um estilo implícito Button que define o estado PointerOver.

Para obter mais informações sobre estados visuais, consulte Estados visuais.

Use bitmaps com botões

A classe Button define uma propriedade ImageSource que permite exibir uma pequena imagem bitmap no Button, sozinha ou em combinação com texto. 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.

Os bitmaps não são dimensionados para caber em um Button. O melhor tamanho geralmente é entre 32 e 64 unidades independentes de dispositivo, dependendo do tamanho desejado para o bitmap.

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 e seu construtor possui 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.

No XAML, você pode criar um Button e definir a propriedade ContentLayout especificando apenas o membro de enumeração, ou o espaçamento, ou ambos, em qualquer ordem separada por vírgulas:

<Button Text="Button text"
        ImageSource="button.png"
        ContentLayout="Right, 20" />

Este é o código C# equivalente:

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

Observação

Se a Button contiver texto e uma imagem, pode não ser possível encaixar todo o conteúdo dentro do botão e, portanto, você deve dimensionar sua imagem manualmente para obter o layout desejado.

Desabilitar um botão

Às vezes, um aplicativo entra em um estado em que um clique Button não é uma operação válida. Nesses casos, o Button pode ser desabilitado definindo a propriedade IsEnabled dele como false.