鸿蒙Next Tabs实现底部导航进阶

目标:实现一个仿微信底部Tab标签随页面滑动颜色渐变的效果

最终效果:

实现思路: 1.需要用到tabs两个回调函数: **onGestureSwipe(handler: (index: number, event: TabsAnimationEvent) => void)**在页面跟手滑动过程中,逐帧触发该回调 通过这个函数回调,我们可以知道手指滑动的距离,和滑动方向,然后根据滑动距离和屏幕宽度计算一个百分比,用做修改tab的色值透明度 onAnimationStart(handler: (index: number, targetIndex: number, event: TabsAnimationEvent) => void) 通过这个函数,我们可以知道滑动触发切换成功,页面已经切换,这里我们将最终色值属性赋值 2.滑动涉及到当前选中和滑动目标页,因此需要定义两个index作为标记,用作text和image判断是否是当前页面和目标页。 3.tab的设计用stack层叠布局,下面放默认状态的布局,不进行修改,上面叠一个变化的布局,即选中状态的样式,通过改变这个布局的透明度,做到渐变 4.当前选中页tab的透明度和目标页的透明度如何根据index设置,给出一段伪代码参考

arduino 复制代码
//if (选中页==index){
//  if(目标页==index){
//    认为是没有滑动,显示正常选中状态 即 透明度=1
//  }else{
//    滑动中,选中页的图片透明度 变化范围是[1-0]
//  }
// }else{
//    if(目标页==index){
//      滑动中,目标页的图片透明度 变化范围是[0-1]
//    }else{
//      不是目标页 也不是当前页 其他页 选中状态的图片透明度 = 0
//    }
// }

实现代码:

kotlin 复制代码
import { getScreenWidth } from '../utils/DisplayUtil';
import Logger from '../utils/Logger'

@Entry
@ComponentV2
struct MainPage{
  tabsController: TabsController = new TabsController();
  pageInfos: NavPathStack = new NavPathStack()
  beginMoveTime :number = 0;
  @Local currentIndex: number = 0; //当前tab页
  @Local targetIndex: number = 0;  //目标tab页
  @Local currentOpacity:number = 1; //当前tab页 tab选中情况下的透明度  变化值1-0
  @Local targetOpacity:number = 0; //目标tab页 tab 将要被选中时的透明度 变化值0-1

  @Builder
  tabBuilder(title: string, index: number, selectedImg: Resource, normalImg: Resource) {
    Column() {
      Stack(){
        Image(normalImg)
          .width(24)
          .height(24)
          .objectFit(ImageFit.Contain)
        Image(selectedImg)
          .width(24)
          .height(24)
          .objectFit(ImageFit.Contain)
          .opacity(this.currentIndex === index?  //如果选择当前的tab 则该图片显示 不透明 如果在移动过程中 target 透明度0-1 当前1-0
            this.targetIndex===index?1:this.currentOpacity:this.targetIndex===index?this.targetOpacity:0)
      }
      Stack(){
        Text(title)
          .margin({ top: 4 })
          .fontSize(12)
          .fontColor('#9E9E9E')
        Text(title)
          .margin({ top: 4 })
          .fontSize(12)
          .fontColor('#007AFF')
          .opacity(this.currentIndex === index?
            this.targetIndex===index?1:this.currentOpacity
            :this.targetIndex===index?this.targetOpacity:0)
        //if (选中页==index){
        //  if(目标页==index){
        //    认为是没有滑动,显示正常选中状态 即 透明度=1
        //  }else{
        //    滑动中,选中页的图片透明度 变化范围是[1-0]
        //  }
        // }else{
        //    if(目标页==index){
        //      滑动中,目标页的图片透明度 变化范围是[0-1]
        //    }else{
        //      不是目标页 也不是当前页 其他页 选中状态的图片透明度 = 0
        //    }
        // ]
      }

    }
    .justifyContent(FlexAlign.Center)
    .height(52)
    .width('100%')
    .onClick(() => {
      this.currentIndex = index;
      this.targetIndex = index;
      this.tabsController.changeIndex(this.currentIndex);
    })
  }
  @Builder
  tabContentBuilder(text: string, index: number, selectedImg: Resource, normalImg: Resource) {
    TabContent() {
      Row() {
        Text(text)
          .height(300)
          .fontSize(30)
      }
      .width('100%')
      .justifyContent(FlexAlign.Center)
    }
    .backgroundColor(Color.White)
    .tabBar(this.tabBuilder(text, index, selectedImg, normalImg))
  }
  build() {
    Navigation(this.pageInfos){
      Tabs({ barPosition: BarPosition.End, controller:this.tabsController}) {
        this.tabContentBuilder('首页', 0, $r('app.media.map_tab_home_sel'), $r('app.media.map_tab_home_nor'))
        this.tabContentBuilder('消息', 1, $r('app.media.map_tab1_sel'), $r('app.media.map_tab1_nor'))
        this.tabContentBuilder('同事圈', 2, $r('app.media.map_tab2_sel'), $r('app.media.map_tab2_nor'))
        this.tabContentBuilder('通讯录', 3, $r('app.media.map_tab3_sel'), $r('app.media.map_tab3_nor'))
        this.tabContentBuilder('我的', 4, $r('app.media.map_tab4_sel'), $r('app.media.map_tab4_nor'))

      }
      .width('100%')
      .backgroundColor('#F3F4F5')
      .barHeight(52)
      .barMode(BarMode.Fixed)
      //tab切换动画时间,例如tab从0-5 直接展示5 不显示中间的滑动过程
      .animationDuration(0)
      // .scrollable(false)  //如果不想让内容滑动,可关闭滑动效果
      .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
        //content 触发切换滑动开始的回调
        Logger.info("======onAnimationStart",'index:'+index+'targetIndex:'+targetIndex)
        this.currentIndex = targetIndex
        this.targetIndex=targetIndex
        this.currentOpacity =1
        this.targetOpacity = 0
      })
      .onGestureSwipe((index: number, event: TabsAnimationEvent) =>{
        //左划小于0 右滑大于0
        let currentOffset = event.currentOffset
        if (currentOffset>0&&index==0) {
          return
        }else if(currentOffset>0){
          this.targetIndex=index-1
        }else if (currentOffset<0&& index<5){
          this.targetIndex=index+1
        }else {
          return
        }

        // 获取屏幕的宽vp 根据手指左右滑动的距离除以屏幕的宽 计算tab图片的透明度
        let percent = Math.abs(currentOffset)/(getScreenWidth()*3/4)
        if (percent>1) {
          percent=1
        }
        if (percent<0) {
          percent=0
        }
        this.currentOpacity = 1-percent
        this.targetOpacity =percent;
        Logger.info("======onGestureSwipe",'index:'+index+'currentOffset:'+event.currentOffset+'percent:'+percent)
      })

    }.hideTitleBar(true).hideToolBar(true)
    .width('100%')
    .height('100%')
  }
}

###注意: 官方文档中onAnimationStart 这个回调函数下面写了,当animationDuration为0时动画关闭,不触发该回调。

这个解释是不严谨的,当animationDuration=0时,只是点击tab切换页签不回调这个函数,滑动切换还是会回调这个函数的。

相关推荐
二流小码农27 分钟前
鸿蒙开发:应用内如何做更新
android·ios·harmonyos
李游Leo1 小时前
鸿蒙 HarmonyOS - SideBarContainer 组件自学指南
华为·harmonyos
陈奕昆4 小时前
2.2HarmonyOS NEXT高性能开发技术:编译优化、内存管理与并发编程实践
华为·harmonyos
陈奕昆5 小时前
2.1HarmonyOS NEXT开发工具链进阶:DevEco Studio深度实践
华为·wpf·harmonyos
全栈若城10 小时前
16.[HarmonyOS NEXT Column案例一(上)] 使用Column组件构建垂直表单布局的基础指南
harmonyos
simple丶10 小时前
HarmonyOS 鸿蒙应用 - NEWS项目详细介绍
harmonyos·arkts·arkui
全栈若城10 小时前
17.[HarmonyOS NEXT Column案例一(下)] 表单组件的详细实现与样式定制
harmonyos
全栈若城10 小时前
22.[HarmonyOS NEXT Column案例四(上)] 水平对齐与响应式设计基础指南
harmonyos
彭不懂赶紧问10 小时前
鸿蒙NEXT开发浅进阶到精通10:我的开发项目中遇到的问题及解决笔记01
harmonyos
lqj_本人12 小时前
鸿蒙OS&UniApp自定义手势识别与操作控制实践#三方框架 #Uniapp
华为·uni-app·harmonyos