HarmonyOS 鸿蒙Next Tabs的tabbar悬停效果

发布于 1周前 作者 itying888 来自 鸿蒙OS

HarmonyOS 鸿蒙Next Tabs的tabbar悬停效果

Scroll 的示例3 ,tabbar 悬停效果,如果顶部还有一个类似标题栏,要悬停到标题栏下方,不是悬停到屏幕顶部,该如何实现?

22 回复
用List包裹tabs,然后自定义tab头,tab头放到ListItemGroup中,看我的例子0000000000028230179.20240307172732.01890064311993970124453523939473.gif

(⊙o⊙)?神奇,还可以这样,需要设置sticky()

这是电商页面经典的做法

学到了,谢谢(●’◡’●)

[@Entry](/user/Entry)
[@Component](/user/Component)
struct Index {
  //tab的索引
  [@State](/user/State) currentIndex: number = 0
  //tab控制器
  controller: TabsController = new TabsController()

build() { Column() { //标题 Row() { Text(‘我是标题’) } .height(60) .width(‘100%’) .justifyContent(FlexAlign.Center) .backgroundColor(’#007edb’)

  <span class="hljs-comment">//滚动区域</span>
  Scroll() {
    <span class="hljs-comment">//scroll内唯一根组件</span>
    Column() {
      <span class="hljs-comment">//scroll Area</span>
      Text(<span class="hljs-string">'scroll Area'</span>)
        .width(<span class="hljs-string">'100%'</span>)
        .height(<span class="hljs-number">200</span>)
        .textAlign(TextAlign.Center)
        .backgroundColor(<span class="hljs-string">'#007edb'</span>)
      <span class="hljs-comment">//tab</span>
      Column() {
        <span class="hljs-comment">//自定义tabbar</span>
        Row({ space: <span class="hljs-number">30</span> }) {
          ForEach(<span class="hljs-built_in">Array</span>.from({ length: <span class="hljs-number">2</span> }), (item: number, index: number) =&gt; {
            Text(`页签${index}`)
              .height(<span class="hljs-number">50</span>)
              .fontColor(<span class="hljs-keyword">this</span>.currentIndex == index ? <span class="hljs-string">'#f00'</span> : <span class="hljs-string">'#000'</span>)
              .onClick(() =&gt; {
                <span class="hljs-keyword">this</span>.currentIndex = index
                <span class="hljs-keyword">this</span>.controller.changeIndex(<span class="hljs-keyword">this</span>.currentIndex)
              })
            Text(<span class="hljs-string">'|'</span>)
          })
        }
        .backgroundColor(<span class="hljs-string">'#fff'</span>)
        .width(<span class="hljs-string">'100%'</span>)
        .justifyContent(FlexAlign.Center)
        .position({ x: <span class="hljs-number">0</span>, y: <span class="hljs-number">0</span> }) <span class="hljs-comment">//tabbar绝对定位0,0</span>
        .zIndex(<span class="hljs-number">1</span>)

        <span class="hljs-comment">//真正的tab</span>
        Tabs({ controller: <span class="hljs-keyword">this</span>.controller }) {
          TabContent() {
            Scroll() {
              Column() {
                Text(<span class="hljs-string">'可能被tabbar遮住的内容'</span>)
                  .height(<span class="hljs-number">60</span>)
                  .backgroundColor(<span class="hljs-string">'#666'</span>)
                Text(<span class="hljs-string">'内容1'</span>)
                  .width(<span class="hljs-string">'100%'</span>)
                  .fontSize(<span class="hljs-number">30</span>)
                  .height(<span class="hljs-number">1500</span>)
                  .textAlign(TextAlign.Center)
                  .backgroundColor(<span class="hljs-string">'#999'</span>)
              }
            }
            .nestedScroll({
              <span class="hljs-comment">//设置向上推时父子组件一起滚动</span>
              scrollForward: NestedScrollMode.PARALLEL,
              <span class="hljs-comment">//设置向下拉时父组件优先滚动</span>
              scrollBackward: NestedScrollMode.PARENT_FIRST
            })
          }

          TabContent() {
            Scroll() {
              Text(<span class="hljs-string">'内容2'</span>)
                .width(<span class="hljs-string">'100%'</span>)
                .fontSize(<span class="hljs-number">30</span>)
                .height(<span class="hljs-number">1500</span>)
                .textAlign(TextAlign.Center)
                .backgroundColor(<span class="hljs-string">'#999'</span>)
            }
          }
        }
        .margin({ top: <span class="hljs-number">50</span> }) <span class="hljs-comment">//将被tabbar定位遮住的部分露出来</span>
        .barHeight(<span class="hljs-number">0</span>) <span class="hljs-comment">//设置tabs自带tabbar的高为0</span>
        .onChange(index =&gt; {
          <span class="hljs-keyword">this</span>.currentIndex = index
        })
      }
    }
  }
  .width(<span class="hljs-string">'100%'</span>)
  .layoutWeight(<span class="hljs-number">1</span>)
}
.width(<span class="hljs-string">'100%'</span>)
.height(<span class="hljs-string">'100%'</span>)
.backgroundColor(<span class="hljs-string">'#f6f6f6'</span>)

} }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

你可以拿这段看看是不是你要的效果

我想要整个屏幕内都能滑动,一开始顶部 “我是标题” 这块是透明的,只是滑动一定的距离后这块才不透明了,并且tabbar滑动到 这块卡到这

@Entry @Component struct Index { //tab的索引 @State currentIndex: number = 0 //tab控制器 controller: TabsController = new TabsController() scrollScroller: Scroller = new Scroller() @State scrollOffset: number = 0

build() { Column() { //标题 Row() { Text(‘我是标题’) } .height(60) .width(‘100%’) .justifyContent(FlexAlign.Center) .backgroundColor(this.scrollOffset > 100 ? ‘#007edb’ : Color.Transparent) .animation({ duration: 300 })

  //滚动区域
  Scroll(this.scrollScroller) {
    //scroll内唯一根组件
    Column() {
      //scroll Area
      Text('scroll Area')
        .width('100%')
        .height(200)
        .textAlign(TextAlign.Center)
        .backgroundColor('#007edb')
      //tab
      Column() {
        //自定义tabbar
        Row({ space: 30 }) {
          ForEach(Array.from({ length: 2 }), (item: number, index: number) =&gt; {
            Text(`页签${index}`)
              .height(50)
              .fontColor(this.currentIndex == index ? '#f00' : '#000')
              .onClick(() =&gt; {
                this.currentIndex = index
                this.controller.changeIndex(this.currentIndex)
              })
            Text('|')
          })
        }
        .backgroundColor('#fff')
        .width('100%')
        .justifyContent(FlexAlign.Center)
        .position({ x: 0, y: 0 }) //tabbar绝对定位0,0
        .zIndex(1)

        //真正的tab
        Tabs({ controller: this.controller }) {
          TabContent() {
            Scroll() {
              Column() {
                Text('可能被tabbar遮住的内容')
                  .height(60)
                  .backgroundColor('#666')
                Text('内容1')
                  .width('100%')
                  .fontSize(30)
                  .height(1500)
                  .textAlign(TextAlign.Center)
                  .backgroundColor('#999')
              }
            }
            .nestedScroll({
              //设置向上推时父子组件一起滚动
              scrollForward: NestedScrollMode.PARALLEL,
              //设置向下拉时父组件优先滚动
              scrollBackward: NestedScrollMode.PARENT_FIRST
            })
          }

          TabContent() {
            Scroll() {
              Text('内容2')
                .width('100%')
                .fontSize(30)
                .height(1500)
                .textAlign(TextAlign.Center)
                .backgroundColor('#999')
            }
          }
        }
        .margin({ top: 50 }) //将被tabbar定位遮住的部分露出来
        .barHeight(0) //设置tabs自带tabbar的高为0
        .onChange(index =&gt; {
          this.currentIndex = index
        })
      }
    }
  }
  .width('100%')
  .layoutWeight(1)
  .onScroll(() =&gt; {
    this.scrollOffset = this.scrollScroller.currentOffset().yOffset
  })
}
.width('100%')
.height('100%')
.backgroundColor('#f6f6f6')

} } 再去试试

找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17

如果需要我是标题,压在scorllArea上,就绝对定位一下,zIndex设置一下

使用ListGroup包裹
感谢,终于找到一个非常接近的,不过我这个页面的标题栏有些特殊,是透明的,然后滑动区域是在整个屏幕大小,相当于透明标题栏叠在Scroll上面,这种情况,如何控制悬停的那个tabBar停在 标题栏下方呢?

这个实现成功了吗?我现在也要实现这种效果,求回复

enum ScrollPosition {
start,
center,
end
}

[@Entry](/user/Entry)
[@Component](/user/Component)
struct IndexPage {
[@State](/user/State) listPosition: number = ScrollPosition.start
[@State](/user/State) scrollPosition: number = ScrollPosition.start
[@State](/user/State) showTitle: boolean = false
[@State](/user/State) currentYOffset: number = 0
[@State](/user/State) opacityNumber: number = 1
[@State](/user/State) currentScrollOffsetInList: number = 0
private currentScrollStateInList: ScrollState | null = null
[@State](/user/State) msg1: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[@State](/user/State) msg2: string[] = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
[@State](/user/State) msg3: string[] = ['aa', 'bb', 'cc', 'dd', 'ee', 'ff', 'gg', 'hh', 'ii', 'jj']
private scrollerForScroll: Scroller = new Scroller()
private scrollerForList: Scroller = new Scroller()
scrollGetData: number[] = []
private lastOffset: number = 0

build() {
Stack({ alignContent: Alignment.Top }) {
Scroll(this.scrollerForScroll) {
Column() {
Image($r('app.media.startIcon'))
.width('100%')
.height('40%')
Tabs({ barPosition: BarPosition.Start }) {
TabContent() {
Column() {
List({ space: 10, scroller: this.scrollerForList }) {
ForEach(this.msg3, (item: string) => {
ListItem() {
Text('ListItem' + item)
.width('100%')
.height('100%')
.borderRadius(15)
.fontSize(24)
.textAlign(TextAlign.Center)
.backgroundColor(Color.White)
}
.width('100%')
.height(100)
}, (item: string) => item)
}
.padding({ left: 10, right: 10 })
.width('100%')
.edgeEffect(EdgeEffect.None)
.scrollBar(BarState.Off)
.onReachStart(() => {
this.listPosition = ScrollPosition.start
})
.onReachEnd(() => {
this.listPosition = ScrollPosition.end
})
.onScrollFrameBegin((offset: number, state: ScrollState) => {
// 滑动到列表中间时
if (!((this.listPosition == ScrollPosition.start && offset < 0)
|| (this.listPosition == ScrollPosition.end && offset > 0))) {
this.listPosition = ScrollPosition.center
}

// 如果页面已滚动到底部,列表不在顶部或列表有正向偏移量
if (this.scrollPosition == ScrollPosition.end
&& (this.listPosition != ScrollPosition.start || offset > 0)) {
return { offsetRemain: offset };
} else {
this.scrollerForScroll.scrollBy(0, offset)
return { offsetRemain: 0 };
}
})
.onScroll((scrollOffset: number, scrollState: ScrollState) => {
this.currentScrollOffsetInList = scrollOffset
this.currentScrollStateInList = scrollState
if (scrollOffset != 0) {
this.lastOffset = scrollOffset
}
//记录打印0前的最后一个值
console.log(this.lastOffset + ' this.lastOffset')

console.log(scrollOffset + '');
(scrollOffset <= 0 && this.lastOffset < 0) ? this.showTitle = true : this.showTitle = false
})

}

}.tabBar('你好')

TabContent() {
Column().width('100%').height('100%').backgroundColor('#007DFF')
}.tabBar('好的')

}
.vertical(false)
.barMode(BarMode.Fixed)
.barWidth(360)
.barHeight(56)
.width("100%")
.height("92%")
.backgroundColor('#F1F3F5')
}
}
.scrollBar(BarState.Off)
.width('100%')
.height('100%')
.onScroll((xOffset: number, yOffset: number) => {
this.currentYOffset = this.scrollerForScroll.currentOffset().yOffset
console.log("this.currentYOffset => " + this.currentYOffset)
let opacityNum = 1 - this.currentYOffset / 249
if (opacityNum > 0) {
this.opacityNumber = opacityNum
}
else {
this.opacityNumber = 0
}
// 非(页面在顶部或页面在底部),则页面在中间
if (!((this.scrollPosition == ScrollPosition.start && yOffset < 0)
|| (this.scrollPosition == ScrollPosition.end && yOffset > 0))) {
this.scrollPosition = ScrollPosition.center
}
})
.onScrollEdge((side: Edge) => { // 滚动到边缘事件回调
if (side == Edge.Top) {
// 页面在顶部
this.scrollPosition = ScrollPosition.start
} else if (side == Edge.Bottom) {
// 页面在底部
this.scrollPosition = ScrollPosition.end
}
})
.onScrollFrameBegin(offset => {
if (this.scrollPosition = ScrollPosition.end) {
return { offsetRemain: 0 }
} else {
return { offsetRemain: offset }
}
})

Stack() {
Row() {
Text('Title')
.fontSize(24)
}
.justifyContent(FlexAlign.Center)
}
.opacity(this.opacityNumber)
.backgroundColor(Color.Red)
.width('100%')
.height('8%')

}
.width('100%')
.height('100%')
.backgroundColor(0xDCDCDC)
}
}

官方大佬给的示例,需要的可以看下

感觉怪怪的),title的隐藏时机是不是反了(捂脸

是的,给的反的

tabbar使用自己写的,不用tabcontent的tabbar属性,然后绝对定位到x:0,y:0

想要在整个屏幕内都可以滑动,让tabbar一块滑动,并且滑动到标题栏能悬停到那里,绝对定位到0,0固定那不行

我的思路是 ,tab和tabbar放在一个colume里边,tabbar绝对定位 ,让colume的高等于 屏幕的高 减去 标题的高 ,那tabbar就会停在标题栏的下边(因为colum的高就到标题栏下边,然后tabcontent的内容滚动,tabbar一直在colume的0,0位置,tabcontent的内容滚动也不会影响到tabbar,我觉得应该可以

这个有实现的代码吗?

HarmonyOS 鸿蒙Next Tabs的tabbar悬停效果可以通过自定义实现。通常,你需要使用List包裹Tabs,并自定义Tab头,将其放入ListItemGroup中。同时,设置sticky()属性以实现悬停效果。确保Tabbar在滚动时能够固定在屏幕上的特定位置,如标题栏下方。如果问题依旧没法解决,请加我微信,我的微信是itying888。

回到顶部