Context (in case you are not familiar with screen-readers). Screen-readers are available on iOS (VoiceOver) and Android (TalkBack) to support accessibility to people with sever visual impairments. In a nutshell, when the screen-reader is activated and the user touches a UI elements, it gets the “accessibility focus" (the “on tap” event is not fired) and then, when the user double taps, the “on tap” event is fired. In native iOS and Android code it is possible to override methods to specify what to do when a UI element gets or loses the accessibility focus. The methods are called onPopulateAccessibilityEvent (for Android in Java) and accessibilityElementDidBecomeFocused() (for iOS in Swift). Almost the same for C# in Xamarin View.OnPopulateAccessibilityEvent for Android and UIResponder.AccessibilityElementDidBecomeFocused Method for iOS).
Problem 1. I couldn’t find a method in Xamarin Forms to manage the accessibility focus events (when the UI element gets or loses the accessibility focus). Do you know if such methods exist in Xamarin Forms? In case they don’t, we believe that they are very important for the development of accessibile applications, so we would like to suggest to add them. Do you know which is the procedure to suggest the Xamarin team to implement a new functionality?
Problem 2. In order to overcome Problem 1, I am trying to make a Custom Renderer that uses native buttons. The custom rendered seems to be correctly initialized (the right message is logged) and shown on the screen. However, the overridden methods are not called. Code is shown below and available Git Repository. Am I doing something wrong?
MainPage.Xaml.cs (in Forms, CustomViewAccessibility):
using System;
using System.ComponentModel;
using Xamarin.Forms;
namespace CustomViewAccessibility
{
[DesignTimeVisible(false)]
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
ICustomViewRenderer mybutton = new ICustomViewRenderer();
AutomationProperties.SetIsInAccessibleTree(mybutton, true);
stacklayout.Children.Add(mybutton);
}
}
}
ICustomViewRenderer.cs (in Forms, CustomViewAccessibility):
`using System;
using Xamarin.Forms;
namespace CustomViewAccessibility
{
public class ICustomViewRenderer: Button
{
public ICustomViewRenderer()
{
}
}
}`
AndroidCustomView.cs (in Android, CustomViewAccessibility.Android):
`using System;
using Android.Content;
using Android.Views.Accessibility;
using CustomViewAccessibility;
using CustomViewAccessibility.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ICustomViewRenderer), typeof(AndroidCustomView))]
namespace CustomViewAccessibility.Droid
{
public class AndroidCustomView: ButtonRenderer
{
public AndroidCustomView(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if(Control == null)
{
return;
}
Console.WriteLine("PIPPO created from Android");
Control.SetBackgroundColor(Android.Graphics.Color.Orange);
}
public override void OnPopulateAccessibilityEvent(AccessibilityEvent e)
{
base.OnPopulateAccessibilityEvent(e);
if (e.EventType == EventTypes.ViewAccessibilityFocused)
{
Console.WriteLine("PIPPO I am in focus");
}
}
}
}`
IOSCustomView.cs (in iOS, CustomViewAccessibility.iOS):
`using System;
using CustomViewAccessibility;
using CustomViewAccessibility.iOS;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(ICustomViewRenderer), typeof(IOSCustomView))]
namespace CustomViewAccessibility.iOS
{
public class IOSCustomView: ButtonRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if(Control == null)
{
return;
}
Console.WriteLine("PIPPO created from IOS");
Control.BackgroundColor = UIColor.Red;
}
public override void AccessibilityElementDidBecomeFocused()
{
base.AccessibilityElementDidBecomeFocused();
Console.WriteLine("PIPPO I am in focus");
}
}
}`