Xamarin.Forms UWP 中 ListView 项是如何获得焦点的?
Xamarin.Forms 列表模板项可聚焦功能实现原理及源码说明
实现原理
- Xamarin.Forms 所有可视控件均继承自
VisualElement基类,基类提供了IsFocusable绑定属性控制控件是否可获得焦点。非交互类被动控件(如Layout、Label等无默认点击响应的控件)默认将该属性设为 false,Button、ImageButton等交互类活跃控件默认设为 true。 - ListView、CollectionView这类列表控件的模板化项,并不是直接将你定义的DataTemplate内容渲染到视图树,而是会在模板外层包裹一层原生平台的项容器:ListView对应
ViewCell容器,CollectionView对应可选项容器。列表控件会自动将外层容器的IsFocusable属性设为 true,同时内置了键盘导航的事件处理逻辑,拦截Tab、方向键输入后按顺序切换不同项容器的焦点。 - 就算DataTemplate内部全部是不可聚焦的被动控件,外层容器本身的可聚焦属性依然生效,所以整个项可以在键盘导航时获得焦点。
源码调用逻辑说明
核心属性定义
VisualElement中IsFocusable属性的基础定义如下:
public static readonly BindableProperty IsFocusableProperty = BindableProperty.Create( propertyName: nameof(IsFocusable), returnType: typeof(bool), declaringType: typeof(VisualElement), defaultValue: true);
不同控件会在构造函数中覆盖该属性的默认值,比如Label的构造函数中会主动设置SetValue(IsFocusableProperty, false)关闭可聚焦能力。
ListView 相关实现
- 跨平台层的
ViewCell类默认将IsEnabled、IsFocusable均设为true,同时对外暴露Tapped、Selected等状态事件。 - 各平台的
ViewCellRenderer渲染器在生成本地视图时,会自动给原生视图设置可聚焦属性:- Android平台会设置原生View的
Focusable = true、FocusableInTouchMode = true,同时绑定选中态样式选择器 - iOS平台会设置原生UITableViewCell的
SelectionStyle不为None,支持响应焦点切换
- Android平台会设置原生View的
- 列表控件的平台渲染器会重写键盘输入事件处理方法,捕获方向键、Tab键输入后计算下一个要聚焦的项索引,调用对应项容器的
RequestFocus()方法完成焦点切换。
CollectionView 相关实现
- CollectionView继承自
SelectableItemsView,无论SelectionMode是否设置为None,项容器的可聚焦属性默认都会开启,仅选择态的展示逻辑会跟随SelectionMode变化。 - 项复用逻辑中,每次将数据项绑定到复用容器时,都会重新校验容器的
IsFocusable属性为true,不会被子模板内控件的属性覆盖。 - 内置的
ItemsViewLayout布局类会维护所有可见项的位置索引,为键盘导航时的焦点顺序计算提供坐标依据。
内容的提问来源于stack exchange,提问作者kyuubi
相关产品推荐
相关产品推荐

