You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin.Forms CollectionView在Android TV下Focus/Hover事件触发问题咨询

问题解答

实际获得焦点的元素

你在Xamarin.Forms/MAUI中看不到Focus事件触发,本质是因为CollectionView在Android平台的渲染逻辑是基于原生RecyclerView实现的,实际获得焦点的是原生RecyclerView中对应条目的ViewHolder根View,默认Xamarin.Forms/MAUI没有把原生层面的焦点变化事件向上传递到共享代码层的控件,所以你在共享代码里给StackLayout、Label加的Focus事件不会被触发。

实现焦点监听的方案

方案1:Xamarin.Forms 用自定义渲染器实现

第一步:共享代码层定义附加属性

用来接收焦点变化的回调,符合MVVM规范:

public static class FocusExtensions
{
    public static readonly BindableProperty ItemFocusedCommandProperty =
        BindableProperty.CreateAttached("ItemFocusedCommand", typeof(ICommand), typeof(FocusExtensions), null);

    public static ICommand GetItemFocusedCommand(BindableObject view)
    {
        return (ICommand)view.GetValue(ItemFocusedCommandProperty);
    }

    public static void SetItemFocusedCommand(BindableObject view, ICommand value)
    {
        view.SetValue(ItemFocusedCommandProperty, value);
    }
}

第二步:Android平台实现自定义CollectionView渲染器

[assembly: ExportRenderer(typeof(CollectionView), typeof(TvCollectionViewRenderer))]
namespace YourAppNamespace.Droid.Renderers
{
    public class TvCollectionViewRenderer : CollectionViewRenderer
    {
        public TvCollectionViewRenderer(Context context) : base(context) { }

        protected override void OnElementChanged(ElementChangedEventArgs<CollectionView> e)
        {
            base.OnElementChanged(e);
            if (e.NewElement != null && Control != null)
            {
                Control.ChildViewAdded += (s, a) =>
                {
                    // 给每个新增条目开启Android原生聚焦能力
                    a.Child.Focusable = true;
                    a.Child.FocusableInTouchMode = true;
                    // 绑定焦点变化监听
                    a.Child.FocusChange += (sender, focusArgs) =>
                    {
                        if (focusArgs.HasFocus)
                        {
                            // 获取当前聚焦条目的位置和对应数据
                            var position = Control.GetChildAdapterPosition((Android.Views.View)sender);
                            var focusItem = e.NewElement.ItemsSource.Cast<object>().ElementAt(position);
                            // 触发绑定的命令
                            var command = FocusExtensions.GetItemFocusedCommand(e.NewElement);
                            command?.Execute(focusItem);
                        }
                    };
                };
            }
        }
    }
}

第三步:XAML中绑定使用

<CollectionView ItemsSource="{Binding Data}" local:FocusExtensions.ItemFocusedCommand="{Binding ItemFocusedCommand}">
    <!-- 原有ItemsLayout、ItemTemplate等代码保持不变即可 -->
</CollectionView>

之后在ViewModel中实现ItemFocusedCommand,就能实时拿到当前获得焦点的条目数据。


方案2:MAUI 适配方案

逻辑和Xamarin.Forms完全一致,只需要将自定义渲染器替换为MAUI的Handler实现,给RecyclerView的子条目添加同样的焦点监听逻辑即可。

额外适配注意点

Android TV平台所有可交互控件都需要显式设置focusable和focusableInTouchMode为true,才能正确响应D-Pad的焦点跳转,你也可以自定义焦点状态的背景drawable,优化交互体验。

内容的提问来源于stack exchange,提问作者Jono_2007

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 23:36:01