Botón Xamarin.Forms
El Botón responde a un toque o clic que dirige una aplicación para llevar a cabo una tarea determinada.
El Button
es el control interactivo más fundamental de todos los Xamarin.Forms. La Button
normalmente muestra una breve cadena de texto que indica un comando, pero también puede mostrar una imagen de mapa de bits o una combinación de texto e imagen. El usuario presiona el Button
con un dedo o hace clic en él con un mouse para iniciar ese comando.
Administración de las pulsaciones de botón
Button
define un evento Clicked
que se produce cuando el usuario pulsa Button
con el dedo o con el puntero del ratón. El evento se produce cuando se suelta el dedo o el botón del mouse de la superficie de Button
. El Button
debe tener la propiedad IsEnabled
establecida en true
para que responda a los toques.
La página Clic de botón básico del ejemplo muestra cómo crear una instancia de Button
en XAML y administrar el evento Clicked
. El archivo BasicButtonClickPage.xaml contiene un StackLayout
con un Label
y un 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>
Button
t0iende a ocupar todo el espacio que se le permite. Por ejemplo, si no establece la propiedad HorizontalOptions
de Button
a algo distinto de Fill
, el Button
ocupará todo el ancho de su principal.
Por defecto, el Button
es rectangular, pero puede darle esquinas redondeadas utilizando la propiedad CornerRadius
, como se describe más adelante en la sección Apariencia del botón.
La propiedad Text
especifica el texto que aparece en el elemento Button
. El evento Clicked
se establece en un controlador de eventos denominado OnButtonClicked
. Este controlador se encuentra en el archivo 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);
}
}
Cuando se pulsa Button
, se ejecuta el método OnButtonClicked
. El argumento sender
es el objeto Button
responsable de este evento. Puedes usarlo para acceder al objeto Button
o para distinguir entre varios objetos Button
que comparten el mismo evento Clicked
.
Este controlador Clicked
en particular llama a una función de animación que rota el Label
360 grados en 1 000 milisegundos. Este es el programa funcionando en dispositivos iOS y Android, y como aplicación de la Plataforma Universal de Windows (UWP) en el escritorio de Windows 10:
Observe que el método OnButtonClicked
incluye el modificador async
porque await
se utiliza dentro del controlador de eventos. Un controlador de eventos Clicked
requiere el modificador async
solo si el cuerpo del controlador utiliza await
.
Cada plataforma interpreta el Button
de una manera específica. En la sección Apariencia de los botones, verá cómo establecer los colores y hacer visible el borde Button
para obtener una apariencia más personalizada. Button
implementa la interfaz IFontElement
, por lo que incluye FontFamily
, FontSize
, y propiedades FontAttributes
.
Crear un botón en código
Es común crear una instancia de Button
en XAML, pero también puede crear una Button
en código. Esto puede ser conveniente cuando su aplicación necesita crear múltiples botones basados en datos que son enumerables con un bucle foreach
.
La página Clic de botón de código muestra cómo crear una página funcionalmente equivalente a la página Clic de botón clásico, pero totalmente en 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
}
};
}
}
Todo se hace en el generador de la clase. Dado que el controlador Clicked
solo tiene una sentencia, puede adjuntarse al evento de forma muy sencilla:
button.Clicked += async (sender, args) => await label.RelRotateTo(360, 1000);
Por supuesto, también puede definir el controlador de eventos como un método separado (al igual que el método OnButtonClick
en Clic de botón básico) y adjuntar ese método al evento:
button.Clicked += OnButtonClicked;
Deshabilitar el botón
A veces, una aplicación se encuentra en un estado concreto en el que un clic Button
determinado no es una operación válida. En tales casos, se debe deshabilitar el objeto Button
estableciendo su propiedad IsEnabled
en false
. El ejemplo clásico es un control Entry
para un nombre de archivo acompañado de una apertura de archivo Button
: El Button
debe activarse solo si se ha escrito algún texto en el Entry
.
Puede utilizar un DataTrigger
para esta tarea, como se muestra en el artículo Desencadenadores de datos.
Uso de la interfaz de comandos
Es posible que una aplicación responda a pulsaciones de Button
sin controlar el evento Clicked
. El Button
implementa un mecanismo de notificación alternativo denominado interfaz comando o de comandos. Esta consta de dos propiedades:
Command
de tipoICommand
, una interfaz definida en el espacio de nombresSystem.Windows.Input
.- Propiedad
CommandParameter
de tipoObject
.
Este enfoque es especialmente adecuado en relación con la vinculación de datos, y en particular cuando se implementa la arquitectura Model-View-ViewModel (MVVM). Estos temas se tratan en los artículos Enlace de datos, desde Enlaces de datos a MVVM, y MVVM.
En una aplicación MVVM, el viewmodel define propiedades de tipo ICommand
que luego se conectan a los elementos Button
XAML con enlaces de datos. Xamarin.Forms también define Command
y Command<T>
clases que implementan la interfaz ICommand
y ayudan al viewmodel a definir propiedades de tipo ICommand
.
Los comandos se describen con más detalle en el artículo La interfaz de comandos, pero la página Comandos básicos de botones del ejemplo muestra el enfoque básico.
La clase CommandDemoViewModel
es un viewmodel muy simple que define una propiedad de tipo double
denominada Number
, y dos propiedades de tipo ICommand
denominadas MultiplyBy2Command
y 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; }
}
Las dos propiedades ICommand
se inicializan en el constructor de la clase con dos objetos de tipo Command
. Los constructores Command
incluyen una pequeña función (llamada argumento del constructor execute
) que duplica o reduce a la mitad la propiedad Number
.
El archivo BasicButtonCommand.xaml establece su BindingContext
a una instancia de CommandDemoViewModel
. El elemento Label
y dos elementos Button
contienen vínculos a las tres propiedades en 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>
Al pulsar los dos elementos Button
, se ejecutan los comandos y el número cambia de valor:
La ventaja de este enfoque sobre los controladores Clicked
es que toda la lógica que implica la funcionalidad de esta página se encuentra en el modelo de vista en lugar del archivo de código subyacente, logrando una mejor separación de la interfaz de usuario de la lógica de negocios.
También es posible que los objetos Command
controlen la habilitación y deshabilitación de los elementos Button
. Por ejemplo, supongamos que deseas limitar el intervalo de valores numéricos entre 210 y 2-10. Puede agregar otra función al constructor (llamado el argumento canExecute
) que devuelve true
si el Button
debe ser habilitado. Aquí está la modificación del constructor CommandDemoViewModel
:
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));
}
···
}
Las llamadas al método ChangeCanExecute
de Command
son necesarias para que el método Command
pueda llamar al método canExecute
y determinar si Button
debe deshabilitarse o no. Con este cambio de código, cuando el número alcanza el límite, Button
se deshabilita:
Es posible que dos o más elementos Button
estén vinculados a la misma propiedad ICommand
. Los elementos Button
se pueden distinguir mediante la propiedad CommandParameter
de Button
. En este caso, querrás usar la clase genérica Command<T>
. El objeto CommandParameter
se pasa como un argumento a los métodos execute
y canExecute
. Esta técnica se muestra en detalle en la sección Comandos básicos del artículo Interfaz de comandos.
En el ejemplo también se usa esta técnica en su clase MainPage
. El archivo MainPage.xaml contiene una Button
para cada página de la muestra:
<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
tiene su propiedad Command
vinculada a una propiedad llamada NavigateCommand
, y el CommandParameter
se establece en un Type
objeto correspondiente a una de las clases de página en el proyecto.
Esa propiedad NavigateCommand
es de tipo ICommand
y está definida en el archivo 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; }
}
El constructor inicializa la propiedad NavigateCommand
a un objeto Command<Type>
porque Type
es el tipo del objeto CommandParameter
establecido en el archivo XAML. Esto significa que el método execute
tiene un argumento de tipo Type
que corresponde a este objeto CommandParameter
. La función crea una instancia de la página y luego navega hasta ella.
Observe que el constructor concluye estableciendo BindingContext
en sí mismo. Esto es necesario para que las propiedades del archivo XAML se vinculen a la propiedad NavigateCommand
.
Presionar y soltar el botón
Además del evento Clicked
, Button
también define los eventos Pressed
y Released
. El evento Pressed
se produce cuando un dedo presiona Button
, o se presiona un botón del ratón con el puntero situado sobre el Button
. El evento Released
se produce cuando se suelta el dedo o el botón del mouse. Generalmente, un evento Clicked
también se activa al mismo tiempo que el evento Released
, pero si el dedo o el puntero del ratón se desliza fuera de la superficie del Button
antes de ser liberado, el evento Clicked
podría no ocurrir.
Los eventos Pressed
y Released
no se utilizan a menudo, pero pueden emplearse para fines especiales, como se demuestra en la página Botón de seleccionar y publicar. El archivo XAML contiene un Label
y un Button
con controladores adjuntos para los eventos Pressed
y 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>
El archivo de código subyacente anima Label
cuando se produce un evento Pressed
, pero suspende la rotación cuando se produce un 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();
}
}
El resultado es que el Label
solo gira mientras un dedo está en contacto con el Button
, y se detiene cuando se levanta el dedo:
Este tipo de comportamiento tiene aplicaciones en los juegos: Mantener el dedo sobre un Button
puede hacer que el objeto se mueva en una dirección determinada.
Apariencia del botón
Button
hereda o define varias propiedades que afectan a su aspecto:
TextColor
es el color del textoButton
BackgroundColor
es el color del fondo de ese textoBorderColor
es el color de un área que rodea alButton
FontFamily
es la familia de fuentes utilizada para el textoFontSize
es el tamaño del textoFontAttributes
indica si el texto está en cursiva o en negritaBorderWidth
es el ancho del bordeCornerRadius
es el radio de esquina deButton
CharacterSpacing
es el espaciado entre caracteres del textoButton
.TextTransform
determina el formato del textoButton
.
Nota:
La clase Button
también tiene Margin
y propiedades Padding
que controlan el comportamiento de diseño de Button
. Para obtener más información, vea Márgenes y relleno.
Los efectos de seis de estas propiedades (excluyendo FontFamily
yFontAttributes
) se muestran en la página Apariencia de los botones. Otra propiedad, Image
, se trata en la sección Uso de mapas de bits con el botón.
Todas las vistas y vinculaciones de datos de la página Apariencia de los botones se definen en el archivo 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>
El Button
en la parte superior de la página tiene sus tres propiedades Color
vinculadas a elementos Picker
en la parte inferior de la página. Los elementos Picker
son colores de la clase NamedColor
incluida en el proyecto. Tres elementos Slider
contienen vínculos bidireccionales a los FontSize
, BorderWidth
, y propiedades CornerRadius
de los Button
.
Este programa le permite experimentar con combinaciones de todas estas propiedades:
Para ver el borde Button
, tendrá que establecer BorderColor
a un valor distinto de Default
, y el BorderWidth
a un valor positivo.
En iOS, notará que los bordes de gran anchura se entrometen en el interior del Button
e interfieren con la visualización del texto. Si decide utilizar un borde con un iOS Button
, probablemente querrá comenzar y terminar la propiedad Text
con espacios para mantener su visibilidad.
En UWP, la selección de un CornerRadius
que exceda la mitad de la altura de la Button
plantea una excepción.
Estados visuales del botón
Button
tiene un Pressed
VisualState
que se puede usar para iniciar un cambio visual en cuando Button
lo presione el usuario, siempre que esté habilitado.
En el ejemplo XAML siguiente se muestra cómo definir un estado visual para el 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>
Pressed
VisualState
Especifica que, cuando Button
se presiona , su Scale
propiedad se cambiará de su valor predeterminado de 1 a 0,8. El VisualState
de Normal
especifica que cuando el Button
está en estado normal, su propiedad Scale
se establecerá en 1. Por lo tanto, el efecto general es que, cuando se presiona Button
, se vuelve a escalar para que sea ligeramente más pequeño y, cuando se libera Button
, se vuelve a escalar a su tamaño predeterminado.
Para más información sobre los estados visuales, consulte el Xamarin.FormsAdministrador de estado visual.
Crear un botón de alternancia
Es posible sub clasificar Button
para que funcione como un interruptor activar/desactivar: pulse el botón una vez para encenderlo y vuelva a pulsarlo para apagarlo.
La siguiente clase ToggleButton
deriva de Button
y define un nuevo evento llamado Toggled
y una propiedad booleana llamada IsToggled
. Estas son las mismas dos propiedades definidas por 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");
}
}
El constructor ToggleButton
adjunta un controlador al evento Clicked
para que pueda cambiar el valor de la propiedad IsToggled
. El método OnIsToggledChanged
activa el evento Toggled
.
La última línea del método OnIsToggledChanged
llama al método VisualStateManager.GoToState
estático con las dos cadenas de texto «ToggledOn» y «ToggledOff». Puede leer más sobre este método y sobre cómo su aplicación puede responder a los estados visuales en el artículo El Xamarin.Forms administrador de estados visuales.
Debido a que ToggleButton
hace la llamada a VisualStateManager.GoToState
, la clase en sí no necesita incluir ninguna facilidad adicional para cambiar la apariencia del botón basándose en su estado IsToggled
. Eso es responsabilidad del XAML que aloja el ToggleButton
.
La página de Demostración del botón Alternar contiene dos instancias de ToggleButton
, incluido el marcado Administrador de estado visual que establece el Text
, BackgroundColor
, y TextColor
del botón en función del 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>
Los controladores de eventos Toggled
se encuentran en el archivo de código subyacente. Son responsables de establecer la propiedad FontAttributes
de la Label
basada en el estado de los botones:
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;
}
}
}
Aquí está el programa funcionando en iOS, Android y la UWP:
Uso de mapas de bits con botones.
La clase Button
define una propiedad ImageSource
que permite mostrar una imagen de mapa de bits en el Button
, ya sea sola o en combinación con texto. También puedes especificar cómo se organizan el texto y la imagen.
La propiedad ImageSource
es de tipo ImageSource
, lo que significa que los mapas de bits se pueden cargar desde un archivo, un recurso incrustado, un URI o una secuencia.
Nota:
Aunque un Button
puede cargar un GIF animado, solo mostrará el primer fotograma del GIF.
Cada plataforma compatible con Xamarin.Forms permite almacenar imágenes en varios tamaños para las diferentes resoluciones de píxeles de los distintos dispositivos en los que podría ejecutarse la aplicación. Estos mapas de bits múltiples se nombran o almacenan de forma que el sistema operativo pueda elegir el que mejor se adapte a la resolución de la pantalla de vídeo del dispositivo.
Para un mapa de bits en un Button
, el mejor tamaño suele estar entre 32 y 64 unidades independientes del dispositivo, dependiendo de lo grande que quieras que sea. Las imágenes utilizadas en este ejemplo se basan en un tamaño de 48 unidades independientes del dispositivo.
En el proyecto iOS, la carpeta Recursos contiene tres tamaños de esta imagen:
- Un mapa de bits cuadrado de 48 píxeles almacenado como /Resources/MonkeyFace.png
- Un mapa de bits cuadrado de 96 píxeles almacenado como /Resource/MonkeyFace@2x.png
- Un mapa de bits cuadrado de 144 píxeles almacenado como /Resource/MonkeyFace@3x.png
A los tres mapas de bits se les asignó una Acción de compilación BundleResource.
En el proyecto Android, todos los mapas de bits tienen el mismo nombre, pero se almacenan en diferentes sub carpetas de la carpeta de Recursos:
- Un mapa de bits cuadrado de 72 píxeles almacenado como /Resources/drawable-hdpi/MonkeyFace.png
- Un mapa de bits cuadrado de 96 píxeles almacenado como /Resources/drawable-xhdpi/MonkeyFace.png
- Un mapa de bits cuadrado de 144 píxeles almacenado como /Resources/drawable-xxhdpi/MonkeyFace.png
- Un mapa de bits cuadrado de 192 píxeles almacenado como /Resources/drawable-xxxhdpi/MonkeyFace.png
A estos se les asignó una Acción de compilación de AndroidResource.
En el proyecto UWP, los mapas de bits pueden almacenarse en cualquier parte del proyecto, pero generalmente se almacenan en una carpeta personalizada o en la carpeta de Activos existentes. El proyecto UWP contiene estos mapas de bits:
- Un mapa de bits cuadrado de 48 píxeles almacenado como /Assets/MonkeyFace.scale-100.png
- Un mapa de bits cuadrado de 96 píxeles almacenado como /Assets/MonkeyFace.scale-200.png
- Un mapa de bits cuadrado de 192 píxeles almacenado como /Assets/MonkeyFace.scale-400.png
A todos ellos se les dio una Acción de compilación de Contenido.
Puedes especificar cómo se organizan las propiedades Text
y ImageSource
en Button
mediante la propiedad ContentLayout
de Button
. Esta propiedad es de tipo ButtonContentLayout
, que es una clase incrustada en Button
. El constructor tiene dos argumentos:
- Un miembro de la enumeración
ImagePosition
:Left
,Top
,Right
oBottom
que indica cómo aparece el mapa de bits en relación con el texto. - Un valor
double
para el espaciado entre el mapa de bits y el texto.
Los valores predeterminados son Left
y 10 unidades. Dos propiedades de solo lectura de ButtonContentLayout
llamada Position
y Spacing
proporcionan los valores de dichas propiedades.
En código, puede crear una Button
y establecer la propiedad ContentLayout
así:
Button button = new Button
{
Text = "button text",
ImageSource = new FileImageSource
{
File = "image filename"
},
ContentLayout = new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Right, 20)
};
En XAML, es necesario especificar solo el miembro de la enumeración, o el espaciado, o ambos en cualquier orden separados por comas:
<Button Text="button text"
ImageSource="image filename"
ContentLayout="Right, 20" />
La página de Demostración del botón de imagen utiliza OnPlatform
para especificar diferentes nombres de archivo para los archivos de mapa de bits de iOS, Android y UWP. Si desea utilizar el mismo nombre de archivo para cada plataforma y evitar el uso de OnPlatform
, tendrá que almacenar los mapas de bits UWP en el directorio raíz del proyecto.
El primero Button
en la página de Demostración del botón de imagen establece la Image
propiedad pero no la propiedad Text
:
<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>
Si los mapas de bits UWP se almacenan en el directorio raíz del proyecto, este marcado puede simplificarse considerablemente:
<Button ImageSource="MonkeyFace.png" />
Para evitar un montón de marcado repetitivo en el archivo ImageButtonDemo.xaml, también Style
se define un implícito para establecer la propiedad ImageSource
. Style
se aplica automáticamente a otros cinco elementos Button
. Aquí está el archivo 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>
Los últimos cuatro elementos Button
hacen uso de la propiedad ContentLayout
para especificar una posición y un espaciado del texto y el mapa de bits:
Ya ha visto las distintas formas en que puede controlar los eventos Button
y cambiar la apariencia Button
.