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 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 Fill
de 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:
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 FontFamily
as propriedades , FontSize
e 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 false
como . 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:
Command
do tipoICommand
, uma interface definida noSystem.Windows.Input
namespace .CommandParameter
da propriedade do tipoObject
.
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 Number
e 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:
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:
É 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 NavigateCommand
e é 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 Button
ou 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 Button
e para quando o dedo é liberado:
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:
TextColor
é a cor doButton
textoBackgroundColor
é a cor da tela de fundo para esse textoBorderColor
é a cor de uma área ao redor doButton
FontFamily
é a família de fontes usada para o textoFontSize
é o tamanho do textoFontAttributes
indica se o texto é itálico ou negritoBorderWidth
é a largura da bordaCornerRadius
é o raio de canto doButton
CharacterSpacing
é o espaçamento entre os caracteres doButton
texto.TextTransform
determina o uso de maiúsculas e minúsculas doButton
texto.
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 FontSize
propriedades , BorderWidth
e CornerRadius
do Button
.
Este programa permite que você experimente combinações de todas essas propriedades:
Para ver a Button
borda, você precisará definir um BorderColor
como algo diferente Default
de 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 Pressed
VisualState
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 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 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
, BackgroundColor
e 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:
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
,Right
ouBottom
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:
Agora você viu as várias maneiras de lidar com Button
eventos e alterar a Button
aparência.