HarmonyOS鸿蒙Next中Tabs组件实现的侧边栏,如何实现自顶到底的效果

HarmonyOS鸿蒙Next中Tabs组件实现的侧边栏,如何实现自顶到底的效果

【问题现象】

在实现侧边栏时,希望侧边栏从最顶部开始往下排列,在条目撑满侧边栏时可以滑动,且在选中条目时能自动居中。但是使用Tabs组件中把页签设置在侧边,页签中的条目始终是居中排列,无法做到从最顶部开始往下排列,如下图:

点击放大

【背景知识】

  • Tabs组件的使用:是一种常见的界面导航结构。通过页签容器,用户可以快捷地访问应用的不同模块。
  • 使用Tabs组件时,可以使用barMode(BarMode.Scrollable)配置实现可滚动页签,但是Tabs组件中条目高度无法自定义,而且条目数量未撑满Tabs组件时,无法实现自顶到底的效果。

【解决方案】

由于原生Tabs组件无法实现自顶到底的效果,所以只能实现自定义组件来达到此效果。本篇采取Column + Scroll实现自定义TabBar组件,如下:

(1)用Column组件实现侧边栏,通过设置justifyContent(FlexAlign.Start)来实现侧边栏条目从顶部开始;

(2)用Scroll组件实现选中侧边栏条目时居中效果;

  • 侧边栏从顶部开始。

代码示例如下:

Column({
  Text("tab0")
    .tabBarStyle(this.currentIndex == 0)
    .onClick(() => {
      this.currentIndex = 0
    })
  Text("tab1")
    .tabBarStyle(this.currentIndex == 1)
    .onClick(() => {
      this.currentIndex = 1
    })
}
.justifyContent(FlexAlign.Start) // 设置自顶向下
  • 页面超过一半时TabBar组件内条目切换到下一页。

代码示例如下:

// 滑动页面超过一半时页面切换
this.swipeRatio = Math.abs(event.currentOffset / this.tabsWidth);
let currentIndex = this.swipeRatio > 0.5 ? nextIndex : index; // 页面滑动超过一半,TabBar组件切换到下一页。
let currentLeft = indexInfo.left + (nextIndexInfo.left - indexInfo.left) * this.swipeRatio;
let currentWidth = indexInfo.width + (nextIndexInfo.width - indexInfo.width) * this.swipeRatio;
this.indicatorIndex = currentIndex;
return { 'index': currentIndex, 'left': currentLeft, 'width': currentWidth };
  • TabBar组件内条目可滑动时,将其定位在正中间。

代码示例如下:

this.scroller.scrollTo({
  // 选中后定位在正中间
  xOffset: 0,
  yOffset: currentOffsetY + tabPositionTop - screenHeight / 2 + tabHeight / 2,
  animation: {
    duration: this.animationDuration,
    curve: this.animationCurve, // 设置动画曲线
  }
});

实现效果:

点击放大


更多关于HarmonyOS鸿蒙Next中Tabs组件实现的侧边栏,如何实现自顶到底的效果的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS鸿蒙Next中Tabs组件实现的侧边栏,如何实现自顶到底的效果的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


使用Column + Scroll实现自定义TabBar组件

通过设置justifyContent(FlexAlign.Start)使侧边栏条目从顶部开始排列。Scroll组件用于实现选中条目时自动居中效果。代码示例如下:

Column({
  Text("tab0")
    .tabBarStyle(this.currentIndex == 0)
    .onClick(() => {
      this.currentIndex = 0
    })
  Text("tab1")
    .tabBarStyle(this.currentIndex == 1)
    .onClick(() => {
      this.currentIndex = 1
    })
}
.justifyContent(FlexAlign.Start) // 设置自顶向下

滑动页面超过一半时,TabBar组件内条目切换到下一页:

// 滑动页面超过一半时页面切换
this.swipeRatio = Math.abs(event.currentOffset / this.tabsWidth);
let currentIndex = this.swipeRatio > 0.5 ? nextIndex : index; // 页面滑动超过一半,TabBar组件切换到下一页。
let currentLeft = indexInfo.left + (nextIndexInfo.left - indexInfo.left) * this.swipeRatio;
let currentWidth = indexInfo.width + (nextIndexInfo.width - indexInfo.width) * this.swipeRatio;
this.indicatorIndex = currentIndex;
return { 'index': currentIndex, 'left': currentLeft, 'width': currentWidth };

TabBar组件内条目可滑动时,将其定位在正中间:

this.scroller.scrollTo({
  // 选中后定位在正中间
  xOffset: 0,
  yOffset: currentOffsetY + tabPositionTop - screenHeight / 2 + tabHeight / 2,
  animation: {
    duration: this.animationDuration,
    curve: this.animationCurve, // 设置动画曲线
  }
});
回到顶部