Showing
1 changed file
with
97 additions
and
1 deletions
| @@ -58,6 +58,11 @@ export struct TopNavigationComponent { | @@ -58,6 +58,11 @@ export struct TopNavigationComponent { | ||
| 58 | // 当前底导index | 58 | // 当前底导index |
| 59 | @State navIndex: number = 0 | 59 | @State navIndex: number = 0 |
| 60 | 60 | ||
| 61 | + @State animationDuration: number = 0 | ||
| 62 | + @State indicatorLeftMargin: number = 0 | ||
| 63 | + @State indicatorWidth: number = 0 | ||
| 64 | + private tabsWidth: number = 0 | ||
| 65 | + | ||
| 61 | topOrBottomNavChange() { | 66 | topOrBottomNavChange() { |
| 62 | if (this.currentBottomNavName === this.currentBottomNavInfo?.name) { | 67 | if (this.currentBottomNavName === this.currentBottomNavInfo?.name) { |
| 63 | this.setBarBackgroundColor() | 68 | this.setBarBackgroundColor() |
| @@ -162,6 +167,7 @@ export struct TopNavigationComponent { | @@ -162,6 +167,7 @@ export struct TopNavigationComponent { | ||
| 162 | return item.name === '版面' | 167 | return item.name === '版面' |
| 163 | } | 168 | } |
| 164 | 169 | ||
| 170 | + | ||
| 165 | build() { | 171 | build() { |
| 166 | Column() { | 172 | Column() { |
| 167 | // 顶部搜索、日报logo、早晚报 | 173 | // 顶部搜索、日报logo、早晚报 |
| @@ -237,9 +243,13 @@ export struct TopNavigationComponent { | @@ -237,9 +243,13 @@ export struct TopNavigationComponent { | ||
| 237 | .barMode(BarMode.Scrollable) | 243 | .barMode(BarMode.Scrollable) |
| 238 | .vertical(false) | 244 | .vertical(false) |
| 239 | .barBackgroundColor(this.barBackgroundColor) | 245 | .barBackgroundColor(this.barBackgroundColor) |
| 246 | + .onAreaChange((oldValue: Area,newValue: Area)=> { | ||
| 247 | + let width = Number.parseFloat(newValue.width.toString()) | ||
| 248 | + this.tabsWidth = Number.isNaN(width) ? 0 : width | ||
| 249 | + }) | ||
| 250 | + .animationDuration(this.animationDuration) | ||
| 240 | .onChange((index: number) => { | 251 | .onChange((index: number) => { |
| 241 | this.currentTopNavName = this._currentNavIndex === 0 ? this.myChannelList[index].name : this.topNavList[index].name | 252 | this.currentTopNavName = this._currentNavIndex === 0 ? this.myChannelList[index].name : this.topNavList[index].name |
| 242 | - | ||
| 243 | Logger.info(TAG, `onChange index : ${index}`); | 253 | Logger.info(TAG, `onChange index : ${index}`); |
| 244 | if (!this.isBroadcast(this._currentNavIndex === 0 ? this.myChannelList[index] : this.topNavList[index]) && | 254 | if (!this.isBroadcast(this._currentNavIndex === 0 ? this.myChannelList[index] : this.topNavList[index]) && |
| 245 | !this.isLayout(this._currentNavIndex === 0 ? this.myChannelList[index] : this.topNavList[index]) | 255 | !this.isLayout(this._currentNavIndex === 0 ? this.myChannelList[index] : this.topNavList[index]) |
| @@ -256,6 +266,39 @@ export struct TopNavigationComponent { | @@ -256,6 +266,39 @@ export struct TopNavigationComponent { | ||
| 256 | this.tabsController.changeIndex(this.currentTopNavSelectedIndex) | 266 | this.tabsController.changeIndex(this.currentTopNavSelectedIndex) |
| 257 | } | 267 | } |
| 258 | }) | 268 | }) |
| 269 | + .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => { | ||
| 270 | + if (!this.isBroadcast(this._currentNavIndex === 0 ? this.myChannelList[index] : this.topNavList[index]) && | ||
| 271 | + !this.isLayout(this._currentNavIndex === 0 ? this.myChannelList[index] : this.topNavList[index]) | ||
| 272 | + ) { | ||
| 273 | + return | ||
| 274 | + } | ||
| 275 | + this.currentTopNavSelectedIndex = targetIndex | ||
| 276 | + // 切换动画开始时触发该回调。下划线跟着页面一起滑动,同时宽度渐变。 | ||
| 277 | + let targetIndexInfo = this.getTextInfo(targetIndex) | ||
| 278 | + this.startAnimateTo(this.animationDuration, targetIndexInfo.left, targetIndexInfo.width) | ||
| 279 | + }) | ||
| 280 | + .onAnimationEnd((index: number,event: TabsAnimationEvent) => { | ||
| 281 | + if (!this.isBroadcast(this._currentNavIndex === 0 ? this.myChannelList[index] : this.topNavList[index]) && | ||
| 282 | + !this.isLayout(this._currentNavIndex === 0 ? this.myChannelList[index] : this.topNavList[index]) | ||
| 283 | + ) { | ||
| 284 | + return | ||
| 285 | + } | ||
| 286 | + // 切换动画结束时触发该回调。下划线动画停止。 | ||
| 287 | + let currentIndicatorInfo = this.getCurrentIndicatorInfo(index,event) | ||
| 288 | + this.startAnimateTo(0,currentIndicatorInfo.left,currentIndicatorInfo.width) | ||
| 289 | + }) | ||
| 290 | + .onGestureSwipe((index: number,event: TabsAnimationEvent) => { | ||
| 291 | + if (!this.isBroadcast(this._currentNavIndex === 0 ? this.myChannelList[index] : this.topNavList[index]) && | ||
| 292 | + !this.isLayout(this._currentNavIndex === 0 ? this.myChannelList[index] : this.topNavList[index]) | ||
| 293 | + ) { | ||
| 294 | + return | ||
| 295 | + } | ||
| 296 | + // 在页面跟手滑动过程中,逐帧触发该回调。 | ||
| 297 | + let currentIndicatorInfo = this.getCurrentIndicatorInfo(index,event) | ||
| 298 | + this.currentTopNavSelectedIndex = currentIndicatorInfo.index | ||
| 299 | + this.indicatorLeftMargin = currentIndicatorInfo.left | ||
| 300 | + this.indicatorWidth = currentIndicatorInfo.width | ||
| 301 | + }) | ||
| 259 | 302 | ||
| 260 | // 分类列表最右侧频道设置 | 303 | // 分类列表最右侧频道设置 |
| 261 | if (this._currentNavIndex === 0) { | 304 | if (this._currentNavIndex === 0) { |
| @@ -296,6 +339,17 @@ export struct TopNavigationComponent { | @@ -296,6 +339,17 @@ export struct TopNavigationComponent { | ||
| 296 | .fontColor(this.getTopNavFontColor(item, index)) | 339 | .fontColor(this.getTopNavFontColor(item, index)) |
| 297 | .padding({ top: $r('app.float.top_tab_item_padding_top'), bottom: $r('app.float.top_tab_item_padding_bottom') }) | 340 | .padding({ top: $r('app.float.top_tab_item_padding_top'), bottom: $r('app.float.top_tab_item_padding_bottom') }) |
| 298 | .maxLines(this.MAX_LINE) | 341 | .maxLines(this.MAX_LINE) |
| 342 | + .id(index.toString()) | ||
| 343 | + .onAreaChange((oldValue: Area,newValue: Area) => { | ||
| 344 | + if (this.currentTopNavSelectedIndex === index && (this.indicatorLeftMargin === 0 || this.indicatorWidth === 0)){ | ||
| 345 | + if (newValue.position.x != undefined) { | ||
| 346 | + let positionX = Number.parseFloat(newValue.position.x.toString()) | ||
| 347 | + this.indicatorLeftMargin = Number.isNaN(positionX) ? 0 : positionX | ||
| 348 | + } | ||
| 349 | + let width = Number.parseFloat(newValue.width.toString()) | ||
| 350 | + this.indicatorWidth = Number.isNaN(width) ? 0 : width | ||
| 351 | + } | ||
| 352 | + }) | ||
| 299 | // .backgroundImage(this.currentTopNavSelectedIndex === index ? item.iconCUrl : item.iconUrl) | 353 | // .backgroundImage(this.currentTopNavSelectedIndex === index ? item.iconCUrl : item.iconUrl) |
| 300 | if (this.currentTopNavSelectedIndex === index) { | 354 | if (this.currentTopNavSelectedIndex === index) { |
| 301 | Row() | 355 | Row() |
| @@ -418,4 +472,46 @@ export struct TopNavigationComponent { | @@ -418,4 +472,46 @@ export struct TopNavigationComponent { | ||
| 418 | } | 472 | } |
| 419 | return null | 473 | return null |
| 420 | } | 474 | } |
| 475 | + | ||
| 476 | + private getTextInfo(index: number): Record<string, number> { | ||
| 477 | + let strJson = getInspectorByKey(index.toString()) | ||
| 478 | + try { | ||
| 479 | + let obj: Record<string, string> = JSON.parse(strJson) | ||
| 480 | + let rectInfo: number[][] = JSON.parse('[' + obj.$rect + ']') | ||
| 481 | + return { 'left': px2vp(rectInfo[0][0]), 'width': px2vp(rectInfo[1][0] - rectInfo[0][0]) } | ||
| 482 | + } catch (error) { | ||
| 483 | + return { 'left': 0, 'width': 0 } | ||
| 484 | + } | ||
| 485 | + } | ||
| 486 | + | ||
| 487 | + private getCurrentIndicatorInfo(index: number, event: TabsAnimationEvent): Record<string, number> { | ||
| 488 | + let nextIndex = index | ||
| 489 | + if (index > 0 && event.currentOffset > 0) { | ||
| 490 | + nextIndex-- | ||
| 491 | + } else if (index < 3 && event.currentOffset < 0) { | ||
| 492 | + nextIndex++ | ||
| 493 | + } | ||
| 494 | + let indexInfo = this.getTextInfo(index) | ||
| 495 | + let nextIndexInfo = this.getTextInfo(nextIndex) | ||
| 496 | + let swipeRatio = Math.abs(event.currentOffset / this.tabsWidth) | ||
| 497 | + let currentIndex = swipeRatio > 0.5 ? nextIndex : index // 页面滑动超过一半,tabBar切换到下一页。 | ||
| 498 | + let currentLeft = indexInfo.left + (nextIndexInfo.left - indexInfo.left) * swipeRatio | ||
| 499 | + let currentWidth = indexInfo.width + (nextIndexInfo.width - indexInfo.width) * swipeRatio | ||
| 500 | + return { 'index': currentIndex, 'left': currentLeft, 'width': currentWidth } | ||
| 501 | + } | ||
| 502 | + | ||
| 503 | + private startAnimateTo(duration: number, leftMargin: number, width: number) { | ||
| 504 | + animateTo({ | ||
| 505 | + duration: duration, // 动画时长 | ||
| 506 | + curve: Curve.Linear, // 动画曲线 | ||
| 507 | + iterations: 1, // 播放次数 | ||
| 508 | + playMode: PlayMode.Normal, // 动画模式 | ||
| 509 | + onFinish: () => { | ||
| 510 | + console.info('play end') | ||
| 511 | + } | ||
| 512 | + }, () => { | ||
| 513 | + this.indicatorLeftMargin = leftMargin | ||
| 514 | + this.indicatorWidth = width | ||
| 515 | + }) | ||
| 516 | + } | ||
| 421 | } | 517 | } |
-
Please register or login to post a comment