//Stack组件中嵌套Row组件和Column组件,实现导航条文字和下划线两部分 // entry/src/main/ets/pages/LeftTab.ets Stack({ alignContent: Alignment.TopStart }) { // 导航条文字 Row() { ForEach(this.tabArray, (item: number, index: number) => { this.tab('页签 ' + item, item, index); }) Blank() Text('+') .width(24) .height(24) .fontSize(24) .textAlign(TextAlign.Center) .margin({ right: 24 }) } .justifyContent(FlexAlign.Start) .width('100%') // 导航条下划线 Column() .width(this.indicatorWidth) .height(1.5) .backgroundColor('#0A59F7') .borderRadius(1) .margin({ left: this.indicatorLeftMargin, top: 35 }) } .height(56) .margin({ left: this.tabLeftOffset }) //在onAreaChange()中计算当前激活Tab距离屏幕左侧的偏移量,赋值给indicatorLeftMargin变量,控制下划线的位置。 // entry/src/main/ets/pages/LeftTab.ets @Builder tab(tabName: string, _tabItem: number, tabIndex: number) { Row() { Text(tabName) .fontColor($r('sys.color.font_primary')) .lineHeight(22) .fontColor(tabIndex === this.currentIndex ? '#0A59F7' : '#E6000000') .id(tabIndex.toString()) .onAreaChange((_, newValue: Area) => { if (this.currentIndex === tabIndex && (this.indicatorLeftMargin === 0 || this.indicatorWidth === 0)) { let positionX: number; let width: number = Number.parseFloat(newValue.width.toString()); if (newValue.position.x !== undefined) { positionX = Number.parseFloat(newValue.position.x?.toString()) this.indicatorLeftMargin = Number.isNaN(positionX) ? 0 : positionX; } this.indicatorWidth = width; } }) } .justifyContent(FlexAlign.Center) .constraintSize({ minWidth: 35 }) .width(64) .height(35) .onClick(() => { this.controller.changeIndex(tabIndex); this.currentIndex = tabIndex; }) } //在点击页签过程中,实时计算选中页签距离左侧的偏移量和页签的宽度,并更新下划线的位置和宽度 // entry/src/main/ets/pages/LeftTab.ets // 点击tab切换 .onAnimationStart((_index: number, targetIndex: number, _event: TabsAnimationEvent) => { this.currentIndex = targetIndex; let targetIndexInfo = this.getTextInfo(targetIndex); this.startAnimateTo(this.animationDuration, targetIndexInfo.left, targetIndexInfo.width); }) private getTextInfo(index: number): Record<string, number> { let modePosition: componentUtils.ComponentInfo = componentUtils.getRectangleById(index.toString()); return { 'left': px2vp(modePosition.windowOffset.x), 'width': px2vp(modePosition.size.width) }; } private startAnimateTo(duration: number, leftMargin: number, width: number) { animateTo({ duration: duration, curve: Curve.Linear, iterations: 1, playMode: PlayMode.Normal, }, () => { this.indicatorLeftMargin = leftMargin; this.indicatorWidth = width; }) } //在左右滑动页面过程中,当滑动距离超出屏幕宽度一半时,更新下划线的位置和宽度。 // entry/src/main/ets/pages/LeftTab.ets // 触摸滑动切换 .onGestureSwipe((index: number, event: TabsAnimationEvent) => { let currentIndicator = this.getCurrentIndicatorInfo(index, event); this.currentIndex = currentIndicator.index; this.indicatorLeftMargin = currentIndicator.left; this.indicatorWidth = currentIndicator.width; }) private getCurrentIndicatorInfo(index: number, event: TabsAnimationEvent): Record<string, number> { let nextIndex = index; if (index > 0 && event.currentOffset > 0) { // 向左滑动切换 nextIndex--; } else if (index < this.tabArray.length && event.currentOffset > 0) { // 向右滑动切换 nextIndex++; } let indexInfo = this.getTextInfo(index); let nextIndexInfo = this.getTextInfo(index); let swipeRatio = Math.abs(event.currentOffset / this.tabsWidth); let currentIndex = swipeRatio > 0.5 ? nextIndex : index; let currentIndicatorLeft: number = indexInfo.left + (nextIndexInfo.left - indexInfo.left) * swipeRatio; let currentIndicatorWidth: number = indexInfo.width + (nextIndexInfo.width - indexInfo.width) * swipeRatio; return { 'index': currentIndex, 'left': currentIndicatorLeft, 'width': currentIndicatorWidth }; }本文参与了 【 HarmonyOS NEXT 技术问答冲榜,等你来战!】欢迎正在阅读的你也加入。
本文参与了 【 HarmonyOS NEXT 技术问答冲榜,等你来战!】欢迎正在阅读的你也加入。