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

阅读 590
1 个回答

当前根据点击坐标获取透明度的整体链路,因组件截图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 { 
   
  } 
 
  onForeground(): void { 
    
  } 
 
  onBackground(): void { 

  } 
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题