Developers can use Effects in Xamarin Forms to customize native controls and add some styling of their own. But why not simply use a custom renderer to achieve the same thing? While that is certainly possible there are some benefits to Effects.
Why would you use Effects?
Contrary to a custom renderer that always targets controls of a specific type an effect can be re-used throughout your app. Another advantage is that you can parameterize your effects with additional data. Most people use effects to simply change properties of a native control that aren’t yet made available through the existing Xamarin Forms controls. Effects work by attaching/detaching them to/from a Xamarin Forms control.
To get a quick idea of how that looks in XAML:
You can add multiple effects to a control. As you might have noticed this gives you a lot of freedom because unlike a custom renderer you specifically decide which control gets the effect without any need to subclass it. When creating an effect it is not mandatory to implement it in each platform. You can create an effect and choose to only implement it in iOS. It’s completely optional.
Creating our first Effect
We’re going to create an effect which puts an awesome cat as the background image of an
Entry. To get started we create a class in our PCL that inherits from
RoutingEffect which has no code but we’re going to use it to make sure we can consume our effect in our XAML code:
This class calls the
RoutingEffect base class constructor and passes in a string parameter. Take note of this parameter as you will be seeing it later on in this sample. It is used to initialize an instance of this effect at runtime and is a concatenation of 2 variables we’ll be seeing in the platform-specific implementations of our effect.
Creating the platform-specific code
To actually create the custom Effect you need to subclass the
PlatformEffect class in your platform-specific projects and each platform-specific
PlatformEffect class subsequently exposes the following properties for you to use:
Container– the platform-specific control being used to implement the layout.
Control– the platform-specific control.
Element– the Xamarin.Forms control that’s being rendered.
When inheriting from
PlatformEffect you also gain access to two methods for you to override:
OnDetached. You can use
OnAttached to apply your effect and
OnDetached to clean up your effect. Now let’s create our effect shall we?
On iOS we implement it as follows:
On Android our effect code looks like this:
As you can see there are 2
assembly attributes decorating our effect.
You might remember I talked about passing a string value into the constructor of your
RoutingEffect class in your PCL a bit higher up in this post. These two values uniquely identify this specific effect and are the linking pin between your PCL code and your platform-specific code. These two values need to match the string in your PCL code (concatenated with a period character in between). It’s what makes the whole thing come together!
Obviously this leaves a lot to be desired and it serves solely as a sample of how effects work and I can’t call this one production-worthy :) There are however ways you can implement your effects that can be a lot more useful. Some samples include:
- Creating drop shadows on visual elements
- Setting keyboard types on an entry
- Setting auto-correct settings on an entry
Sharing is caring
Why did I create such a useless effect to show off how effects work instead of creating one from the list above? Because the ones I mentioned have already been created by other people! The beauty of Effects is that you can easily share them which is exactly what some people have done. The FormsCommunityToolkit is a project that tries to aggregate Effects (among other things) and you can contribute to it if you’ve created one. Since it already contains some nice ones you don’t have to recreate them yourself.
A word of warning…
You can attach effects to any type of view however you need to take care of the fact that someone might attach your effect to a
Button even though it was meant to work with an
Entry control. Xamarin Forms does nothing to stop this behaviour. You will need to take care of graceful exception handling yourself just in case this type of thing occurs either by also implementing it for
Button or by silently (yet gracefully) failing.