Criando um efeito
Efeitos simplificam a personalização de um controle. Este artigo demonstra como criar um efeito que altera a cor da tela de fundo do controle Entry quando o controle obtém foco.
O processo para criar um efeito em cada projeto específico da plataforma é o seguinte:
- Crie uma subclasse da classe
PlatformEffect
. - Substitua o método
OnAttached
e escreva a lógica para personalizar o controle. - Substitua o método
OnDetached
e escreva a lógica para limpar a personalização do controle se necessário. - Adicione um atributo
ResolutionGroupName
à classe do efeito. Esse atributo define um namespace para os efeitos que abrange toda a empresa, evitando conflitos com outros efeitos de mesmo nome. Observe que esse atributo só pode ser aplicado uma vez por projeto. - Adicione um atributo
ExportEffect
à classe do efeito. Esse atributo registra o efeito com uma ID exclusiva que é usada por Xamarin.Forms, juntamente com o nome do grupo, para localizar o efeito antes de aplicá-lo a um controle. O atributo utiliza dois parâmetros – o nome do tipo de efeito e uma cadeia de caracteres exclusiva que será usada para localizar o efeito antes de aplicá-lo a um controle.
O efeito, em seguida, poderá ser consumido sendo anexado ao controle apropriado.
Observação
O fornecimento de um efeito em cada projeto de plataforma é opcional. Tentar usar um efeito quando não há um efeito registrado retornará um valor não nulo que não faz nada.
O aplicativo de exemplo demonstra um FocusEffect
que altera a cor da tela de fundo de um controle quando ele obtém o foco. O seguinte diagrama ilustra as responsabilidades de cada projeto no aplicativo de exemplo, bem como as relações entre elas:
Um controle Entry
no HomePage
é personalizado pela classe FocusEffect
em cada projeto específico da plataforma. Cada classe FocusEffect
é derivada da classe PlatformEffect
de cada plataforma. Isso faz com que o controle Entry
seja renderizado com uma cor da tela de fundo específica da plataforma, que muda quando o controle obtém foco, conforme mostrado nas capturas de tela seguir:
Criando o efeito em cada plataforma
As seções a seguir abordam a implementação da classe FocusEffect
específica da plataforma.
Projeto do iOS
O exemplo de código a seguir mostra a implementação de FocusEffect
para o projeto do 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);
}
}
}
}
O método OnAttached
define a propriedade BackgroundColor
do controle como roxo claro com o método UIColor.FromRGB
e também armazena essa cor em um campo. Essa funcionalidade é encapsulada em um bloco try
/catch
caso o controle a que o efeito está anexado não tenha uma propriedade de BackgroundColor
. Nenhuma implementação é fornecida pelo método OnDetached
porque nenhuma limpeza é necessária.
A OnElementPropertyChanged
substituição responde às alterações de propriedade associável no Xamarin.Forms controle. Quando a propriedade IsFocused
é alterada, a propriedade BackgroundColor
do controle será alterada para branco se o controle estiver em foco, caso contrário, é alterada para roxo claro. Essa funcionalidade é encapsulada em um bloco try
/catch
caso o controle a que o efeito está anexado não tenha uma propriedade de BackgroundColor
.
Projeto do Android
O exemplo de código a seguir mostra a implementação de FocusEffect
para o projeto do 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);
}
}
}
}
O método OnAttached
chama o método SetBackgroundColor
para definir a cor da tela de fundo do controle como verde claro e também armazena essa cor em um campo. Essa funcionalidade é encapsulada em um bloco try
/catch
caso o controle a que o efeito está anexado não tenha uma propriedade de SetBackgroundColor
. Nenhuma implementação é fornecida pelo método OnDetached
porque nenhuma limpeza é necessária.
A OnElementPropertyChanged
substituição responde às alterações de propriedade associável no Xamarin.Forms controle. Quando a propriedade IsFocused
é alterada, a cor da tela de fundo do controle será alterada para branco se o controle estiver em foco, caso contrário, é alterada para verde claro. Essa funcionalidade é encapsulada em um bloco try
/catch
caso o controle a que o efeito está anexado não tenha uma propriedade de BackgroundColor
.
Projetos da Plataforma Universal do Windows
O exemplo de código a seguir mostra a implementação de FocusEffect
para projetos da UWP (Plataforma Universal do Windows):
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()
{
}
}
}
O método OnAttached
define a propriedade Background
do controle como ciano e define a propriedade BackgroundFocusBrush
como branco. Essa funcionalidade é encapsulada em um bloco try
/catch
caso o controle a que o efeito está anexado não tenha essas propriedades. Nenhuma implementação é fornecida pelo método OnDetached
porque nenhuma limpeza é necessária.
Consumindo o efeito
O processo para consumir um efeito de uma biblioteca .NET Standard ou de um Xamarin.Forms projeto de Biblioteca Compartilhada é o seguinte:
- Declare um controle que será personalizado pelo efeito.
- Anexe o efeito ao controle adicionando-o à coleção
Effects
do controle.
Observação
Uma instância de efeito pode ser anexada somente a um único controle. Portanto, um efeito deve ser resolvido duas vezes para usá-lo em dois controles.
Consumindo o efeito em XAML
O exemplo de código XAML abaixo mostra um controle Entry
ao qual o FocusEffect
está anexado:
<Entry Text="Effect attached to an Entry" ...>
<Entry.Effects>
<local:FocusEffect />
</Entry.Effects>
...
</Entry>
A classe FocusEffect
na biblioteca do .NET Standard dá suporte ao consumo do efeito em XAML e é mostrado no exemplo de código a seguir:
public class FocusEffect : RoutingEffect
{
public FocusEffect () : base ($"MyCompany.{nameof(FocusEffect)}")
{
}
}
A classe FocusEffect
cria subclasses da classe RoutingEffect
, que representa um efeito independente de plataforma que encapsula um efeito interno, que é geralmente é específico da plataforma. A classe FocusEffect
chama o construtor da classe base, passando um parâmetro composto por uma concatenação do nome do grupo de resolução (especificado usando o atributo ResolutionGroupName
na classe do efeito) e pela ID exclusiva que foi especificada usando o atributo ExportEffect
na classe do efeito. Portanto, quando o Entry
é inicializado em runtime, uma nova instância do MyCompany.FocusEffect
é adicionada à coleção Effects
do controle.
Efeitos também podem ser anexados a controles usando um comportamento ou usando propriedades anexadas. Para obter mais informações sobre como anexar um efeito a um controle usando um comportamento, confira EffectBehavior reutilizável. Para obter mais informações sobre como anexar um efeito a um controle usando propriedades anexadas, confira Passar parâmetros para um efeito.
Consumindo o efeito em C#
O Entry
equivalente em C# é mostrado no exemplo de código a seguir:
var entry = new Entry {
Text = "Effect attached to an Entry",
...
};
O FocusEffect
é anexado à instância de Entry
adicionando o efeito à coleção Effects
do controle, conforme demonstrado no exemplo de código a seguir:
public HomePageCS ()
{
...
entry.Effects.Add (Effect.Resolve ($"MyCompany.{nameof(FocusEffect)}"));
...
}
O Effect.Resolve
retorna um Effect
para o nome especificado, que é uma concatenação do nome do grupo de resolução (especificado usando o atributo ResolutionGroupName
na classe do efeito) e pela ID exclusiva que foi especificada usando o atributo ExportEffect
na classe do efeito. Se uma plataforma não fornecer o efeito, o método Effect.Resolve
retornará um valor não null
.
Resumo
Este artigo demonstrou como criar um efeito que altera a cor da tela de fundo do controle Entry
quando o controle obtém foco.