Forum Xamarin Xamarin.Forms

How can I use custom renderers without breaking TalkBack?

ComdyComdy Member
edited March 31 in Xamarin.Forms

While testing accessibility on our new app, we found that our Entry controls decorated with a LabeledBy weren't being read by TalkBack. After some testing we seem to have narrowed down the issue to us using a custom Label renderer. Even having a blank custom renderer prevents TalkBack from reading the label correctly. Below is a stripped down example.

MainPage.xaml

<ContentPage>
    <StackLayout Orientation="Vertical">
        <Label
            x:Name="MyLabel"
            Text="Custom Text Here"
            />
        <Entry
            x:Name="MyEntry"
            />
    </StackLayout>
</ContentPage>

MainPage.xaml.cs

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        AutomationProperties.SetIsInAccessibleTree(MyEntry, true);
        AutomationProperties.SetLabeledBy(MyEntry, MyLabel);
    }
}

In this case, when clicking on MyEntry, TalkBack reads "Edit box for Custom Text Here".

If you add the following custom label renderer:

[assembly: ExportRenderer(typeof(Label), typeof(CustomLabelRenderer))]
namespace CustomRenderer.Droid
{
    public class CustomLabelRenderer : LabelRenderer
    {
        public CustomLabelRenderer(Context context) : base(context) { }
    }
}

Now when clicking on MyEntry, TalkBack simply reads "Edit box".

Is there an additional step we need to take when creating a custom renderer to keep TalkBack functioning correctly?

Note: we have not tested other platforms or other accessibility apps aside from TalkBack.

Best Answer

  • JGoldbergerJGoldberger USMember, Forum Administrator, Xamarin Team, University Xamurai
    edited April 9 Accepted Answer

    Thanks for bringing this up.

    This revealed a bug in the original renderer used for a Label.

    Many Xamarin.Forms controls have 2 renderers, an original renderer and a fast renderer. By default, the fast renderer is used. When you create a custom renderer, if you do not want to change the default behavior, then you need to inherit from the fast renderer in your custom renderer class.

    The fast renderers are in the Xamarin.Forms.Platform.Android.FastRenderers name space. The original renderers are in the Xamarin.Forms.Platform.Android namespace. So what happened here is that by default, the fast renderer is used. By creating the custom renderer and inheriting from Xamarin.Forms.Platform.Android.LabelRenderer, then you are moving to the original renderer, thus exposing the issue in the original renderer.

    [assembly: ExportRenderer(typeof(Label), typeof(CustomLabelRenderer))]
    namespace CustomRenderer.Droid
    {
        public class CustomLabelRenderer : Xamarin.Forms.Platform.Android.FastRenderers.LabelRenderer
        {
            public CustomLabelRenderer(Context context) : base(context) { }
        }
    }
    

    Bug report filed: https://github.com/xamarin/Xamarin.Forms/issues/10282

Answers

  • JGoldbergerJGoldberger USMember, Forum Administrator, Xamarin Team, University Xamurai
    edited April 9 Accepted Answer

    Thanks for bringing this up.

    This revealed a bug in the original renderer used for a Label.

    Many Xamarin.Forms controls have 2 renderers, an original renderer and a fast renderer. By default, the fast renderer is used. When you create a custom renderer, if you do not want to change the default behavior, then you need to inherit from the fast renderer in your custom renderer class.

    The fast renderers are in the Xamarin.Forms.Platform.Android.FastRenderers name space. The original renderers are in the Xamarin.Forms.Platform.Android namespace. So what happened here is that by default, the fast renderer is used. By creating the custom renderer and inheriting from Xamarin.Forms.Platform.Android.LabelRenderer, then you are moving to the original renderer, thus exposing the issue in the original renderer.

    [assembly: ExportRenderer(typeof(Label), typeof(CustomLabelRenderer))]
    namespace CustomRenderer.Droid
    {
        public class CustomLabelRenderer : Xamarin.Forms.Platform.Android.FastRenderers.LabelRenderer
        {
            public CustomLabelRenderer(Context context) : base(context) { }
        }
    }
    

    Bug report filed: https://github.com/xamarin/Xamarin.Forms/issues/10282

  • ComdyComdy Member

    Perfect, swapping out the old renderer for the fast renderer fixed our issue. Thanks!

Sign In or Register to comment.