Xamarin.Forms (Keyboard Accessibility) - Change background color/highlighting of a view when it has the focus and issue with tap event triggering (when using keyboard))

Uragonda, Rajesh 31 Reputation points
2021-10-29T11:37:54.517+00:00

Based on our requirement we need to make the app keyboard accessible (navigate using tab key and arrow keys) and change the background color of the view/layout when it has focus.

The view/layout can be made accessible by adding AutomationProperties.IsInAccessibleTree="True" to it.
But the issue we are facing here is when ever a view/layout has focus we are unable to change the background color of the view/layout.

For example if a user is navigating through items in a list view using index or arrows keys (on keyboard) we need to add a different background color(visual indicator) to an item when it has the focus (by default there is a light grey color background which we want to change).

Below are the views/layouts for which we are unable to change the background color when it has focus and tap event is not fired when using keyboard enter/space keys :
-List item in a listview.
-StackLayout
-Label
-Grid
-Frame
-CollectionView
We have tried FocusEffect, custom renderers and visual state managers to change background color. But its not working.
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/effects/creating
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/visual-state-manager
https://github.com/PureWeen/A11YTools

Could you please let us know how can we achieve this?

Note : For Button and Entry we are able to change the background color when it has the focus using FocusEffect and visual state managers.
As of now our observations are made on Android and yet to test on iOS devices.

Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,364 questions
{count} votes

3 answers

Sort by: Most helpful
  1. Wenyan Zhang (Shanghai Wicresoft Co,.Ltd.) 32,386 Reputation points Microsoft Vendor
    2021-11-04T03:19:28.44+00:00

    Hello,

    Welcome to our Microsoft Q&A platform!

    I check MainPage and notice that the VisualState of Frame is not triggered. The Class of visual states that are defined in Xamarin.Forms does not contain Frame, so we have to define our own visual states. You could refer to the following code

    XAML(give this Frame a name)

    <Frame x:Name="MyFrame" AutomationProperties.IsInAccessibleTree="True" Margin="0,10,0,0">  
    

    CodeBehind

      private void TapGestureRecognizer_Tapped(object sender, EventArgs e)  
      {  
          App.Current.MainPage.DisplayAlert("Alert", "Alert message", "OK");  
          VisualStateManager.GoToState(MyFrame, "Focused");  
      }  
    

    Best Regards,
    Wenyan Zhang


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  2. Wenyan Zhang (Shanghai Wicresoft Co,.Ltd.) 32,386 Reputation points Microsoft Vendor
    2022-01-04T06:28:55.49+00:00

    Hello,

    Welcome to our Microsoft Q&A platform!

    Sorry for my late response. We have been able to change the background color of visual elements (such as Frame, StackLayout etc) using custom renderer.
    Same concept can be applied to other visual elements that are not working out-of-the-box with Xamarin Forms. You just need to access the Android APIs which can be done by using a renderer.
    LabelRenderer.cs

    using Android.Content;  
    using VisualFocusApp.Droid;  
    using Xamarin.Forms;  
    using Xamarin.Forms.Platform.Android.FastRenderers;  
      
        [assembly: ExportRenderer(typeof(Label), typeof(MyLabelRenderer))]  
        namespace VisualFocusApp.Droid  
        {  
        public class MyLabelRenderer : LabelRenderer  
        {  
            public MyLabelRenderer(Context context) : base(context)  
            {  
      
            }  
            protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Label> e)  
            {  
                base.OnElementChanged(e);  
      
                if (Control != null)  
                {  
                    Control.FocusChange += Control_FocusChange;  
                }  
            }  
      
            private void Control_FocusChange(object sender, FocusChangeEventArgs e)  
            {  
      
                if (Control.HasFocus)  
                {  
                    Control.SetBackgroundColor(Android.Graphics.Color.Red);  
                }  
                else  
                {  
                    Control.SetBackgroundColor(Android.Graphics.Color.White);  
                }  
            }  
        }  
    }  
    

    CustomStackLayoutRenderer.cs

    using Android.Content;  
    using VisualFocusApp.Droid;  
    using Xamarin.Forms;  
    using Xamarin.Forms.Platform.Android;  
      
    [assembly: ExportRenderer(typeof(StackLayout), typeof(CustomStackLayoutRenderer))]  
    namespace VisualFocusApp.Droid  
    {  
        public class CustomStackLayoutRenderer : VisualElementRenderer<StackLayout>  
        {  
            public CustomStackLayoutRenderer(Context context) : base(context)  
            {  
      
            }  
      
            protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)  
            {  
                base.OnElementChanged(e);  
                if (this != null)  
                {  
                    FocusChange += Control_FocusChange;  
                }  
            }  
      
            private void Control_FocusChange(object sender, FocusChangeEventArgs e)  
            {  
      
                if (HasFocus)  
                {  
                    SetBackgroundColor(Android.Graphics.Color.Red);  
                }  
                else  
                {  
                    SetBackgroundColor(Android.Graphics.Color.White);  
                }  
            }  
        }  
    }  
    

    CustomFrameRenderer.cs

    using Android.Content;  
    using VisualFocusApp.Droid;  
    using Xamarin.Forms;  
    using Xamarin.Forms.Platform.Android.FastRenderers;  
      
    [assembly: ExportRenderer(typeof(Frame), typeof(CustomFrameRenderer))]  
    namespace VisualFocusApp.Droid  
    {  
        public class CustomFrameRenderer : FrameRenderer  
        {  
            public CustomFrameRenderer(Context context) : base(context)  
            {  
      
            }  
      
            protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Frame> e)  
            {  
                base.OnElementChanged(e);  
      
                if (Control != null)  
                {  
                    Control.FocusChange += Control_FocusChange;  
                }  
            }  
      
            private void Control_FocusChange(object sender, FocusChangeEventArgs e)  
            {  
      
                if (Control.HasFocus)  
                {  
                    Control.SetBackgroundColor(Android.Graphics.Color.Red);  
                }  
                else  
                {  
                    Control.SetBackgroundColor(Android.Graphics.Color.White);  
                }  
            }  
        }  
    }  
    

    We will look into iOS, it doesn’t work out of the box like android, then it might take a while to figure it out.

    Best Regards,
    Wenyan Zhang


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  3. Wenyan Zhang (Shanghai Wicresoft Co,.Ltd.) 32,386 Reputation points Microsoft Vendor
    2022-02-17T08:31:44.687+00:00

    Hello,

    Welcome to our Microsoft Q&A platform!

    You could try changing backgroundcolor on iOS, according to the following solution:

    First, you need to enable Full Keyboard Access in the Settings > Accessibility > Keyboards on an iOS device (this does nothing on a simulator)
    Once tested on device, getting the background color to change with Tab/Arrow key navigation (Tab navigates to groups, Arrows navigate linearly by direction of arrow used) was simple pairing it with a keyboard.
    **CustomLabelRenderer **(The same concept of custom renderer should work for the other elements)

    [assembly: ExportRenderer(typeof(Label), typeof(CustomLabelRenderer))]  
    namespace VisualStateManagerDemo.iOS  
    {  
        public class CustomLabelRenderer: LabelRenderer  
        {  
            UIColor originalColor;  
            protected override void OnElementChanged(ElementChangedEventArgs<Label> e)  
            {  
                base.OnElementChanged(e);  
                if (Control != null)  
                    originalColor = Control.BackgroundColor;  
            }  
    
        public override bool CanBecomeFocused => true;  
    
        public override void DidUpdateFocus(UIFocusUpdateContext context, UIFocusAnimationCoordinator coordinator)  
        {  
            base.DidUpdateFocus(context, coordinator);  
            if (Control.BackgroundColor == originalColor)  
                Control.BackgroundColor = UIColor.Red;  
            else  
                Control.BackgroundColor = originalColor;  
        }  
    }  
    }  
    

    Best Regards,
    Wenyan Zhang


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.