HarmonyOS鸿蒙Next中如何实现一个底部的曲线形式导航

HarmonyOS鸿蒙Next中如何实现一个底部的曲线形式导航 目前在项目中,UI设计了一个曲线的导航,在鸿蒙开发中,如何来实现呢?

cke_982.png


更多关于HarmonyOS鸿蒙Next中如何实现一个底部的曲线形式导航的实战教程也可以访问 https://www.itying.com/category-93-b0.html

5 回复

似乎现在的应用,底部导航都是千篇一律,基本上都是几个按钮,点击之后,切换切换图标,更改更改颜色,稍微好点的会增加动画效果,今天,给大家推荐一款,底部的曲线导航,它可以让底部导航的实现方式别具一格。

我们先看下静态效果:

动态效果如下:

目前第一个版本,完成了基本的曲线形式效果,还未追加曲线的移动动画,在下一个版本会加上,那么针对这样的一个曲线形式导航,它是如何来实现的呢?答案很简单,就是使用简单的Path路径绘制。

Path路径,有两种方式实现,一种是系统提供的Path组件,另一种就是使用new drawing.Path(),然后使用canvas来绘制,两种方式都可以实现,看大家的技术选型,这里我使用的是Path组件,因为只需要设置符合SVG路径描述规范的命令字符串即可实现。

SVG路径介绍

SVG路径是SVG(可缩放矢量图形)中用于创建复杂形状的核心元素,通过数学描述定义图形轮廓,支持直线、曲线、弧线等多种图形绘制。

例如,绘制一个三角形,直接在属性commands传递SVG路径即可,代码如下:

Path()
        .width('210px')
        .height('310px')
        .commands('M100 0 L200 240 L0 240 Z')
        .fillOpacity(0)
        .stroke(Color.Black)
        .strokeWidth(3)

相对来说还是比较的简单,下面就针对SVG中的绘制命令,简单的罗列一下:

曲线绘制

由于需要点击时,让本按钮进行曲线展示,有两个方面需要考虑,一是曲线的位置,点击不同位置的按钮,曲线就会移动到指定位置,二是曲线连接之处,保持平滑过渡,使用三次贝塞尔曲线段完成。

完整的绘制曲线代码如下,大家可以作为参考,averageWidth为每个tab按钮的宽度,navigationSize为导航数量。

 // 绘制曲线的函数
  async drawCurve(position: number) {
    // 初始点:0,100
    let tagPosition = 0
    let d = 'M 0 ' + tagPosition;

    // 计算曲线的起始和结束位置
    const curveStart = (position - 1) * this.averageWidth;
    const curveEnd = position * this.averageWidth;

    // 0到曲线起始位置的直线部分
    if (curveStart > 0) {
      d += ' L ' + curveStart + ' ' + tagPosition;
    }

    // 曲线部分:使用两个三次贝塞尔曲线段确保平滑连接
    const midPoint = (curveStart + curveEnd) / 2;
    const controlPoint1X = curveStart + (this.averageWidth / this.navigationSize);
    const controlPoint2X = curveEnd - (this.averageWidth / this.navigationSize);

    d += ' C ' + controlPoint1X + ' ' + tagPosition + ' ' + controlPoint1X + ' ' + this._privateCurveBottom + ' ' +
      midPoint +
      ' ' +
    this._privateCurveBottom;
    d += ' C ' + controlPoint2X + ' ' + this._privateCurveBottom + ' ' + controlPoint2X + ' ' + tagPosition + ' ' +
      curveEnd +
      ' ' + tagPosition;

    // 曲线结束位置到最大宽度的直线部分
    if (curveEnd < this._privateMaxWidth) {
      d += ' L ' + this._privateMaxWidth + ' ' + tagPosition;
    }

    // 新增闭合路径逻辑
    d += ` V ${this._privateCurveBottom}`; // 垂直延伸到底部
    d += ' H 0'; // 水平返回起点
    d += ' Z';

    this._privatePathCommands = d

  }

快速使用

如果你不想自己实现,而是想快速的使用,这个已经为大家考虑到了,目前已经上传到到了中心仓库,有需要的同学,可以前去体验。

中心仓库地址:

[https://ohpm.openharmony.cn/#/cn/detail/@abner%2Fcurve_navigation](https://ohpm.openharmony.cn/#/cn/detail/@abner%2Fcurve_navigation)

依赖方式

1、远程依赖

方式一:在Terminal窗口中,执行如下命令安装三方包,DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。

建议:在使用的模块路径下进行执行命令。

ohpm install [@abner](/user/abner)/curve_navigation

方式二:在模块的oh-package.json5中设置三方包依赖,配置示例如下:

"dependencies": { "[@abner](/user/abner)/curve_navigation": "^1.0.1"}

代码使用

CurveNavigation({
  navigationSize: 5, //tab数量
  navigationPaddingBottom: WindowUtils.windowBottomNavHeight,//距离底部距离
  onPageChange: (position: number) => {
    //page改变
    this.selectIndex = position
  },
  tabView: (position: number) => {
    //导航视图
    this.tabView(position)
  },
  pageView: (position: number) => {
    //页面视图
    this.pageView(position)
  }
})

完整案例

@Entry
@Component
struct Index {
  private tempColorArray: ResourceColor[] = ["#ffcc80", "#ff9323ac", "#ff26a965", "#ff93d923", "#ff11c5de",]
  @State selectIndex: number = 0
  private tabArray: Resource[] =
    [$r('sys.symbol.house_fill'), $r('sys.symbol.square_fill_grid_2x2'), $r('sys.symbol.bell_fill'),
      $r('sys.symbol.externaldrive_fill'), $r('sys.symbol.person_2_fill')]

  @Builder
  tabView(position: number) {
    if (this.selectIndex == position) {
      Column() {
        SymbolGlyph(this.tabArray[position])
          .fontSize(20)
          .renderingStrategy(SymbolRenderingStrategy.SINGLE)
          .fontColor([Color.Black])
      }
      .backgroundColor(Color.White)
      .width(35)
      .height(35)
      .borderRadius(35)
      .justifyContent(FlexAlign.Center)
    } else {
      SymbolGlyph(this.tabArray[position])
        .fontSize(20)
        .renderingStrategy(SymbolRenderingStrategy.SINGLE)
        .fontColor([Color.Gray])
    }

  }

  @Builder
  pageView(position: number) {
    Column() {
      Text(position.toString())
    }.width("100%")
    .height("100%")
    .justifyContent(FlexAlign.Center)
    .backgroundColor(this.tempColorArray[position])
  }

  build() {
    RelativeContainer() {
      CurveNavigation({
        navigationSize: 5, //tab数量
        navigationPaddingBottom: WindowUtils.windowBottomNavHeight,
        onPageChange: (position: number) => {
          this.selectIndex = position
        },
        tabView: (position: number) => {
          this.tabView(position)
        },
        pageView: (position: number) => {
          this.pageView(position)
        }
      })
    }
    .height('100%')
    .width('100%')
  }
}

属性介绍

相关总结

目前唯一的遗憾是,没有实现曲线在切换时的动画偏移,而是直接的切换,后续会针对这块再单独的处理,大家可以先进行使用。

更多关于HarmonyOS鸿蒙Next中如何实现一个底部的曲线形式导航的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


解:让UI重新设计一个。

cke_498.png

这才是解决问题的根本,哈哈~,

在HarmonyOS Next中,实现底部曲线形式导航,主要使用Navigation组件与自定义TabBar。首先,创建Navigation并设置TabBar为自定义组件。在自定义TabBar中,使用Canvas绘制曲线路径,结合PathLinearGradient实现曲线与渐变效果。通过@State管理选中状态,动态调整曲线位置与颜色。最后,将TabBar与页面内容绑定,完成导航切换功能。

在HarmonyOS Next中实现底部曲线导航,核心是使用Canvas绘制贝塞尔曲线路径并配合Shape组件。以下是关键实现步骤:

  1. 使用<Shape>组件作为容器,设置其高度和宽度,并采用绝对定位固定在底部。

  2. Shape内使用<Path>命令绘制曲线路径。通常使用三次贝塞尔曲线(C命令)来创建平滑的弧形过渡。例如,路径数据可能类似:

    M 0,0 L 100,0 C 120,0 140,20 150,50 ... (后续对称曲线)
    

    这表示从起点开始,先画直线到(100,0),再通过控制点绘制曲线到(150,50)。

  3. 为路径填充颜色,并设置合适的z-index确保导航栏位于内容上层。

  4. 在曲线区域上方使用FlexGrid布局导航图标,通过定位使图标精确放置在曲线凸起部分。

  5. 结合状态管理(如@State)控制当前选中项,并切换图标颜色或样式。

主要优势在于完全使用ArkUI声明式语法,无需依赖第三方库,性能较好且与系统风格统一。注意在绘制路径时需根据设计稿精确计算控制点坐标,以实现对称的曲线效果。

回到顶部