Xamarin.Forms 2.1: Effects
23 January 2016

Xamarin.Forms 2.1: Effects

One of the biggest challanges in creating a Xamarin.Forms compelling application is the customization of the look & feel of it. To this date, you could use styles to change some properties of the elements or CustomRenderers to change completely it appearance. But CustomRenderers allow developers to override completely the flow of rendering a control in every platform, thus generating a lot of work to do.

In the last version of Xamarin.Forms, 2.1, a new tool to customize controls is introduced: Effects.

Effects

Effects allow a developer to write little, atomic pieces of code that could be easily reusable across controls to customize it native look & feel, based on the native control, without need to rewrite it.

An Effect is a class implementing the PlatformEffect abstract class from Xamarin.Forms.Platform namespace. It provides two overridable methods by default: OnAttached and OnDetached.

public class FocusEffect : PlatformEffect
{
    protected override void OnAttached()
    {
    }
    protected override void OnDetached()
    {
    }
}

PlatformEffect exposes also a Control instance, containing the native control generated by Xamarin.Forms, so you can change the properties you need, for example to add a border to it, for example in iOS platform:

protected override void OnAttached()
{
    Control.Layer.BorderColor = new CGColor(0, 0, 1);
    Control.Layer.BorderWidth = 2;
}

When you finish writing your effects you need to make them available in your core PCL to add it to your views. To make things work, first you need to expose your effects from the platform projects using two assembly attributes: ResolutionGroupName and ExportEffect. You can place these on every one of your platform projects assemblyInfo.cs file.

ResolutionGroupName is an agregator, it groups all your effects under the same umbrella, so your names don't collide with third party effects. Then, for each Effect you had, you need to export it type and name:

[assembly: ResolutionGroupName("DevsDNA")]
[assembly: ExportEffect(typeof(FocusEffect), "FocusEffect")]

I think Effects are an awesome idea from the guys at Xamarin.Forms, but here is one part i'm not entirely happy with. To add an Effect to your view, you need to add it to an IList<Effect> collection called Effects in each view. As you don't have a way to select an Effect located in the platform projects, Xamarin.Forms provides a Resolver who use the Group and Effect name to obtain in runtime the correct Effect instance:

entryText.Effects.Add(Effect.Resolve("DevsDNA.FocusEffect"));

And that is, you need to take care to not missspell it, or the effect simply will not be applied. No fails, as you can define an Effect only in one platform, when an Effect is not present in a platform, the Resolve method take care to return a valid, empty effect that simply does nothing. 

The above sample changes the look & feel of a control adding a cyan border to it, but you can also listen to changes in other properties to apply your own changes, overriding the OnElementPropertyChanged method of PlatformEffect. This way you can change the control background based on the focused property:

public class FocusEffect : PlatformEffect
{
    protected override void OnAttached()
    {
    }
    protected override void OnDetached()
    {
    }
    protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
    {
        base.OnElementPropertyChanged(args);
        if (args.PropertyName == "IsFocused")
        {
            if (Control.BackgroundColor == UIColor.Cyan)
                Control.BackgroundColor = UIColor.White;
            else
                Control.BackgroundColor = UIColor.Cyan;
        }
    }
}

Or even handle events to change the background:

public class FocusEffect : PlatformEffect
{
    protected override void OnAttached()
    {
        Control.GotFocus += Control_GotFocus;
        Control.LostFocus += Control_LostFocus;
    }
    protected override void OnDetached()
    {
        Control.GotFocus -= Control_GotFocus;
        Control.LostFocus -= Control_LostFocus;
    }
    private void Control_LostFocus(object sender, System.Windows.RoutedEventArgs e)
    {
        (Control as System.Windows.Controls.Control).Background = new SolidColorBrush(Colors.White);
    }
    private void Control_GotFocus(object sender, System.Windows.RoutedEventArgs e)
    {
        (Control as System.Windows.Controls.Control).Background = new SolidColorBrush(Colors.Cyan);
    }
}

This allows you to easily write down complex customization scenarios, even with interactions.

You can download a complete sample about using Effects in Xamarin.Forms from my GitHub:

gitHub-download-butt...

Happy Coding!

 

 

Related

0 ( 0 reviews)

Post a Comment