文档管理中心
我的
您当前正在浏览新版开发者文档中心,目录分类和层级有所调整。点击左侧当前文档分类名称前的“☰”图标,可切换文档分类。 了解新版目录
问题处理与运维开发与测试问题应用框架开发UI框架组件使用解决bindContextMenu长按菜单关闭时的事件穿透问题

解决bindContextMenu长按菜单关闭时的事件穿透问题

问题现象

当使用bindContextMenu为组件A配置长按菜单时,菜单弹出后,如果点击菜单区域外的任意位置可以关闭菜单,但组件A(或其他区域外的组件)的点击事件也会被触发。

效果预览

背景知识

  • bindContextMenu用于为组件绑定自定义菜单。菜单的显示和隐藏通过控制绑定的isShown属性实现:当isShown为true时,菜单弹出;为false时,菜单隐藏。
  • hitTestBehavior属性可以实现在复杂的多层级场景下,一些组件能够响应手势和事件,而一些组件不能响应手势和事件。HitTestMode.Block自身会响应触摸测试,阻塞子节点和兄弟节点的触摸测试,从而导致子节点和兄弟节点的onTouch事件和手势均无法触发。

解决方案

为解决点击菜单区域外时事件穿透问题,当菜单显示时,在页面最外层组件上添加hitTestBehavior.Block属性以阻止事件传播。同时,在最外层组件的点击事件回调方法中加入一个if条件判断,判断是否是处于菜单显示的情况,若是则直接返回,不处理后面的点击逻辑。

收起
自动换行
深色代码主题
复制
  1. import { PromptAction } from '@kit.ArkUI';
  2. @Entry
  3. @Component
  4. struct BindContextMenuIndex {
  5. @State menuShow: boolean = false;
  6. @State flag: boolean = false;
  7. promptAction: PromptAction = new PromptAction();
  8. @Builder
  9. menu() {
  10. Menu() {
  11. MenuItem({ startIcon: $r('app.media.startIcon'), content: '菜单1' });
  12. MenuItem({ startIcon: $r('app.media.startIcon'), content: '菜单2' });
  13. MenuItem({ startIcon: $r('app.media.startIcon'), content: '菜单3' });
  14. };
  15. }
  16. build() {
  17. Column() {
  18. Text('第一层')
  19. .height('150vp');
  20. Column() {
  21. Text('第二层')
  22. .height('150vp');
  23. Column() {
  24. Text('第三层的兄弟层1')
  25. .height('150vp');
  26. }
  27. .width('100%')
  28. .backgroundColor('#0D5AF5')
  29. .onClick(() => {
  30. this.promptAction.showToast({ message: '第三层的兄弟层1' });
  31. })
  32. // 长按手势,将控制菜单显隐的值修改为true
  33. .gesture(LongPressGesture().onAction(() => {
  34. this.menuShow = true;
  35. this.flag = true;
  36. }))
  37. // 绑定菜单
  38. .bindContextMenu(!!this.menuShow, this.menu(), {
  39. onDisappear: () => {
  40. this.menuShow = false;
  41. }
  42. });
  43. Column() {
  44. Text('第三层的兄弟层2')
  45. .height('150vp');
  46. }
  47. .width('100%')
  48. .backgroundColor('#0D85F5')
  49. .onClick(() => {
  50. this.promptAction.showToast({ message: '第三层的兄弟层2' });
  51. });
  52. }
  53. .width('100%')
  54. .height('100%')
  55. .backgroundColor('#65BA5F')
  56. .onClick(() => {
  57. this.promptAction.showToast({ message: '第二层' });
  58. });
  59. }
  60. .width('100%')
  61. .height('100%')
  62. .backgroundColor('#ECA724')
  63. .onClick(() => {
  64. console.info('onClick');
  65. if (this.flag) {
  66. this.flag = false;
  67. return;
  68. }
  69. this.promptAction.showToast({ message: '第一层' });
  70. })
  71. // 阻止事件穿透
  72. .hitTestBehavior(
  73. this.menuShow ?
  74. HitTestMode.Block :
  75. HitTestMode.Default
  76. );
  77. }
  78. }