加入下方官方CSDN班级,得鸿蒙礼盒

一起拿鸿蒙礼盒,戳我戳我!!

本期活动时间:2025年8月1日-12月31日

如有问题欢迎私聊我呀!


问题现象

当Menu组件内数据为空时,点击蓝色的菜单按钮,左下角依旧弹出一个白色圆点。该现象本身是符合组件逻辑,当展示组件内容为空时,仍然弹出空白的Menu组件容器。但是若开发设计为当菜单为空时不展示菜单,则该现象不符合要求。

背景知识

  • Menu是菜单接口,一般用于鼠标右键弹窗、点击弹窗等。具体用法请参考菜单控制
  • 当前Menu组件作为一个绑定交互组件,被应用在各种地方,例如历史记录、账号等。目前Menu当其中的信息为空时,会展示一个空白的交互框提示用户无信息,但若应用设计方面决定是不展示,则可参考如下实现。
    • 显隐控制:通过配置visibility的不同值,实现不同的显隐控制效果。
    • 禁用控制:通过enable设置按钮可交互性。
    • 触摸测试控制:设置组件的触摸测试类型。在ArkUI开发框架中,处理触屏事件时,会在触屏事件触发前进行按压点与组件区域的触摸测试,以收集需响应触屏事件的组件。基于测试结果,框架会分发相应的触屏事件。hitTestBehavior属性用于设置不同的触摸测试响应模式,影响触摸测试收集结果及后续触屏事件分发。

解决方案

使用bindMenu,让Menu为空时不显示可以通过如下三方面入手(其他组件也可类似分析)。

  • 方案一:查看组件自身是否有属性可以控制(Menu自身属性)。

    通过查看官方文档,Menu无对应属性控制是否显示。

  • 方案二:让组件隐身(Menu组件本身)。

    通过显隐控制可知,在Menu数据为空时,设置Menu组件visibility属性为None即可。注意此处不可设置为Hidden。此方法隐藏的原因是绑定的Builder组件为空没有内容可显示,因此点击无显示。参与布局会让Builder内有内容可显示,无法隐藏,因此只能使用None无法使用Hidden。同理可使用if让Builder内组件不参与组件树构建,不生成内容。

    名称

    描述

    Hidden

    隐藏,但参与布局进行占位。

    Visible

    显示。

    None

    隐藏,但不参与布局,不进行占位。

    @Entry
    @Component
    struct Index {
    @State visibility_param: Visibility = Visibility.Visible
    
    @Builder
    MyMenu() {
    Menu()
    .visibility(this.visibility_param)
    }
    
    build() {
    Column({ space: 30 }) {
    Button('菜单')
    .bindMenu(this.MyMenu)
    Button('Visibility = ' + this.visibility_param)
    .onClick(() => {
    this.visibility_param += 1
    if (this.visibility_param == 3) {
    this.visibility_param = 0
    }
    })
    }
    .width('100%')
    .height('100%')
    .alignItems(HorizontalAlign.Center)
    .backgroundColor(Color.Yellow)
    }
    }

    以下是三种效果图:

    • Visibility = Visible。

    • Visibility = Hidden。

    • Visibility = None。

  • 方案三:组件不触发Menu显示事件(被绑定Menu的组件)。
    • 禁用控制。

      通过禁用控制可知,设置enabled为false即可阻止交互事件,因此设置绑定Menu事件的组件的enabled为false。

      说明

      此时该组件进入不可交互状态,不会响应点击事件触摸事件拖拽事件按键事件焦点事件鼠标事件。同时组件UI会发生变化。

      @Entry
      @Component
      struct menu {
      @State enabled_param: boolean = true
      @Builder
      MyMenu() {
      Menu()
      }
      
      build() {
      Column({ space: 30 }) {
      Button('菜单')
      .bindMenu(this.MyMenu)
      .enabled(this.enabled_param)
      Button('Enable = ' + this.enabled_param)
      .onClick(() => {
      this.enabled_param = !this.enabled_param
      })
      }
      .width('100%')
      .height('100%')
      .alignItems(HorizontalAlign.Center)
      .backgroundColor(Color.Grey)
      }
      }

      以下是两种效果图:

      • Enable = true。

      • Enable = false。

    • 触摸测试控制。

      通过触摸测试控制可知,将组件组件测试拦截hitTestBehavior设置为HitTestMode.None,即可使当前组件不响应触摸事件,同时不影响同位置不同层级组件的点击响应。

      @Entry
      @Component
      struct menu {
      @State hitTestBehavior_param: HitTestMode = HitTestMode.Default
      
      @Builder
      MyMenu() {
      Menu()
      }
      
      build() {
      Column({ space: 30 }) {
      Blank()
      .height(100)
      Button('菜单')
      .bindMenu(this.MyMenu)
      .hitTestBehavior(this.hitTestBehavior_param)
      Button('HitTestMode = ' + this.hitTestBehavior_param)
      .onClick(() => {
      if (this.hitTestBehavior_param == HitTestMode.Default) {
      this.hitTestBehavior_param = HitTestMode.None
      } else {
      this.hitTestBehavior_param = HitTestMode.Default
      }
      })
      }
      .width('100%')
      .height('100%')
      .alignItems(HorizontalAlign.Center)
      .backgroundColor(Color.Grey)
      }
      }

      以下是两种效果图:

      • HitTestMode = Default。

      • HitTestMode = None。

总结

对于通过交互显示组件的问题,可以按照定位思路从三方面出发,首先查看显示组件自身是否有单独属性可以处理,其次就是使用通用的属性Visibility来处理显隐问题,最后可屏蔽交互事件,防止触发组件显示。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐