HarmonyOS 如何将一个页面,可以通过手势拖拽出来?

有一个页面,可以通过正常路由跳转展现。

同时,也可以通过,从屏幕侧边跟手拖拽出来。

目前从UI效果上,可以通过设置当前页面和目标页面componet 之间的布局来实现,

但是这样子出来的页面,一些诸如aboutToAppear 的生命周期不会回调。

是否有好的解决办法? 最好是能在路由的框架下实现。

HarmonyOS
2024-12-25 07:36:39
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
Heiang

参考代码:

import { display, matrix4, promptAction, window } from '@kit.ArkUI';

enum EPageId {
  ONE,
  TWO,
  TREE
}


@Entry
@Component
struct Index {
  @State pageId: EPageId = EPageId.ONE;
  @State scrollX: number = 0


  screenWidth: number = 0
  offsetX: number = 0
  // 可以直接用0,1,2,3,4代替id
  pageIds: EPageId[] = [EPageId.ONE, EPageId.TWO, EPageId.TREE]
  pageIndex: number = 0
  nextIndex: number = 0
  isChange: boolean = true
  scrollController: Scroller = new Scroller()

  // 页面的x轴偏移量列表
  @State pageOffsetX: number[] = []
  // 页面的zIndex,可以和偏移量合起来
  pageZIndex: number[] = []


  aboutToAppear(): void {
    // 这边也可以获取屏幕宽度
    this.screenWidth = display.getDefaultDisplaySync().width
    this.pageOffsetX = [0, this.screenWidth, this.screenWidth]
    this.pageZIndex = [1,2,3,4,5]
  }

  build() {
    Column(){
      PageOne({pageId: this.pageId}).animation({
        duration: 100,
      })
      PageTwo({pageId: this.pageId}).zIndex(this.pageZIndex[1]).position({x: this.pageOffsetX[1], y: 0}).animation({
        duration: 100,
      })
      PageTree({pageId: this.pageId}).zIndex(this.pageZIndex[2]).position({x: this.pageOffsetX[2], y: 0}).animation({
        duration: 100,
      })
    }
    .parallelGesture(PanGesture({distance: 1, direction: PanDirection.Horizontal})
      .onActionStart((event: GestureEvent)=>{
        console.info(event.offsetX.toString())
        if(event.offsetX > 0){
          if(this.nextIndex > 0){
            this.pageOffsetX[this.nextIndex] = event.offsetX
          }
          return
        }
        if(this.nextIndex < this.pageOffsetX.length - 1){
          this.nextIndex += 1
          // this.pageZIndex[this.nextIndex] = this.nextIndex + 1
          this.pageOffsetX[this.nextIndex] = this.screenWidth + event.offsetX
        }
      })
      .onActionUpdate((event: GestureEvent)=>{
        let isLeftByStart = this.nextIndex > this.pageIndex
        if(isLeftByStart && event.offsetX < 0){
          this.pageOffsetX[this.nextIndex] = this.screenWidth + event.offsetX
          return
        }
        if(!isLeftByStart && event.offsetX > 0){
          this.pageOffsetX[this.nextIndex] = event.offsetX
          return
        }
      })
      .onActionEnd((event: GestureEvent)=>{
        let isLeftByStart = this.nextIndex > this.pageIndex
        console.info(isLeftByStart.toString(), event.offsetX)

        // 手势结束后,滑动偏移,向左为负,向右为正
        let offsetX = event.offsetX
        // 手势结束时,滑动的速度,向左为负,向右为正
        let speedX = event.velocityX
        if(isLeftByStart && offsetX < 0){
          // 向左滑动了,增加页面
          // this.pageZIndex[this.pageIndex] = 1
          this.pageIndex++
          this.pageOffsetX[this.pageIndex] = 0
          this.pageId = this.pageIds[this.pageIndex]
          return
        }
        if(!isLeftByStart && offsetX > 0 && this.pageIndex > 0){
          // 右滑
          this.pageOffsetX[this.pageIndex] = this.screenWidth
          this.pageIndex--
          this.nextIndex--
          this.pageId = this.pageIds[this.pageIndex]
          // if(speedX < 0){
          //   // 最后向左滑动了,说明页面不需要更新
          //   this.scrollController.scrollTo({ yOffset: scrollOffset.yOffset, animation: true, xOffset: scrollOffset.xOffset + offsetX })
          // }else {
          //   // 最后手势为右滑
          //   this.pageIndex--
          //   this.pageId = this.pageIds[this.pageIndex]
          //   this.scrollController.scrollTo({ yOffset: scrollOffset.yOffset, animation: true, xOffset: scrollOffset.xOffset - offsetX - this.screenWidth })
          // }
        }
      }))

    .height('100%')
    .width('100%')
    .onAreaChange((oldArea, newArea)=>{
      // 其实这边都是number
      this.screenWidth = Number(newArea.width) || 0
    })
  }
}


@Component
struct PageOne{

  @Prop @Watch('onCountUpdated') pageId: number = 0;
  @State total: number = 0;
  // @Watch 回调
  onCountUpdated(propName: string): void {
    // 对应数据更新时pageId,更新监听
    this.init()
  }

  aboutToAppear(): void {
    // 初始化时
    this.init()
  }

  init(){
    if(this.pageId ===  EPageId.ONE){
      // 为当前页,触发部分回调
      promptAction.showToast({message: 'page one init func address'})
    }
  }

  build() {
    Column() {
      Text("page One")
      // Flex({}){
      //   Text("主标题xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxsdgdsgfsdfgsdgsdfgsdfgsd")
      //     .maxLines(1)
      //     .textOverflow({overflow: TextOverflow.Ellipsis})
      //
      //   Text("副标题xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxsdgdsgfsdfgsdgsdfgsdfgsd")
      //     .textOverflow({overflow: TextOverflow.Ellipsis})
      //     .maxLines(1)
      //     .flexBasis(40)
      //     .flexGrow(1)
      // }
    }
    .backgroundColor(Color.Gray)
    .height('100%')
    .width('100%')
  }
}

@Component
struct PageTwo{

  @Prop @Watch('onCountUpdated') pageId: number = 0;
  // @Watch 回调
  onCountUpdated(propName: string): void {
    // 对应数据更新时,pageId的更新监听,内部走某些逻辑
    this.init()
  }

  aboutToAppear(): void {
    // 初始化时
    this.init()
  }

  init(){
    if(this.pageId ===  EPageId.TWO){
      // 为当前页,触发部分回调
      promptAction.showToast({message: 'page two init func address'})
    }
  }

  build() {
    Column() {
      Text("page Two").fontColor(Color.White)
    }
    .backgroundColor(Color.Blue)
    .height('100%')
    .width('100%')
  }
}


@Component
struct PageTree{

  @Prop @Watch('onCountUpdated') pageId: number = 0;
  @State total: number = 0;
  // @Watch 回调
  onCountUpdated(propName: string): void {
    // 对应数据更新时pageId,更新监听
    this.init()
  }

  aboutToAppear(): void {
    // 初始化时
    this.init()
  }

  init(){
    if(this.pageId ===  EPageId.TREE){
      // 为当前页,触发部分回调
      promptAction.showToast({message: 'page tree init func address'})
    }
  }

  build() {
    Column() {
      Text("page Tree")
      // Flex({}){
      //   Text("主标题xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxsdgdsgfsdfgsdgsdfgsdfgsd")
      //     .maxLines(1)
      //     .textOverflow({overflow: TextOverflow.Ellipsis})
      //
      //   Text("副标题xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxsdgdsgfsdfgsdgsdfgsdfgsd")
      //     .textOverflow({overflow: TextOverflow.Ellipsis})
      //     .maxLines(1)
      //     .flexBasis(40)
      //     .flexGrow(1)
      // }
    }
    .backgroundColor(Color.Gray)
    .height('100%')
    .width('100%')
  }
}
分享
微博
QQ
微信
回复
2024-12-25 10:54:28
相关问题
HarmonyOS 如何将一个方法标记为过时
213浏览 • 1回复 待解决
如何将多工程的hap打包成一个app
1552浏览 • 1回复 待解决