Custom Picker Renderer on Android
The default Picker
view for Android in Xamarin.Forms includes an underline:
To get rid of it, a custom renderer is required:
[assembly: ExportRenderer(typeof(BorderlessPicker), typeof(BorderlessPickerRenderer))]
namespace AndroidPickerRenderer.Droid.Renderers
{
public class BorderlessPickerRenderer : PickerRenderer
{
public BorderlessPickerRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
Control.Background = null;
}
}
}
}
The target BorderlessPicker
control can trivially derive from the original Picker
control:
public class BorderlessPicker : Picker
{
}
The new control is rendered without the underline as desired (you can always add a Xamarin.Forms ImageButton
as a dropdown icon on the right if you want to):
However, the new control will have another undesired side effect in rendering. This was the popup of the original control:
The new control with the custom renderer opens a different popup:
How is this possible? Why would the rendering change if the new renderer derives from the original one, and only prevents the underline from rendering?
This can happen because there are two renderers for Picker
on Android. One in the Xamarin.Forms.Platform.Android
namespace where most renderers reside. And a different one in the Xamarin.Forms.Platform.Android.AppCompat
namespace.
As it turns out, the latter is the default one. And the custom renderer above happens to derive from the former. This is likely to happen not only because you expect the renderer to be in the same namespace as most others, but also because the ElementChangedEventArgs
class used in the overridden method is in that same namespace.
To get the same popup as by default, the base renderer must be derived from the AppCompat
sub-namespace:
[assembly: ExportRenderer(typeof(BorderlessPicker), typeof(BorderlessPickerRenderer))]
namespace AndroidPickerRenderer.Droid.Renderers
{
public class BorderlessPickerRenderer
: Xamarin.Forms.Platform.Android.AppCompat.PickerRenderer
{
public BorderlessPickerRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
Control.Background = null;
}
}
}
}
You can find a working sample in my GitHub repository. Both custom renderers are implemented as separate commits.
Creating a custom renderer for a Xamarin.Forms control might result in other changes in addition to the ones intentionally implemented. If that happens to you, make sure you are deriving from the correct base renderer.