HarmonyOS鸿蒙Next中如何实现页面上滑tabBar和顶部标题的悬停以及属性动画效果

HarmonyOS鸿蒙Next中如何实现页面上滑tabBar和顶部标题的悬停以及属性动画效果

【问题现象】

参照Scroll的示例3,实现了tabBar在页面顶部的悬停效果。

如果页面顶部还有一个标题栏(即下图中“首页”),现在要实现tab内容向上滚动时tabBar悬停到标题栏下方(即下图中“同城”,“推荐”,“活动”,“玩机”这一行),且可以实现标题栏在滚动过程中样式变化(如下图背景变化),该如何实现?

点击放大 点击放大

【背景知识】

【解决方案】

  1. 使用Stack层叠布局,将标题栏悬浮展示在页面顶部。

  2. 考虑页面滚动以及tabContent里面的list滚动就要考虑滚动嵌套问题,目前场景需要选择:

    • 向上滚动时,父组件先滚动,父组件滚动到边缘以后自身滚动;
    • 向下滚动时:自身先滚动,自身滚动到边缘以后父组件滚动。

    实现代码如下:

    .nestedScroll({
         scrollForward: NestedScrollMode.PARENT_FIRST,
         scrollBackward: NestedScrollMode.SELF_FIRST
    })
    
  3. 父组件滚动过程中,根据滚动偏移量线性修改标题栏样式(如字体大小、透明度、背景等),onDidScroll可以返回当前帧滚动的偏移量和当前滚动状态。

    具体实现代码如下:

    [@Entry](/user/Entry)
    [@Component](/user/Component)
    struct StickyNestedScroll {
      @State arr: number[] = []
      @State opacityNum: number = 0
      @State curYOffset: number = 0
    
      aboutToAppear() {
        for (let i = 0; i < 30; i++) {
          this.arr.push(i)
        }
      }
    
      @Styles
      listCard() {
        .backgroundColor(Color.White)
        .height(72)
        .width('calc(100% - 20vp)')
        .borderRadius(12)
        .margin({ left: 10, right: 10 })
      }
    
      build() {
        Stack() {
          Scroll() {
            Column() {
              Image($r('app.media.bg'))
                .width('100%')
                .height(300)
              Tabs({ barPosition: BarPosition.Start }) {
                TabContent() {
                  List({ space: 10 }) {
                    ForEach(this.arr, (item: number) => {
                      ListItem() {
                        Text("item" + item)
                          .fontSize(20)
                      }.listCard()
                    }, (item: string) => item)
                  }.width("100%")
                  .edgeEffect(EdgeEffect.None)
                  .nestedScroll({
                    scrollForward: NestedScrollMode.PARENT_FIRST,
                    scrollBackward: NestedScrollMode.SELF_FIRST
                  })
                }.tabBar("待办")
    
                TabContent() {
                }.tabBar("待阅")
              }
              .vertical(false)
              .width("100%")
              .height('calc(100% - 60vp)')
            }.width("100%")
          }
          .friction(0.6)
          .backgroundColor('# DCDCDC')
          .scrollBar(BarState.Off)
          .width('100%')
          .height('100%')
          .onDidScroll((xOffset: number, yOffset: number, scrollState: ScrollState): void => {
            // 累计计算当前父组件滚动在Y轴方向的偏移量
            this.curYOffset += yOffset
            // 根据父组件一共可以滚动的距离计算当前每帧的当前透明度
            let opacity = this.curYOffset / 240
            if (opacity >= 1) {
              opacity = 1
            }
            if (opacity <= 0) {
              opacity = 0
            }
            this.opacityNum = opacity
          })
    
          // 悬浮标题栏
          Text("工作台")
            .fontSize(24)
            .fontColor(Color.Black)
            .fontWeight(FontWeight.Bold)
            .backgroundColor(`rgba(255,255,255,${this.opacityNum})`)
            .position({ x: 0, y: 0 })
            .width('100%')
            .height(60)
            .padding({ left: 20 })
        }.width('100%')
        .height('100%')
      }
    }
    

效果如图:

点击放大 点击放大 点击放大

【总结】

  1. 悬浮类布局首先考虑Stack层叠布局;
  2. 嵌套滚动,考虑父子组件之前的先后滚动模式,选择合适的滚动模式;
  3. 滚动过程中,获取当前滚动每帧偏移量和滚动状态,做合适的UI更新。

更多关于HarmonyOS鸿蒙Next中如何实现页面上滑tabBar和顶部标题的悬停以及属性动画效果的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS鸿蒙Next中如何实现页面上滑tabBar和顶部标题的悬停以及属性动画效果的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


使用Stack层叠布局将标题栏悬浮在页面顶部

通过nestedScroll设置父组件和子组件的滚动模式,父组件先滚动,子组件后滚动。在onDidScroll回调中获取滚动偏移量,动态调整标题栏的样式,如背景透明度。具体代码见帖子内容。

回到顶部