When you have worked with Xamarin.Forms before you’ll know that the translation from the Forms control to a native control is done by renderers. If you, as a developer, would want to change anything about the way Forms renders it for you, you would have to subclass the whole renderer and create your custom logic for it. This was considered a heavy-weight solution, especially when you would just want to change something basic like a color on a switch control.
What are Effects?
Effects are an easy way to access these native features of controls. They are more or less similar to Custom Renderers, but a bit more lightweight. So in terms of when to use what, keep this in mind:
- Whenever you can achieve the result you want with Effects, use an effect. This will mostly be when just setting a property to change behaviour or achieve some visual effect;
- If you need to influence actual behaviour of the control and thus overriding methods, etc. use a Custom Renderer;
- When you need to replace the control rendered by Xamarin.Forms as a whole by another platform-specific control also use a Custom Renderer.
Now we know what Effects are more or less, let us have a look at how that works in code.
Just like renderers we will also have to subclass certain classes and add our behaviour to it. This is the PlatformEffect class. This class has (amongst others) three properties to work with: Container, Control, Element.
- Container. This property contains the parent control that holds this control.
- Control. Contains the native control that the Xamarin.Forms control is being translated too.
- Element. Contains the Xamarin.Forms control that is being rendered.
Note: the properties are not strongly typed, since they can be applied to every control. It is up to you to cast them to the corresponding type.
Furthermore the PlatformEffect has two main methods:
- OnAttached. This is where the effect gets attached to the Xamarin.Forms control. This is the place where you apply your customisation, do the error and exception handling, etc.
- OnDetached. The reverse method of the one above. Not absolutely necessary in all cases but here you can so some cleaning up or unhooking events.
It also exposes the OnElementPropertyChanged. This way you can update your logic according to property values being changed. Enough talk, lets see it in action!
How to use Effects
Let’s start simple: for iOS you can set the color which is shown when the UISwitch control is set to on (or off). If you want it to match your application style better, you might want to set it. This is something that is not supported by Xamarin.Forms by default. We’ve seen in my previous post that we can do it on the native control, now let’s see how we can do it with an Effect.
First, let’s see what we have to do on the platform side. Create a new file with a class and inherit from the PlatformEffect. Then implement the OnAttached by getting the control and set the native property OnTintColor. My complete class is below.
As you may have noticed I also included two attributes, the ExportEffect attribute is needed to make the effect available for access from another library or binary. You may recognise it from the way custom renderers do this or when you register code for the dependency service.
The first attribute is to make the effect more uniquely identifiable. Technically it isn’t absolutely necessary, but it helps! Why it is needed we will see in a little bit.
In this case the OnDetached can be empty since there is nothing to cleanup.
Effects need a little bit more instruction than custom renderers, you need to apply the effect to a certain control. So go over to your Xamarin.Forms project and here also create a new class which will function as a placeholder for your effect. I’ve named it exactly the same. Only this time, let it inherit from a RoutingEffect. By doing that you need to call the base constructor with the identifier of the effect we created earlier. Have a look at my implementation below.
Notice how I call the base constructor with the identifiers I have attributed the SwitchEffect class in the platform project with.
Finally, to apply this to a control we need to add it to the Effects collection property.
When we now run our project a Switch control will be visible and when you switch it to on, it’s red! Now this can be applied to all different platforms, for all kinds of purposes of course. Let’s have a quick look at how we can also create one for Android.
In the Droid project also create a class SwitchEffect which inherits from the PlatformEffect. The code I have used on Android is seen underneath. It isn’t exactly the same behaviour as on iOS, but you get the idea.
This is just a small example. We can make it a little bit more interesting by adding the ability to consume parameters. This way you can make them more flexible and reusable. Lets add the ability to specify the color right from our Xamarin.Forms project in the XAML.
To do this, we need to make some modifications. We will implement something that is called attached properties you can read all about it under the link, but in the base it comes down to this: create a static class with the bindable properties and implement it, then the property can be applied to any control. This has a small advantage that you do not need to add the effect to the Effects collection, this is done by the attached property for you.
First, I create the static class like this.
This introduces a TrueColor property which can be attached. I have kept the classname similar to the effect. This can both be confusing as well as helping you correlate the two together. Use it wisely!
The class itself isn’t all that much, we create a property with a getter and a setter and a handler for when the value is changed at runtime. I have reused the Xamarin.Forms.Color object so we use the power of what that has to offer and create any color like that, instead of limiting ourselves to certain colors.
Now in our platform projects, we of course need to pick up this color and use it to customise our control. Below you can find how I changed the code in both Android and iOS. Nothing much changed, I just get the color from the property and use that instead of hard coding it.
Finally, we can lose our Effects from the control and just specify the attached property. The Effect will be implied by that.
I kept the previous code in comments so you can see the difference. When we now run the project we will see the color has changed to yellow and when we change it to another color it will reflect in our app. Because I used the Xamarin.Forms.Color we can use both named colors but also HEX codes.
Luckily for you, a couple of smart guys and myself have created some common effects for you and bundled them into a library! Have a look at the Github page. It has now been assimilated by the Xamarin community and is known as the FormsCommunityToolkit/Effects. It will be packaged as a NuGet seen, if it hasn’t already. You are more than welcome to improve or extend it with some PRs.
All the code I have used (and borrowed from the library) can be found on it’s own repo here.