HarmonyOS 弹层的点击事件透传处理

实现一套各个页面均可弹层的功能,涉及到弹层的点击事件透传处理

希望可以获取到点击的位置,弹层内的像素点,并获取到透明度,来判断点击事件是否需要透传到底部场景。

HarmonyOS
4天前
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
zbw_apple

当前根据点击坐标获取透明度的整体链路,因组件截图api是异步接口,事件拦截需要同步接口,无法达成整体链路。

参考代码;

@Entry
@Component
struct HitTestPage {
  @State message: string = 'Hello World';

  build() {
    Stack() {
      Column()
        .onTouch((event: TouchEvent)=> {
          if (event.type == TouchType.Down) {
            console.info("点击了:底部的界面")
          }
        })
        .height('100%')
        .width('100%')
        .backgroundColor(Color.Green)
      Column() {
        Text()
          .backgroundColor(Color.Black)
          .onTouch((event: TouchEvent)=> {
            event.stopPropagation()
            if (event.type == TouchType.Down) {
              console.info("点击了:文本")
            }
          })
          .height(100)
          .width(100)
      }
      .onTouch((event: TouchEvent)=> {
        if (event.type == TouchType.Down) {
          console.info("点击了:上面的界面")
        }
      })
      .hitTestBehavior(HitTestMode.Transparent)
      .backgroundColor(Color.Transparent)
      .height('100%')
      .width('100%')
    }
    .height('100%')
    .width('100%')
  }
}
//Index.ets
import { PageTwo } from './pageTwo';

export class NavParam {
  dialogHeightChangeBack?: (dialogHeight: number) => void

  constructor( dialogHeightChangeBack?: (dialogHeight: number) => void) {
    this.dialogHeightChangeBack = dialogHeightChangeBack
  }
}


@Entry
@Component
struct Index {
  @State message: string = 'Hello World';
  @Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack()
  @StorageLink("windowHeight") windowHeight: number = 0
  @State contentHeight: number = 100;
  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

  @Builder
  PageMap(name: string, param: NavParam) {
    if (name === 'pageTwo') {
      PageTwo({dialogHeightChangeBlock: param.dialogHeightChangeBack});
    }
  }

  aboutToAppear() {
    console.info("testTag: 当前windowHeight" + this,this.windowHeight);
    this.contentHeight = px2vp(this.windowHeight);
  }

  build() {
    Navigation(this.pageInfos) {
      Column() {
        Row().height(50)
        Button("pageOne")
          .fontSize(30)
          .type(ButtonType.Capsule)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            this.pageInfos.pushPath({ name: 'pageTwo', param: new NavParam(
              (dialogHeight: number) => {
                if (dialogHeight == 0) {
                  animateTo({ duration: 250 }, () => {
                    this.contentHeight = px2vp(this.windowHeight);
                  })
                } else {
                  this.contentHeight = px2vp(this.windowHeight) - dialogHeight;
                }
              })
            });
          })

        List({ space: 20, initialIndex: 0 }) {
          ForEach(this.arr, (item: number) => {
            ListItem() {
              Text('' + item)
                .width('100%').height(100).fontSize(16)
                .textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF)
            }
          }, (item: string) => item)
        }
        .listDirection(Axis.Vertical) // 排列方向
        .scrollBar(BarState.Off)
        .friction(0.6)
        .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线
        .edgeEffect(EdgeEffect.Spring) // 边缘效果设置为Spring
        .width('90%')

      }
      .justifyContent(FlexAlign.Center)
      .width('100%')
      .height(this.contentHeight)
      .hitTestBehavior(HitTestMode.Transparent)
      .onTouch((event: TouchEvent) => {
        if (event.type == TouchType.Down) {
          console.info('事件穿透:colume点击了')
        }
      })
    }
    .navDestination(this.PageMap)
    .onTouchIntercept((event: TouchEvent) => {
      if (event.type == TouchType.Down) {
        console.info('事件穿透:navigation点击了')
      }
      return HitTestMode.Transparent
    })
  }
}

//PageTwo.ets

@Component
export struct PageTwo {
  @State isShow: boolean = true;
  gravity: Alignment = Alignment.Bottom
  transitionEdge: TransitionEdge = TransitionEdge.BOTTOM
  @Consume('pageInfos') pageInfos: NavPathStack;
  @State gestureHeight: number = 500;
  dialogHeightChangeBlock?: (dialogHeight: number) => void;
  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  scrollOffsetY: number = 0;
  private scrollerForList: Scroller = new Scroller()
  @State canHandleScroll: boolean = true;

  aboutToAppear() {
    this.callBackHeight(this.gestureHeight);
  }

  callBackHeight(height: number) {
    if (this.dialogHeightChangeBlock) {
      this.dialogHeightChangeBlock!(height);
    }
  }

  build() {
    NavDestination() {
      //背景层
      Stack({ alignContent: this.gravity }) {
        //内容区
        Stack({ alignContent: this.gravity }) {
          if (this.isShow) {
            //手势层
            Stack({ alignContent: Alignment.Top }) {
              Column() {
                List({ space: 20, initialIndex: 0, scroller: this.scrollerForList }) {
                  ForEach(this.arr, (item: number) => {
                    ListItem() {
                      Text('' + item)
                        .width('100%')
                        .height(100)
                        .fontSize(16)
                        .textAlign(TextAlign.Center)
                        .borderRadius(10)
                        .backgroundColor(0xFFFFFF)
                    }
                  }, (item: string) => item)
                }
                .enableScrollInteraction(this.canHandleScroll)
                .listDirection(Axis.Vertical) // 排列方向
                .scrollBar(BarState.Off)
                .friction(0.6)
                .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线
                .edgeEffect(EdgeEffect.Spring) // 边缘效果设置为Spring
                .onScroll((scrollOffset: number, scrollState: ScrollState) => {
                  this.scrollOffsetY += scrollOffset;
                  console.info("list: y偏移量 " + this.scrollOffsetY);

                  if (this.scrollOffsetY <= 0) {
                    this.scrollerForList.scrollTo({xOffset:0,yOffset:0,animation:false});
                    this.scrollOffsetY = 0;
                    this.canHandleScroll = false;
                  }
                })

                .height('100%')
                .width('100%')
              }
            }
            .borderRadius(6)
            .transition(TransitionEffect.move(this.transitionEdge).animation({ duration: 250, curve: Curve.Smooth }))
            .position({ x: 0, y: 0 })
            .height("100%")
            .width("100%")
            .clip(true)
            .backgroundColor(Color.White)
          }
        }
        .width("100%")
        .height(this.gestureHeight)
        .parallelGesture(
          PanGesture({ direction: PanDirection.Vertical, fingers: 1 })
            .onActionUpdate((event: GestureEvent) => {
              if (!this.canHandleScroll) {
                console.info("testTag: y偏移量 " + event.offsetY);
                let temHeight = 500;
                temHeight -= event.offsetY;
                if (temHeight >= 500) {
                  this.gestureHeight = 500;
                } else {
                  this.gestureHeight = temHeight;
                }
                this.callBackHeight(this.gestureHeight);
              }
            })
            .onActionEnd((event: GestureEvent) => {
              if (!this.canHandleScroll) {
                console.info("testTag: 动画结束y偏移量 " + event.offsetY);
                let temHeight = 500;
                temHeight -= event.offsetY;
                if (temHeight < 250) {
                  this.closeDialogAction()
                } else if (temHeight >= 250 && temHeight < 500) {
                  let duration = (500 - temHeight) / 500.0 * 250.0;
                  animateTo({ duration: duration }, () => {
                    this.gestureHeight = 500;
                    this.callBackHeight(this.gestureHeight);
                  })
                }
                this.canHandleScroll = true;
              }
            })
        )
      }
      .onClick(() => {
        // this.closeDialogAction()
      })
      .onTouchIntercept((event: TouchEvent) => {
        if (event.type == TouchType.Down) {
          console.info('事件穿透:stack点击了')
        }
        return HitTestMode.Transparent
      })
      .width('100%')
      .height('100%')
      .backgroundColor('#33000000')
    }
    .onBackPressed(() => {
      this.closeDialogAction()
      return true
    })
    .hitTestBehavior(HitTestMode.Transparent)
    .onTouch((event: TouchEvent) => {
      if (event.type == TouchType.Down) {
        console.info('事件穿透:dialog点击了')
      }
    })
    .hideTitleBar(true)
    .mode(NavDestinationMode.DIALOG)
  }

  closeDialogAction() {
    this.isShow = false;
    this.callBackHeight(0);
    animateTo({
      duration: 100, delay: 250, onFinish: () => {
        this.pageInfos.pop()
      }
    }, () => {
    })
  }
}

//EntryAbility.ets

import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';

async function enterImmersion(windowClass: window.Window) {

  AppStorage.setOrCreate<number>('windowHeight', windowClass.getWindowProperties().windowRect.height)
  AppStorage.setOrCreate<number>('windowWidth', windowClass.getWindowProperties().windowRect.width)

  // 监听窗口高度变化
  windowClass.on('windowSizeChange', (size)=> {
    AppStorage.setOrCreate<number>('windowHeight', size.height)
    AppStorage.setOrCreate<number>('windowWidth', size.width)
  })

  // 设置窗口布局为沉浸式布局
  await windowClass.setWindowLayoutFullScreen(true)
  await windowClass.setWindowSystemBarEnable(["status", "navigation"])
  // 设置状态栏和导航栏的背景为透明
  await windowClass.setWindowSystemBarProperties({
    navigationBarColor: "#00000000",
    statusBarColor: "#00000000",
  })
}


export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onDestroy(): void {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  async onWindowStageCreate(windowStage: window.WindowStage) {
    // Main window is created, set main page for this ability
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    let windowClass:window.Window = await windowStage.getMainWindow()
    await enterImmersion(windowClass)

    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }
      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
    });
  }

  onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    // Ability has brought to foreground
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground(): void {
    // Ability has back to background
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
  }
}
分享
微博
QQ
微信
回复
4天前
相关问题
怎么onClick事件
308浏览 • 1回复 待解决
如何将点击事件传到下一
1918浏览 • 1回复 待解决
customDialog焦点
859浏览 • 1回复 待解决
如何实现事件,你会吗?
2133浏览 • 1回复 待解决
两个重叠组件如何实现事件
637浏览 • 1回复 待解决
HarmonyOS 动态UI点击事件处理
164浏览 • 1回复 待解决
父组件中如何处理子组件内点击事件
2753浏览 • 1回复 待解决
HarmonyOS 富文本点击事件
465浏览 • 1回复 待解决
HarmonyOS 气泡点击问题
463浏览 • 1回复 待解决
如何禁止Button点击事件
599浏览 • 1回复 待解决