鸿蒙6.0应用开发——Tabs多种应用场景
文章摘要 本文详细介绍了Tabs组件在应用开发中的多样化应用场景和实现方法。首先分析了Tabs组件的三种常见导航样式:底部导航(主导航)、顶部导航(二级导航)和侧边导航(横屏适配),分别通过barPosition和vertical参数实现。其次阐述了页签对齐方式的定制方法,通过barModifier属性实现灵活布局。然后重点讲解了自定义页签样式的实现方案,包括图标+文字的组合样式和选中态变化效果。
概述
在日常开发中,开发者经常遇到使用Tabs作为导航的场景,包括多层嵌套的Tabs、自定义Tabs样式、Tabs数据加载和动态变更显示的Tabs等。
开发者在实际开发中往往需要处理多个功能点的配合,以及与其他组件或数据的互动。为了帮助开发者更直观和全面地理解Tabs组件,本文通过将这些场景整合到一个应用首页的具体实例中,展示Tabs组件的各项功能及其协同效果,以及与其他组件或数据的联动。
Tabs显示排版
在Tabs组件的应用场景中,开发者通常会自定义Tabs的布局和样式。本章节将介绍Tabs组件提供的几种常用的布局和样式功能。
Tabs导航样式
常见的应用页签导航效果包括底部导航、顶部导航和侧边导航。

底部导航栏通常用于应用的主导航,其标签数量相对固定,不涉及TabBar滑动。作为应用的主导航,开发者通常会自定义TabBar的样式。底部导航栏可通过设置Tabs的barPosition参数来实现,需将barPosition设置为BarPosition.End。
Tabs({
barPosition: BarPosition.End,
// ...
}) {
// ...
}
顶部导航栏主要用于主栏目的二级导航。由于二级导航可能包含较多的页签项,其TabBar通常设计为可滚动显示,并能动态调整所显示的页签。同样地,顶部导航栏通过将Tabs的barPosition参数设置为BarPosition.Start来实现。
Tabs({
barPosition: BarPosition.Start,
// ...
}) {
// ...
}
侧边导航栏常见于横屏界面的导航。由于横屏界面尺寸规格的差异,导航条的页签需要适配宽度和高度,以确保更佳的显示效果。侧边导航栏的实现方式有所不同,需要将Tabs的vertical属性设置为true,而Tabs的barPosition参数则用于控制导航栏显示在左侧或右侧。
Tabs({
// ...
}) {
// ...
}
.vertical(false) // true to make the tab bar in side
页签对齐方式
当页签数量不足,无法铺满屏幕宽度或高度,或者铺满后影响到UI美观时,Tabs提供了自定义导航条页签对齐方式的API。例如,在应用的二级导航中,如果页签较少,可以考虑将页签居左对齐。

实现原理
通过barModifier属性设置tabBar的align参数,可以实现页签对齐布局效果。类似于文本对齐,开发者可以自行设置居中、居上、居下、居左或者居右对齐。
说明
- 只有在TabBar的barMode为BarMode.Scrollable时,这些设置才会生效。除此之外,还可以通过barModifier参数设置一系列的通用属性。
- 居上居下对齐仅在侧边导航栏中生效。若要控制顶部和底部导航栏中页签与顶部的距离,同样可以使用barModifier设置padding属性,以保持页签与TabBar顶部的特定间距。
开发步骤
定义tabBarModifier属性,并将其作为参数构造Tabs,然后通过tabBarModifier设置对齐方式。
@Component
export default struct InTabsComponent {
// ...
@State tabBarModifier: CommonModifier = new CommonModifier();
// ...
async aboutToAppear() {
// ...
this.tabBarModifier.margin({ right: 56 }).align(Alignment.Start);
// ...
}
// ...
build() {
// ...
Tabs({
// ...
barModifier: this.tabBarModifier
}) {
// ...
}
// ...
}
}
自定义页签
对于底部导航栏,通常用于应用主页面的功能区分。为了更好的用户体验,开发者通常会自定义页签样式。开发者可以使用Tabs组件提供的定制页签样式的API,将页签自定义为图标加文字标题的形式,并且在选中和非选中的状态下,提供不同的样式。

实现原理
Tabs组件的tabBar()方法接受联合类型的参数,可以将由@Builder修饰的UI构建函数作为参数传入,以自定义TabBar的样式。因此,开发者可以定义一个UI构建函数tabBuilder(),作为参数传递给tabBar()方法。由于选中的页签和未选中的页签需要不同的样式,还需定义一个由@State修饰的数值型变量currentIndex,用于在tabBuilder()函数中判断当前页签是否被选中。当currentIndex发生变化时,能够触发tabBar样式的更新。最后,注册Tabs组件的onchange函数,在该函数中更新currentIndex的值。
开发步骤
-
定义currentIndex属性。
@Component export default struct OutTabsComponent { @State currentIndex: number = 0; // ... } -
定义@Builder装饰器修饰的自定义样式构建方法tabBuilder()。
@Builder tabBuilder(index: number, name: string | Resource, icon: Resource) { Column() { // set special styles if selected SymbolGlyph(icon).fontColor([this.currentIndex === index ? $r('app.color.out_tab_bar_font_active_color') : $r('app.color.out_tab_bar_font_inactive_color')]) .fontSize(25) Text(name) .margin({ top: 4 }) .fontSize(10) .fontColor(this.currentIndex === index ? $r('app.color.out_tab_bar_font_active_color') : $r('app.color.out_tab_bar_font_inactive_color')) } .justifyContent(FlexAlign.Center) .height(Constants.FULL_HEIGHT) .width(Constants.FULL_WIDTH) .padding({ bottom: 60 }) // .backgroundColor($r('app.color.out_tab_bar_background_color')) } -
将tabBuilder()方法传入Tabs,并在Tabs注册onChange()函数,并在其中更新currentIndex属性。
Tabs({ // ... }) { TabContent() { InTabsComponent({ switchNext: this.switchNext }) }.tabBar(this.tabBuilder(0, $r('app.string.out_bar_text_home'), $r('sys.symbol.house'))) // ... } // ... .onChange((index: number) => { this.currentIndex = index; })
Tabs吸顶
在一些二级导航栏页面中,二级页签的内容上方通常会放置一些banner位或其他优先级较高的内容,并且在向上滑动时会退出显示区域。为了提供更好的用户体验,建议在上划的过程中,导航条能够吸附在顶部,便于用户进行内容切换。

实现原理
开发者可以通过设置滑动组件的属性nestedScroll来控制父子组件的滑动顺序,从而实现吸顶效果。具体而言,需确保TabContent内容是可滑动的,并且Tabs的上层父组件也必须是可滑动的。为内容组件添加nestedScroll属性,设置为当向上滑动时父组件先动,而向下滑动时自己先动,从而实现滑动吸顶效果。
开发步骤
在Tabs父组件上嵌套Scroll组件,TabContent中的List组件显示内容,List组件本身是可滑动的,仅需设置其滑动触发行为即可。
Scroll() {
Column() {
BannerComponent()
Stack({ alignContent: Alignment.TopEnd }) {
// ...
Column() {
Tabs({
// ...
}) {
// bind selected tabs to ui
ForEach(this.selectTabsViewModel.selectedTabs, (tab: TabItemViewModel, index: number) => {
if (index === this.selectTabsViewModel.selectedTabs.length - 1) {
TabContent() {
List({ space: 10 }) {
// ...
}
// ...
// set the sliding behavior to move up parent first, and move down self first
.nestedScroll({
scrollForward: NestedScrollMode.PARENT_FIRST,
scrollBackward: NestedScrollMode.SELF_FIRST
})
}
// ...
} else {
// ...
}
}, (tab: TabItemViewModel, index: number) => index + '_' + JSON.stringify(tab))
}
// ...
}
.width(Constants.FULL_WIDTH)
.height(Constants.FULL_HEIGHT)
.backgroundColor($r('app.color.out_tab_bar_background_color'))
}
}
}
TabsBar显示效果
在某些UI设计风格中,可能需要为TabBar采用特殊样式,比如首页导航栏的毛玻璃背景效果等。
-
通过设置Tabs组件的barOverlap属性,可以实现TabBar变模糊并叠加在TabContent之上,并且配合barBackgroundBlurStyle
属性实现毛玻璃效果。
Tabs({ // ... }) { // ... } // ... .barOverlap(true) .barBackgroundBlurStyle(BlurStyle.Thin)底部导航栏覆盖在内容上方,并具有毛玻璃效果。

-
通过barModifier设置tabBar的clip属性,实现页签超出tabBar区域显示效果。
@Component export default struct OutTabComponent { // ... private controller: TabsController = new TabsController(); aboutToAppear(): void { this.tabBarModifier.clip(false); } // ... build() { Column() { Tabs({ // ... barModifier: this.tabBarModifier }) { // ... } // ... } .width('100%') .height('calc(100% + 60vp)') .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM]) } }底层导航栏图标可超出导航条范围。

-
通过配置fadingEdge(true)实现TabBar边缘渐隐。
Tabs({controller: this.subController}){ // ... } .fadingEdge(this.isFadingEdge) // true set tab bar edge fade顶部导航栏页签靠近两侧会模糊化。

-
通过TabsController的setTabBarTranslate()、setTabBarOpacity()方法可以设置TabBar偏移量及透明度。
@Component export default struct InTabComponent { // ... private subController: TabsController = new TabsController(); onDidBuild(): void { if (this.isSetTabBarTranslateAndOpacity) { this.subController.setTabBarTranslate({x:-20,y:30}); this.subController.setTabBarOpacity(0.5); } } // ... build() { Tabs({controller: this.subController}){ // ... } // ... .barMode(BarMode.Scrollable) } }顶部导航栏位置向左下偏移,并且呈现半透明效果。

说明
在以下情况下,该设置无法生效:当显示内容过长时,通常会将其置于可滚动容器组件中,并在向上滑动时隐藏TabBar,向下滑动时显示。此时,会使用bindTabsToScrollable或bindTabsToNestedScrollable等接口将Tabs组件与可滚动容器组件绑定。由于TabBar的控制与滚动组件联动,通过setTabBarOpacity接口设置的TabBar偏移量和不透明度将不再生效。
更多推荐



所有评论(0)