如何防止iOS Voiceover在Flyout菜单未显示时读取菜单项
解决Xamarin Forms 5原生Flyout菜单Voiceover读取未显示菜单项的问题
核心思路是在Flyout菜单收起时,通过原生平台的辅助功能API,将菜单项所在的视图标记为不可被辅助功能访问,展开时恢复可访问状态。
iOS 平台处理
iOS的FlyoutPage对应原生的UISplitViewController,侧边栏菜单在收起时仍会被Voiceover扫描到。我们可以通过自定义FlyoutPageRenderer,监听菜单的展开/收起状态,动态设置菜单项容器的辅助属性:
[assembly: ExportRenderer(typeof(FlyoutPage), typeof(CustomFlyoutPageRenderer))] namespace YourAppNamespace.iOS.Renderers { public class CustomFlyoutPageRenderer : FlyoutPageRenderer { protected override void OnElementChanged(VisualElementChangedEventArgs e) { base.OnElementChanged(e); if (e.NewElement != null) { ((FlyoutPage)e.NewElement).IsPresentedChanged += OnFlyoutIsPresentedChanged; UpdateMenuAccessibility(false); } } private void OnFlyoutIsPresentedChanged(object sender, EventArgs e) { var flyoutPage = sender as FlyoutPage; UpdateMenuAccessibility(flyoutPage.IsPresented); } private void UpdateMenuAccessibility(bool isPresented) { if (SplitViewController?.ViewControllers.Length > 1) { var menuViewController = SplitViewController.ViewControllers[0]; menuViewController.View.IsAccessibilityElement = isPresented; menuViewController.View.AccessibilityElementsHidden = !isPresented; } } } }
Android 平台处理
Android的Flyout基于DrawerLayout,抽屉关闭时需要将抽屉内容视图的ImportantForAccessibility属性设置为NoHideDescendants,阻止Voiceover读取内部元素:
[assembly: ExportRenderer(typeof(FlyoutPage), typeof(CustomFlyoutPageRenderer))] namespace YourAppNamespace.Droid.Renderers { public class CustomFlyoutPageRenderer : FlyoutPageRenderer { private DrawerLayout _drawerLayout; public CustomFlyoutPageRenderer(Context context) : base(context) { } protected override void OnElementChanged(ElementChangedEventArgs<FlyoutPage> e) { base.OnElementChanged(e); if (e.NewElement != null) { _drawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawer_layout); ((FlyoutPage)e.NewElement).IsPresentedChanged += OnFlyoutIsPresentedChanged; UpdateMenuAccessibility(false); } } private void OnFlyoutIsPresentedChanged(object sender, EventArgs e) { var flyoutPage = sender as FlyoutPage; UpdateMenuAccessibility(flyoutPage.IsPresented); } private void UpdateMenuAccessibility(bool isPresented) { if (_drawerLayout != null) { var drawerView = _drawerLayout.GetChildAt(1); if (drawerView != null) { drawerView.ImportantForAccessibility = isPresented ? ImportantForAccessibility.Auto : ImportantForAccessibility.NoHideDescendants; } } } } }
额外注意事项
- 确保自定义Renderer所在的命名空间正确,并且项目中引用了
Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.Android命名空间。 - 如果Flyout菜单使用了自定义菜单项模板,需确保模板中的控件没有强制设置
IsAccessibilityElement="True",否则会覆盖上述设置。
内容的提问来源于stack exchange,提问作者Jeffery Jones
相关产品推荐
相关产品推荐

