Creación de un efecto
Los efectos simplifican la personalización de un control. En este artículo se muestra cómo crear un efecto que cambia el color de fondo del control Entry cuando recibe el foco.
El proceso para crear un efecto de cada proyecto específico de la plataforma es el siguiente:
- Se crea una subclase de la clase
PlatformEffect
. - Se invalida el método
OnAttached
y se escribe lógica para personalizar el control. - Se invalida el método
OnDetached
y se escribe lógica para limpiar la personalización del control, si es necesario. - Se agrega un atributo
ResolutionGroupName
a la clase de efecto. Este atributo establece un espacio de nombres para los efectos para toda la empresa, lo que evita conflictos con otros efectos con el mismo nombre. Tenga en cuenta que este atributo solo se puede aplicar una vez por proyecto. - Agregue un atributo
ExportEffect
a la clase de efecto. Este atributo registra el efecto con un identificador único que Xamarin.Forms usa junto con el nombre del grupo para buscar el efecto antes de aplicarlo a un control. El atributo toma dos parámetros: el nombre de tipo del efecto y una cadena única que se usará para buscar el efecto antes de aplicarlo a un control.
Después, el efecto se puede consumir si se adjunta al control adecuado.
Nota:
Proporcionar un efecto en cada proyecto de la plataforma es un paso opcional. Al intentar usar un efecto cuando no se ha registrado uno, se devolverá un valor distinto de NULL que no hace nada.
En la aplicación de ejemplo se muestra un elemento FocusEffect
que cambia el color de fondo de un control cuando recibe el foco. El siguiente diagrama muestra las responsabilidades de cada proyecto de la aplicación de ejemplo, junto con las relaciones entre ellos:
La clase FocusEffect
personaliza un control Entry
en el elemento HomePage
en cada proyecto específico de la plataforma. Cada clase FocusEffect
se deriva de la clase PlatformEffect
para cada plataforma. Como resultado, se representa el control Entry
con un color de fondo específico de la plataforma, que cambia cuando el control recibe el foco, como se muestra en las capturas de pantalla siguientes:
Creación del efecto en cada plataforma
En las secciones siguientes se describe la implementación específica de la plataforma de la clase FocusEffect
.
Proyecto de iOS
En el ejemplo de código siguiente se muestra la implementación FocusEffect
para el proyecto de iOS:
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(EffectsDemo.iOS.FocusEffect), nameof(EffectsDemo.iOS.FocusEffect))]
namespace EffectsDemo.iOS
{
public class FocusEffect : PlatformEffect
{
UIColor backgroundColor;
protected override void OnAttached ()
{
try {
Control.BackgroundColor = backgroundColor = UIColor.FromRGB (204, 153, 255);
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}
protected override void OnDetached ()
{
}
protected override void OnElementPropertyChanged (PropertyChangedEventArgs args)
{
base.OnElementPropertyChanged (args);
try {
if (args.PropertyName == "IsFocused") {
if (Control.BackgroundColor == backgroundColor) {
Control.BackgroundColor = UIColor.White;
} else {
Control.BackgroundColor = backgroundColor;
}
}
} catch (Exception ex) {
Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
}
}
}
}
El método OnAttached
establece la propiedad BackgroundColor
del control en color morado claro con el método UIColor.FromRGB
y también almacena este color en un campo. Esta funcionalidad se encapsula en un bloque try
/catch
en caso de que el control al que está asociado el efecto no tenga una propiedad BackgroundColor
. El método OnDetached
no proporciona ninguna implementación porque no se necesita limpieza.
La invalidación de OnElementPropertyChanged
responde a los cambios de propiedad enlazable en el control de Xamarin.Forms. Cuando cambia la propiedad IsFocused
, la propiedad BackgroundColor
del control se cambia a color blanco si el control tiene el foco; en caso contrario, se cambia a color morado claro. Esta funcionalidad se encapsula en un bloque try
/catch
en caso de que el control al que está asociado el efecto no tenga una propiedad BackgroundColor
.
Proyecto de Android
En el ejemplo de código siguiente se muestra la implementación FocusEffect
para el proyecto de Android:
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(EffectsDemo.Droid.FocusEffect), nameof(EffectsDemo.Droid.FocusEffect))]
namespace EffectsDemo.Droid
{
public class FocusEffect : PlatformEffect
{
Android.Graphics.Color originalBackgroundColor = new Android.Graphics.Color(0, 0, 0, 0);
Android.Graphics.Color backgroundColor;
protected override void OnAttached()
{
try
{
backgroundColor = Android.Graphics.Color.LightGreen;
Control.SetBackgroundColor(backgroundColor);
}
catch (Exception ex)
{
Console.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
}
}
protected override void OnDetached()
{
}
protected override void OnElementPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args)
{
base.OnElementPropertyChanged(args);
try
{
if (args.PropertyName == "IsFocused")
{
if (((Android.Graphics.Drawables.ColorDrawable)Control.Background).Color == backgroundColor)
{
Control.SetBackgroundColor(originalBackgroundColor);
}
else
{
Control.SetBackgroundColor(backgroundColor);
}
}
}
catch (Exception ex)
{
Console.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
}
}
}
}
El método OnAttached
llama al método SetBackgroundColor
para establecer el color de fondo del control en verde claro y también almacena este color en un campo. Esta funcionalidad se encapsula en un bloque try
/catch
en caso de que el control al que está asociado el efecto no tenga una propiedad SetBackgroundColor
. El método OnDetached
no proporciona ninguna implementación porque no se necesita limpieza.
La invalidación de OnElementPropertyChanged
responde a los cambios de propiedad enlazable en el control de Xamarin.Forms. Cuando cambia la propiedad IsFocused
, el color de fondo del control se cambia a color blanco si el control tiene el foco; en caso contrario, se cambia a color verde claro. Esta funcionalidad se encapsula en un bloque try
/catch
en caso de que el control al que está asociado el efecto no tenga una propiedad BackgroundColor
.
Proyectos de la Plataforma universal de Windows
En el ejemplo de código siguiente se muestra la implementación FocusEffect
para los proyectos de la Plataforma universal de Windows (UWP):
using Xamarin.Forms;
using Xamarin.Forms.Platform.UWP;
[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(EffectsDemo.UWP.FocusEffect), nameof(EffectsDemo.UWP.FocusEffect))]
namespace EffectsDemo.UWP
{
public class FocusEffect : PlatformEffect
{
protected override void OnAttached()
{
try
{
(Control as Windows.UI.Xaml.Controls.Control).Background = new SolidColorBrush(Colors.Cyan);
(Control as FormsTextBox).BackgroundFocusBrush = new SolidColorBrush(Colors.White);
}
catch (Exception ex)
{
Debug.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
}
}
protected override void OnDetached()
{
}
}
}
El método OnAttached
establece la propiedad Background
del control en cian y la propiedad BackgroundFocusBrush
en blanco. Esta funcionalidad se encapsula en un bloque try
/catch
en caso de que el control al que está asociado el efecto carezca de estas propiedades. El método OnDetached
no proporciona ninguna implementación porque no se necesita limpieza.
Consumo del efecto
El proceso para consumir un efecto desde un proyecto de biblioteca de .NET Standard o de biblioteca compartida de Xamarin.Forms es el siguiente:
- Se declara un control que el efecto va a personalizar.
- Se adjunta el efecto al control agregándolo a la colección
Effects
del control.
Nota:
Una instancia de efecto solo se puede adjuntar a un único control. Por tanto, un efecto se debe resolver dos veces para usarlo en dos controles.
Consumo del efecto en XAML
En el ejemplo de código XAML siguiente se muestra un control Entry
al que se adjunta el elemento FocusEffect
:
<Entry Text="Effect attached to an Entry" ...>
<Entry.Effects>
<local:FocusEffect />
</Entry.Effects>
...
</Entry>
La clase FocusEffect
de la biblioteca de .NET Standard admite el consumo de efectos en XAML, y se muestra en el ejemplo de código siguiente:
public class FocusEffect : RoutingEffect
{
public FocusEffect () : base ($"MyCompany.{nameof(FocusEffect)}")
{
}
}
La clase FocusEffect
crea subclases de la clase RoutingEffect
, que representa un efecto independiente de la plataforma que encapsula un efecto interno que suele ser específico de la plataforma. La clase FocusEffect
llama al constructor de clase base, y se pasa un parámetro que consiste en la concatenación del nombre del grupo de resolución (que se especifica con el atributo ResolutionGroupName
en la clase de efecto), y el identificador único que se ha especificado con el atributo ExportEffect
en la clase de efecto. Por tanto, cuando se inicializa Entry
en tiempo de ejecución, se agrega una nueva instancia de MyCompany.FocusEffect
a la colección Effects
del control.
Los efectos también se pueden adjuntar a los controles mediante un comportamiento, o bien mediante propiedades adjuntas. Para obtener más información sobre cómo adjuntar un efecto a un control mediante un comportamiento, vea EffectBehavior reutilizable. Para obtener más información sobre cómo adjuntar un efecto a un control mediante propiedades adjuntas, vea Pasar parámetros a un efecto.
Consumo del efecto en C#
El control Entry
equivalente en C# se muestra en el ejemplo de código siguiente:
var entry = new Entry {
Text = "Effect attached to an Entry",
...
};
FocusEffect
se adjunta a la instancia de Entry
mediante la adición del efecto a la colección Effects
del control, como se muestra en el ejemplo de código siguiente:
public HomePageCS ()
{
...
entry.Effects.Add (Effect.Resolve ($"MyCompany.{nameof(FocusEffect)}"));
...
}
Effect.Resolve
devuelve un elemento Effect
para el nombre especificado, que es una concatenación del nombre del grupo de resolución (que se especifica con el atributo ResolutionGroupName
en la clase de efecto), y el identificador único que se ha especificado con el atributo ExportEffect
en la clase de efecto. Si una plataforma no proporciona el efecto, el método Effect.Resolve
devolverá un valor que no es null
.
Resumen
En este artículo se ha mostrado cómo crear un efecto que cambia el color de fondo del control Entry
cuando el control recibe el foco.