1. 简介

默认情况下按键事件从根节点元素,沿着焦点链向子元素进行分发,再自底向上冒泡触发绑定的事件。这里介绍如何对按键事件进行拦截,并自定义分发事件到指定子元素。

OpenHarmony版本:master
设备: rk3568

2. API介绍

功能实现主要PR:https://gitee.com/openharmony/arkui_ace_engine/pulls/51467

新增jsapi接口PR:https://gitee.com/openharmony/interface_sdk-js/pulls/15660

主要有三个api的变化:

  • onKeyEventDispatch:新增接口,在父组件组件上使用,可以对KeyEvent事件下发事件进行拦截,当返回为false时会阻止事件冒泡和走焦,并且当前父组件也不会执行onKeyEvent回调。

  • dispatchKeyEvent:新增接口,用来对对KeyEvent事件自定义分发,它可以将对KeyEvent事件分发到指定节点子元素,返回值为目标子元素的onKeyEvent接口的返回值,默认为false。

  • onKeyEvent接口添加了有返回值的场景,当返回为true时表示KeyEvent事件被消费,默认返回false。

3. 使用方法

构建一个如下结构的页面,在跟元素节点下创建Button1、Row、Button4三个子元素,再在Row元素下创建Button2、Button3两个子元素。

img

代码如下:

Column({space: 20}) {
    FocusBtn({text: 'Button1', defFocus: true})
    Row({space: 10}){
        FocusBtn({text: 'Button2'})
        FocusBtn({text: 'Button3'})
    }
    .id('parent')
    FocusBtn({text: 'Button4'})
}
.width('100%')
.height('100%')

FocusBtn为一个自定义Button组件:

@Component
export struct FocusBtn {
  @Prop text:string;
  defFocus:boolean = false;
  keyEvent: (e:KeyEvent) => void | boolean = (e:KeyEvent) => {
    console.info(`son btn ${this.text} onKeyEvent key:${e.keyCode} ${e.type == 1 ? '抬起' :'按下'}`);
  };
  w: number = 120;
  build() {
    Button(this.text)
      .id(this.text)
      .key(this.text)
      .width(this.w)
      .height(60)
      .fontSize(20)
      .defaultFocus(this.defFocus)
      .onKeyEvent((e) =>{
        return this.keyEvent(e);
      })
  }
}

默认子元素Button走焦顺序为:Button1->Button2->Button3->Button4

当使用键盘tab键切换焦点时,Button1、Button2、Button3、Button4会依次获焦,并且如果Button绑定了onKeyEvent事件,则会依次执行onKeyEvent回调。

在Row元素上添加onKeyEventDispatch拦截KeyEvent事件,并在其回调中调用dispatchKeyEvent分发KeyEvent事件到Button3子元素:

Row(){
    ...
}
.onKeyEventDispatch((event)=>{
    let res = false;
    let context = this.getUIContext();
    context.getFocusController().requestFocus('Button3');
    res = context.dispatchKeyEvent('Button3', event);
    console.info(`row dispatchKeyEvent Button3 onKeyEvent res:${res}`);
    return false;
})

这种情况下子元素Button走焦顺序就为:Button1->Button3->Button4

并且会直接执行Button3绑定的onKeyEvent回调。

4. 总结

以上是一个小的使用样例,在实际使用中,有几点需要注意:

  • onKeyEventDispatch返回true时,会阻止事件冒泡和阻止焦点移动,因此必须在特定场景下才能使其返回false,这里一般是通过dispatchKeyEvent和当前焦点组件判断。

  • onKeyEvent添加返回值场景后,若返回true,也会阻止事件冒泡和阻止焦点移动,其效果等同于event.stopPropagation();

  • 使用dispatchKeyEvent时,必须先使用requestFocus将焦点聚焦到目标元素,但是由于onKeyEventDispatch回调的执行时机在默认走焦之后,因此焦点样式会先走到默认焦点元素然后自动跳到目标元素,想要实现较好的效果,可以在上一个焦点元素的onBlur中预先执行requestFocus聚焦到目标元素。

  • 当onKeyEventDispatch与onKeyPreIme同时使用时,onKeyEventDispatch会失去任何作用。

  • onKeyEventDispatch与dispatchKeyEvent主要不是处理焦点事件本身,而是处理在需要特殊走焦时,能正确的执行目标元素的onKeyEvent事件。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐