鸿蒙开发入门day15-焦点事件

(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,还请三连支持一波哇ヾ(@^∇^@)ノ)

目录

焦点事件

基础概念与规范

基础概念

走焦规范

走焦算法

获焦/失焦事件

设置组件是否可获焦

默认焦点

页面的默认焦点

容器的默认焦点

页面/容器整体获焦时的焦点链

焦点样式

主动获焦/失焦

焦点组与获焦优先级


 

焦点事件

基础概念与规范

基础概念

焦点、焦点链和走焦

  • 焦点:指向当前应用界面上唯一的一个可交互元素,当用户使用键盘、电视遥控器、车机摇杆/旋钮等非指向性输入设备与应用程序进行间接交互时,基于焦点的导航和交互是重要的输入手段。
  • 焦点链:在应用的组件树形结构中,当一个组件获得焦点时,从根节点到该组件节点的整条路径上的所有节点都会被视为处于焦点状态,形成一条连续的焦点链。
  • 走焦:指焦点在应用内的组件之间转移的行为。这一过程对用户是透明的,但开发者可以通过监听onFocus(焦点获取)和onBlur(焦点失去)事件来捕捉这些变化。关于走焦的具体方式和规则。

焦点态

用来指向当前获焦组件的样式。

  • 显示规则:默认情况下焦点态不会显示,只有当应用进入激活态后,焦点态才会显示。因此,虽然获得焦点的组件不一定显示焦点态(取决于是否处于激活态),但显示焦点态的组件必然是获得焦点的。大部分组件内置了焦点态样式,开发者同样可以使用样式接口进行自定义,一旦自定义,组件将不再显示内置的焦点态样式。在焦点链中,若多个组件同时拥有焦点态,系统将采用子组件优先的策略,优先显示子组件的焦点态,并且仅显示一个焦点态。
  • 进入激活态:仅使用外接键盘按下TAB键时才会进入焦点的激活态,进入激活态后,才可以使用键盘TAB键/方向键进行走焦。首次用来激活焦点态的TAB键不会触发走焦。
  • 退出激活态:当应用收到点击事件时(包括手指触屏的按下事件和鼠标左键的按下事件),焦点的激活态会退出。

层级页面

层级页面是焦点框架中特定容器组件的统称,涵盖Page、Dialog、SheetPage、ModalPage、Menu、Popup、NavBar、NavDestination等。这些组件通常具有以下关键特性:

  • 视觉层级独立性:从视觉呈现上看,这些组件独立于其他页面内容,并通常位于其上方,形成视觉上的层级差异。
  • 焦点跟随:此类组件在首次创建并展示之后,会立即将应用内焦点抢占。
  • 走焦范围限制:当焦点位于这些组件内部时,用户无法通过键盘按键将焦点转移到组件外部的其他元素上,焦点移动仅限于组件内部。

在一个应用程序中,任何时候都至少存在一个层级页面组件,并且该组件会持有当前焦点。当该层级页面关闭或不再可见时,焦点会自动转移到下一个可用的层级页面组件上,确保用户交互的连贯性和一致性。

说明

Popup组件在focusable属性(组件属性,非通用属性)为false的时候,不会有第2条特性。

NavBar、NavDestination没有第3条特性,对于它们的走焦范围,是与它们的首个父层级页面相同的。

根容器

根容器是层级页面内的概念,当某个层级页面首次创建并展示时,根据层级页面的特性,焦点会立即被该页面抢占。此时,该层级页面所在焦点链的末端节点将成为默认焦点,而这个默认焦点通常位于该层级页面的根容器上。

在缺省状态下,层级页面的默认焦点位于其根容器上,但开发者可以通过defaultFocus属性来自定义这一行为。

当焦点位于根容器时,首次按下TAB键不仅会使焦点进入激活状态,还会触发焦点向子组件的传递。如果子组件本身也是一个容器,则焦点会继续向下传递,直至到达叶子节点。传递规则是:优先传递给上一次获得焦点的子节点,如果不存在这样的节点,则默认传递给第一个子节点。

走焦规范

根据走焦的触发方式,可以分为主动走焦和被动走焦。

主动走焦

指开发者/用户主观行为导致的焦点移动,包括:使用外接键盘的按键走焦(TAB键/Shift+TAB键/方向键)、使用requestFocus申请焦点、clearFocus清除焦点、focusOnTouch点击申请焦点等接口导致的焦点转移。

  • 按键走焦
  1. 前提:当前应用需处于焦点激活态。
  2. 范围限制:按键走焦仅在当前获得焦点的层级页面内进行,具体参见“层级页面”中的“走焦范围限制”部分。
  3. 按键类型:

    TAB键:遵循Z字型遍历逻辑,完成当前范围内所有叶子节点的遍历,到达当前范围内的最后一个组件后,继续按下TAB键,焦点将循环至范围内的第一个可获焦组件,实现循环走焦。

    Shift+TAB键:与TAB键具有相反的焦点转移效果。

    方向键(上、下、左、右):遵循十字型移动策略,在单层容器中,焦点的转移由该容器的特定走焦算法决定。若算法判定下一个焦点应落在某个容器组件上,系统将采用中心点距离优先的算法来进一步确定容器内的目标子节点。

  4. 走焦算法:每个可获焦的容器组件都有其特定的走焦算法,用于定义焦点转移的规则。
  5. 子组件优先:当子组件处理按键走焦事件,父组件将不再介入。
  • requestFocus

    详见requestFocus,可以主动将焦点转移到指定组件上。

    不可跨窗口,不可跨ArkUI实例申请焦点,可以跨层级页面申请焦点。

  • clearFocus

    详见clearFocus,会清除当前层级页面中的焦点,最终焦点停留在根容器上。

  • focusOnTouch

    详见focusOnTouch,使绑定组件具备点击后获得焦点的能力。若组件本身不可获焦,则此功能无效。若绑定的是容器组件,点击后优先将焦点转移给上一次获焦的子组件,否则转移给第一个可获焦的子组件。

被动走焦

被动走焦是指组件焦点因系统或其他操作而自动转移,无需开发者直接干预,这是焦点系统的默认行为。

目前会被动走焦的机制有:

  • 组件删除:当处于焦点状态的组件被删除时,焦点框架首先尝试将焦点转移到相邻的兄弟组件上,遵循先向后再向前的顺序。若所有兄弟组件均不可获焦,则焦点将释放,并通知其父组件进行焦点处理。
  • 属性变更:若将处于焦点状态的组件的focusable或enabled属性设置为false,或者将visibility属性设置为不可见,系统将自动转移焦点至其他可获焦组件,转移方式与1中相同
  • 层级页面切换:当发生层级页面切换时,如从一个页面跳转到另一个页面,当前页面的焦点将自动释放,新页面可能会根据预设逻辑自动获得焦点。
  • Web组件初始化:对于Web组件,当其被创建时,若其设计需要立即获得焦点(如某些弹出框或输入框),则可能触发焦点转移至该Web组件,其行为属于组件自身的行为逻辑,不属于焦点框架的规格范围。

走焦算法

在焦点管理系统中,每个可获焦的容器都配备有特定的走焦算法,这些算法定义了当使用TAB键、Shift+TAB键或方向键时,焦点如何从当前获焦的子组件转移到下一个可获焦的子组件。

容器采用何种走焦算法取决于其UX(用户体验)规格,并由容器组件进行适配。目前,焦点框架支持三种走焦算法:线性走焦、投影走焦和自定义走焦。

线性走焦算法

线性走焦算法是默认的走焦策略,它基于容器中子节点在节点树中的挂载顺序进行走焦,常用于单方向布局的容器,如Row、Column和Flex容器。运行规则如下:

  • 顺序依赖:走焦顺序完全基于子节点在节点树中的挂载顺序,与它们在界面上的实际布局位置无关。
  • TAB键走焦:使用TAB键时,焦点将按照子节点的挂载顺序依次遍历。
  • 方向键走焦:当使用与容器定义方向垂直的方向键时,容器不接受该方向的走焦请求。例如,在横向的Row容器中,无法使用方向键进行上下移动。
  • 边界处理:当焦点位于容器的首尾子节点时,容器将拒绝与当前焦点方向相反的方向键走焦请求。例如,焦点在一个横向的Row容器的第一个子节点上时,该容器无法处理方向键左的走焦请求。

投影走焦算法

投影走焦算法基于当前获焦组件在走焦方向上的投影,结合子组件与投影的重叠面积和中心点距离进行胜出判定。该算法特别适用于子组件大小不一的容器,目前仅有配置了wrap属性的Flex组件。运行规则如下:

  • 方向键走焦时,判断投影与子组件区域的重叠面积,在所有面积不为0的子组件中,计算它们与当前获焦组件的中心点直线距离,距离最短的胜出,若存在多个备选,则节点树上更靠前的胜出。若无任何子组件与投影由重叠,说明该容器已经无法处理该方向键的走焦请求。
  • TAB键走焦时,先使用规格1,按照方向键右进行判定,若找到则成功退出,若无法找到,则将当前获焦子组件的位置模拟往下移动该获焦子组件的高度,然后再按照方向键左进行投影判定,有投影重叠且中心点直线距离最远的子组件胜出,若无投影重叠的子组件,则表示该容器无法处理本次TAB键走焦请求。
  • Shift+TAB键走焦时,先使用规格1,按照方向键左进行判定,找到则成功退出。若无法找到,则将当前获焦子组件的位置模拟向上移动该获焦子组件的高度,然后再按照方向键右进行投影判定,有投影重叠且中心点直线距离最远的子组件胜出,若无投影重叠的子组件,则表示该容器无法处理本次的Shift+TAB键走焦请求。

自定义走焦算法

由组件自定义的走焦算法,规格由组件定义。

获焦/失焦事件

onFocus(event: () => void)

获焦事件回调,绑定该接口的组件获焦时,回调响应。

onBlur(event:() => void)

失焦事件回调,绑定该接口的组件失焦时,回调响应。

onFocus和onBlur两个接口通常成对使用,来监听组件的焦点变化。

// xxx.ets
@Entry
@Component
struct FocusEventExample {@State oneButtonColor: Color = Color.Gray;@State twoButtonColor: Color = Color.Gray;@State threeButtonColor: Color = Color.Gray;build() {Column({ space: 20 }) {// 通过外接键盘的上下键可以让焦点在三个按钮间移动,按钮获焦时颜色变化,失焦时变回原背景色Button('First Button').width(260).height(70).backgroundColor(this.oneButtonColor).fontColor(Color.Black)// 监听第一个组件的获焦事件,获焦后改变颜色.onFocus(() => {this.oneButtonColor = Color.Green;})// 监听第一个组件的失焦事件,失焦后改变颜色.onBlur(() => {this.oneButtonColor = Color.Gray;})Button('Second Button').width(260).height(70).backgroundColor(this.twoButtonColor).fontColor(Color.Black)// 监听第二个组件的获焦事件,获焦后改变颜色.onFocus(() => {this.twoButtonColor = Color.Green;})// 监听第二个组件的失焦事件,失焦后改变颜色.onBlur(() => {this.twoButtonColor = Color.Grey;})Button('Third Button').width(260).height(70).backgroundColor(this.threeButtonColor).fontColor(Color.Black)// 监听第三个组件的获焦事件,获焦后改变颜色.onFocus(() => {this.threeButtonColor = Color.Green;})// 监听第三个组件的失焦事件,失焦后改变颜色.onBlur(() => {this.threeButtonColor = Color.Gray ;})}.width('100%').margin({ top: 20 })}
}

上述示例包含以下3步:

  • 应用打开,按下TAB键激活走焦,“First Button”显示焦点态样式:组件外围有一个蓝色的闭合框,onFocus回调响应,背景色变成绿色。
  • 按下TAB键,触发走焦,“Second Button”获焦,onFocus回调响应,背景色变成绿色;“First Button”失焦、onBlur回调响应,背景色变回灰色。
  • 按下TAB键,触发走焦,“Third Button”获焦,onFocus回调响应,背景色变成绿色;“Second Button”失焦、onBlur回调响应,背景色变回灰色。

设置组件是否可获焦

focusable(value: boolean)

设置组件是否可获焦。

按照组件的获焦能力可大致分为三类:

  • 默认可获焦的组件,通常是有交互行为的组件,例如Button、Checkbox,TextInput组件,此类组件无需设置任何属性,默认即可获焦。

  • 有获焦能力,但默认不可获焦的组件,典型的是Text、Image组件,此类组件缺省情况下无法获焦,若需要使其获焦,可使用通用属性focusable(true)使能。对于没有配置focusable属性,有获焦能力但默认不可获焦的组件,为其配置onClick或是单指单击的Tap手势,该组件会隐式地成为可获焦组件。如果其focusable属性被设置为false,即使配置了上述事件,该组件依然不可获焦。

  • 无获焦能力的组件,通常是无任何交互行为的展示类组件,例如Blank、Circle组件,此类组件即使使用focusable属性也无法使其可获焦。

enabled(value: boolean)

 设置组件可交互性属性enabled为false,则组件不可交互,无法获焦。

visibility(value: Visibility)

设置组件可见性属性visibility为Visibility.None或Visibility.Hidden,则组件不可见,无法获焦。

focusOnTouch(value: boolean)

设置当前组件是否支持点击获焦能力。

说明

  • 当某组件处于获焦状态时,将其的focusable属性或enabled属性设置为false,会自动使该组件失焦,然后焦点按照走焦规范将焦点转移给其他组件。
// xxx.ets
@Entry
@Component
struct FocusableExample {@State textFocusable: boolean = true;@State textEnabled: boolean = true;@State color1: Color = Color.Yellow;@State color2: Color = Color.Yellow;@State color3: Color = Color.Yellow;build() {Column({ space: 5 }) {Text('Default Text')    // 第一个Text组件未设置focusable属性,默认不可获焦.borderColor(this.color1).borderWidth(2).width(300).height(70).onFocus(() => {this.color1 = Color.Blue;}).onBlur(() => {this.color1 = Color.Yellow;})Divider()Text('focusable: ' + this.textFocusable)    // 第二个Text设置了focusable初始为true,focusableOnTouch为true.borderColor(this.color2).borderWidth(2).width(300).height(70).focusable(this.textFocusable).focusOnTouch(true).onFocus(() => {this.color2 = Color.Blue;}).onBlur(() => {this.color2 = Color.Yellow;})Text('enabled: ' + this.textEnabled)    // 第三个Text设置了focusable为true,enabled初始为true.borderColor(this.color3).borderWidth(2).width(300).height(70).focusable(true).enabled(this.textEnabled).focusOnTouch(true).onFocus(() => {this.color3 = Color.Blue;}).onBlur(() => {this.color3 = Color.Yellow;})Divider()Row() {Button('Button1').width(140).height(70)Button('Button2').width(160).height(70)}Divider()Button('Button3').width(300).height(70)Divider()}.width('100%').justifyContent(FlexAlign.Center).onKeyEvent((e) => {// 绑定onKeyEvent,在该Column组件获焦时,按下'F'键,可将第二个Text的focusable置反if (e.keyCode === 2022 && e.type === KeyType.Down) {this.textFocusable = !this.textFocusable;}// 绑定onKeyEvent,在该Column组件获焦时,按下'G'键,可将第三个Text的enabled置反if (e.keyCode === 2023 && e.type === KeyType.Down) {this.textEnabled = !this.textEnabled;}})}
}

运行效果:

上述示例包含以下3步:

  • 第一个Text组件没有设置focusable(true)属性,该Text组件无法获焦。
  • 点击第二个Text组件,由于设置了focusOnTouch(true),第二个组件获焦。按下TAB键,触发走焦,仍然是第二个Text组件获焦。按键盘F键,触发onKeyEvent,focusable置为false,第二个Text组件变成不可获焦,焦点自动转移,会自动从Text组件寻找下一个可获焦组件,焦点转移到第三个Text组件上。
  • 按键盘G键,触发onKeyEvent,enabled置为false,第三个Text组件变成不可获焦,焦点自动转移,使焦点转移到Row容器上,容器中使用的是默认配置,会转移到Button1上。

默认焦点

页面的默认焦点

defaultFocus(value: boolean)

设置当前组件是否为当前页面上的默认焦点。

// xxx.ets
@Entry
@Component
struct morenjiaodian {@State oneButtonColor: Color = Color.Gray;@State twoButtonColor: Color = Color.Gray;@State threeButtonColor: Color = Color.Gray;build() {Column({ space: 20 }) {// 通过外接键盘的上下键可以让焦点在三个按钮间移动,按钮获焦时颜色变化,失焦时变回原背景色Button('First Button').width(260).height(70).backgroundColor(this.oneButtonColor).fontColor(Color.Black)// 监听第一个组件的获焦事件,获焦后改变颜色.onFocus(() => {this.oneButtonColor = Color.Green;})// 监听第一个组件的失焦事件,失焦后改变颜色.onBlur(() => {this.oneButtonColor = Color.Gray;})Button('Second Button').width(260).height(70).backgroundColor(this.twoButtonColor).fontColor(Color.Black)// 监听第二个组件的获焦事件,获焦后改变颜色.onFocus(() => {this.twoButtonColor = Color.Green;})// 监听第二个组件的失焦事件,失焦后改变颜色.onBlur(() => {this.twoButtonColor = Color.Grey;})Button('Third Button').width(260).height(70).backgroundColor(this.threeButtonColor).fontColor(Color.Black)// 设置默认焦点.defaultFocus(true)// 监听第三个组件的获焦事件,获焦后改变颜色.onFocus(() => {this.threeButtonColor = Color.Green;})// 监听第三个组件的失焦事件,失焦后改变颜色.onBlur(() => {this.threeButtonColor = Color.Gray ;})}.width('100%').margin({ top: 20 })}
}

上述示例包含以下2步:

  • 在第三个Button组件上设置了defaultFocus(true),进入页面后第三个Button默认获焦,显示为绿色
  • 按下TAB键,触发走焦,第三个Button正处于获焦状态,会出现焦点框

容器的默认焦点

容器的默认焦点受到获焦优先级的影响。

defaultFocus与FocusPriority的区别

defaultFocus是用于指定页面首次展示时的默认获焦节点,FocusPriority是用于指定某个容器首次获焦时其子节点的获焦优先级。上述两个属性在某些场景同时配置时行为未定义,例如下面的场景,页面首次展示无法同时满足defaultFocus获焦和高优先级组件获焦。

@Entry
@Component
struct Index {build() {Row() {Button('Button1').defaultFocus(true)Button('Button2').focusScopePriority('RowScope', FocusPriority.PREVIOUS)}.focusScopeId('RowScope')}
}

页面/容器整体获焦时的焦点链

整体获焦与非整体获焦

  • 整体获焦是页面/容器自身作为焦点链的叶节点获焦,获焦后再把焦点链叶节点转移到子孙组件。例如,页面切换、Navigation组件中的路由切换、焦点组走焦、容器组件主动调用requestFocusById等。

  • 非整体获焦是某个组件作为焦点链叶节点获焦,导致其祖先节点跟着获焦。例如TextInput组件主动获取焦点、Tab键在非焦点组场景下走焦等。

整体获焦的焦点链形成

1.页面首次获焦

  • 焦点链叶节点为配置了defaultFocus的节点。

  • 未配置defaultFocus时,焦点停留在页面的根容器上。

2.页面非首次获焦:由上次获焦的节点获焦。

3.获焦链上存在配置了获焦优先级的组件和容器

  • 容器内存在优先级大于PREVIOUS的组件,由优先级最高的组件获焦。

  • 容器内不存在优先级大于PREVIOUS的组件,由上次获焦的节点获焦。例如,窗口失焦后重新获焦。

焦点样式

focusBox(style: FocusBoxStyle)

设置当前组件系统焦点框样式。

import { ColorMetrics, LengthMetrics } from '@kit.ArkUI'@Entry
@Component
struct RequestFocusExample {build() {Column({ space: 30 }) {Button("small black focus box").focusBox({margin: new LengthMetrics(0),strokeColor: ColorMetrics.rgba(0, 0, 0),})Button("large red focus box").focusBox({margin: LengthMetrics.px(20),strokeColor: ColorMetrics.rgba(255, 0, 0),strokeWidth: LengthMetrics.px(10)})}.alignItems(HorizontalAlign.Center).width('100%')}
}

上述示例包含以下2步:

  • 进入页面,按下TAB触发走焦,第一个Button获焦,焦点框样式为紧贴边缘的蓝色细框
  • 按下TAB键,走焦到第二个Button,焦点框样式为远离边缘的红色粗框

主动获焦/失焦

  • 使用FocusController中的方法

    更推荐使用FocusController中的requestFocus主动获取焦点。优势如下:

    • 当前帧生效,避免被下一帧组件树变化影响。
    • 有异常值返回,便于排查主动获取焦点失败的原因。
    • 避免多实例场景中取到错误实例。

    需先使用UIContext中的getFocusController()方法获取实例,再通过此实例调用对应方法。

requestFocus(key: string): void

通过组件的id将焦点转移到组件树对应的实体节点,生效时间为当帧生效。

clearFocus(): void

清除焦点,将焦点强制转移到页面根容器节点,焦点链路上其他节点失焦。

使用focusControl中的方法 

requestFocus(value: string): boolean

调用此接口可以主动让焦点转移至参数指定的组件上,焦点转移生效时间为下一个帧信号。

// focusTest.ets
@Entry
@Component
struct RequestExample {@State btColor: string = '#ff2787d9'@State btColor2: string = '#ff2787d9'build() {Column({ space: 20 }) {Column({ space: 5 }) {Button('Button').width(200).height(70).fontColor(Color.White).focusOnTouch(true).backgroundColor(this.btColor).onFocus(() => {this.btColor = '#ffd5d5d5'}).onBlur(() => {this.btColor = '#ff2787d9'}).id("testButton")Button('Button').width(200).height(70).fontColor(Color.White).focusOnTouch(true).backgroundColor(this.btColor2).onFocus(() => {this.btColor2 = '#ffd5d5d5'}).onBlur(() => {this.btColor2 = '#ff2787d9'}).id("testButton2")Divider().vertical(false).width("80%").backgroundColor('#ff707070').height(10)Button('FocusController.requestFocus').width(200).height(70).fontColor(Color.White).onClick(() => {this.getUIContext().getFocusController().requestFocus("testButton")}).backgroundColor('#ff2787d9')Button("focusControl.requestFocus").width(200).height(70).fontColor(Color.White).onClick(() => {focusControl.requestFocus("testButton2")}).backgroundColor('#ff2787d9')Button("clearFocus").width(200).height(70).fontColor(Color.White).onClick(() => {this.getUIContext().getFocusController().clearFocus()}).backgroundColor('#ff2787d9')}}.width('100%').height('100%')}
}

上述示例包含以下3步:

  • 点击FocusController.requestFocus按钮,第一个Button获焦
  • 点击focusControl.requestFocus按钮,第二个Button获焦
  • 点击clearFocus按钮,第二个Button失焦

焦点组与获焦优先级

focusScopePriority(scopeId: string, priority?: FocusPriority)

 设置当前组件在指定容器内获焦的优先级。需要配合focusScopeId一起使用。

focusScopeId(id: string, isGroup?: boolean)

设置当前容器组件的id标识,设置当前容器组件是否为焦点组。焦点组与tabIndex不能混用。

// focusTest.ets
@Entry
@Component
struct FocusableExample {@State inputValue: string = ''build() {Scroll() {Row({ space: 20 }) {Column({ space: 20 }) {  // 标记为Column1Column({ space: 5 }) {Button('Group1').width(165).height(40).fontColor(Color.White)Row({ space: 5 }) {Button().width(80).height(40).fontColor(Color.White)Button().width(80).height(40).fontColor(Color.White)}Row({ space: 5 }) {Button().width(80).height(40).fontColor(Color.White)Button().width(80).height(40).fontColor(Color.White)}}.borderWidth(2).borderColor(Color.Red).borderStyle(BorderStyle.Dashed)Column({ space: 5 }) {Button('Group2').width(165).height(40).fontColor(Color.White)Row({ space: 5 }) {Button().width(80).height(40).fontColor(Color.White)Button().width(80).height(40).fontColor(Color.White).focusScopePriority('ColumnScope1', FocusPriority.PRIOR)  // Column1首次获焦时获焦}Row({ space: 5 }) {Button().width(80).height(40).fontColor(Color.White)Button().width(80).height(40).fontColor(Color.White)}}.borderWidth(2).borderColor(Color.Green).borderStyle(BorderStyle.Dashed)}.focusScopeId('ColumnScope1')Column({ space: 5 }) {  // 标记为Column2TextInput({placeholder: 'input', text: this.inputValue}).onChange((value: string) => {this.inputValue = value}).width(156)Button('Group3').width(165).height(40).fontColor(Color.White)Row({ space: 5 }) {Button().width(80).height(40).fontColor(Color.White)Button().width(80).height(40).fontColor(Color.White)}Button().width(165).height(40).fontColor(Color.White).focusScopePriority('ColumnScope2', FocusPriority.PREVIOUS)  // Column2获焦时获焦Row({ space: 5 }) {Button().width(80).height(40).fontColor(Color.White)Button().width(80).height(40).fontColor(Color.White)}Button().width(165).height(40).fontColor(Color.White)Row({ space: 5 }) {Button().width(80).height(40).fontColor(Color.White)Button().width(80).height(40).fontColor(Color.White)}}.borderWidth(2).borderColor(Color.Orange).borderStyle(BorderStyle.Dashed).focusScopeId('ColumnScope2', true)  // Column2为焦点组}.alignItems(VerticalAlign.Top)}}
}

上述示例包含以下2步:

  • input方框内设置了焦点组,因此按下TAB键后焦点会快速从input中走出去,而按下方向键后可以在input内走焦
  • 左上角的Column没有设置焦点组,因此只能通过Tab键一个一个地走焦

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/52811.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【逐行注释】MATLAB下的UKF(无迹卡尔曼滤波),带丰富的中文注释,可直接复制到MATLAB上运行,无需下载

文章目录 程序组成部分完整代码运行结果主要模块解读:运动模型绘图部分误差统计特性输出程序组成部分 由模型初始化、运动模型、UKF主体部分、绘图代码和输出部分组成: 完整代码 将下列代码复制粘贴到MATLAB里面,即可运行: % 三维状态量的UKF例程 % 作者联系方式:微信…

安全面试常见问题任意文件下载

《网安面试指南》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484339&idx1&sn356300f169de74e7a778b04bfbbbd0ab&chksmc0e47aeff793f3f9a5f7abcfa57695e8944e52bca2de2c7a3eb1aecb3c1e6b9cb6abe509d51f&scene21#wechat_redirect 1.1 任意文件下…

培训第三十九天(了解docker-compose,docker-compose编排容器,配置harbor服务)

一、回顾 1、拉取私有仓库镜像 # 配置dockerdocker pull 10.0.0.10:5000/centosnginx:v0 2、容器网络类型 brideg(net) default# docker启动之后会生成新的虚拟网卡,网卡的名称docker0# 网段默认是172.17.0.1# 所有的容器都桥接docker0,通过桥接共享网…

LRN正则化是什么?

LRN正则化,全称为Local Response Normalization(局部响应归一化),是一种在深度学习,特别是在卷积神经网络(CNN)中常用的正则化技术。该技术旨在通过模拟生物视觉系统中的侧抑制现象,…

OpenLayers3, 设置地图背景

文章目录 一、前言二、代码实现三、总结 一、前言 本文基于OpenLayers3&#xff0c;实现地图加入背景图的功能。 二、代码实现 <!DOCTYPE html> <html xmlns"http://www.w3.org/1999/xhtml"> <head><meta http-equiv"Content-Type"…

QT学习ubuntu qt + desktop

环境搭建 ubuntu 安装QT 遇到kit 选择不了 通过sudo apt-get install qt5-default去安装SDK的时候报错&#xff1a; Package qt5-default is not available, but is referred to by another package. This may mean that the package is missing, has been obsoleted, or is …

Linux——nginx 负载均衡

常规的web服务器一般提供对于静态资源的访问&#xff0c;比如说&#xff1a;图片、web样式 网站提供的大部分交互功能都需要web编程语言的支持&#xff0c;而web服务对于程序的调用&#xff0c;不管编译型语言还是解释型语言&#xff0c;web服务同将对于应用程序的调用递交给通…

在蓝桥云课ROS中快速搭建Arduino开发环境

普通方式 一步步慢悠悠的搭建和讲解需要5-6分钟&#xff1a; 如何在蓝桥云课ROS中搭建Arduino开发环境 视频时间&#xff1a;6分40秒 高效方式 如何高效率在蓝桥云课ROS中搭建Arduino开发环境 视频时间&#xff1a;1分45秒 配置和上传程序到开发板 上传程序又称为下载程序h…

html+css+js网页设计 婚庆网站8个页面

htmlcssjs网页设计 婚庆网站8个页面 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 1&#xff…

C#骑砍逻辑类Mod制作详细解说

前言&#xff1a; 最近在研究骑砍的mod&#xff0c;主要是想修改其中的逻辑部分&#xff0c;因此有了这篇帖子。 一&#xff0c;文件夹与XML配置 在Modules创建一个新文件夹&#xff0c;文件夹名称随意&#xff0c;不影响实际的读取。 文件夹下面的位置需要固定&#xff0c;因…

闲置物品|基于SprinBoot+vue的校园闲置物品交易平台(源码+数据库+文档)

校园闲置物品交易平台 目录 基于SprinBootvue的校园闲置物品交易平台 一、前言 二、系统设计 三、系统功能设计 5.1系统功能实现 5.2管理员模块实现 5.3用户模块实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xf…

项目:基于TCP的文件传输系统

项目介绍: 模拟FTP原理&#xff1a;客户端连接服务器后&#xff0c;向服务器发送一个文件。文件名可以通过参数指定&#xff0c;服务器端接收客户端传来的文件&#xff08;文件名随意&#xff09;&#xff0c;如果文件不存在自动创建文件&#xff0c;如果文件存在&#xff0c;…

matlab 相位解缠

目录 一、功能概述1、相位解缠2、主要函数二、代码实现1、螺旋线的正确相位角2、使用不同阈值平移相位角3、将相移应用于矩阵三、参考链接本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的抄袭狗。 一、功能概述 1、相位解缠 对…

FPGA实现多功能SDI视频采集卡,基于GTX+RIFFA架构,提供2套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的PCIE方案本博已有的 SDI 编解码方案 3、详细设计方案设计框图SDI 输入设备Gv8601a 均衡器GTX 解串与串化SMPTE SD/HD/3G SDI IP核BT1120转RGBFDMA图像缓存RIFFA用户数据控制RIFFA架构详解Xilinx 7 Series Integrated Bloc…

智能优化特征选择|基于鲸鱼WOA优化算法实现的特征选择研究Matlab程序(XGBoost分类器)

智能优化特征选择|基于鲸鱼WOA优化算法实现的特征选择研究Matlab程序&#xff08;XGBoost分类器&#xff09; 文章目录 一、基本原理鲸鱼智能优化特征选择流程 二、实验结果三、核心代码四、代码获取五、总结 智能优化特征选择|基于鲸鱼WOA优化算法实现的特征选择研究Matlab程序…

从地图信息实时检测路口的各向通行状况、红绿灯及溢出情况

高德地图、百度地图都能获得实时的道路信息。 C# 编写的路况信息爬虫可获得准实时&#xff08;1分钟间隔&#xff09;的路口的各向通行状况、红绿灯及溢出情况。 优势&#xff1a; 投入少&#xff0c;效果好&#xff0c;无需安装设备&#xff1b; 缺陷&#xff1a; 时间间隔…

更新RK3588开发板的rknn_server和librknnrt.so【这篇文章是RKNPU2从入门到实践 --- 【5】的配套文章】

作者使用的平台有&#xff1a; 一台装有Windows系统的宿主机&#xff0c;在该宿主机上装有Ubuntu 20.04虚拟系统&#xff1b; 瑞芯微RK3588开发板&#xff0c;开发板上的系统为Ubuntu22.04系统&#xff1b; 更新板子的 rknn_server 和 librknnrt.so&#xff0c;rknn_server 和…

USART之串口发送+接收应用案例

文章目录 前言一、电路接线图二、应用案例代码三、应用案例分析3.1 USART模块初始化3.1.1 RCC开启时钟3.1.2 GPIO初始化3.1.3 配置USART3.1.4 开启中断、配置NVIC3.1.5 开启USART 3.2 USART串口收发模块3.2.1 Serial_SendByte&#xff08;发送一个字节数据&#xff09;3.2.2 US…

【蓝桥杯集训100题】scratch绘制扇子 蓝桥杯scratch比赛专项预测编程题 集训模拟练习题第28题

scratch绘制扇子 蓝桥杯集训100题第28题模拟练习解析 此题曾经作为第十届省赛的真题考过 一、题目要求 以坐标(0,0)点为中心绘制一把扇子;扇面和扇把都是三分之一圆,扇面的半径 为 100 左右,扇把的半径为 20 左右。 编程实现 每次点击绿旗后,舞台背景为白色,…

【自动驾驶】控制算法(六)前馈控制与航向误差

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…