鸿蒙开发:自定义一个圆形动画菜单

前言

在最近上架的应用趣谜语中,有一个功能,点击悬浮菜单后,弹出子菜单,效果如下:

很简单的一个功能,也就是常见的卫星菜单功能,那么在鸿蒙开发中如何来实现呢?想必大家猜到了,也就是利用最简单的属性动画来实现。

最终实现效果

全圆效果

显示在左半边

显示在上半边

当然了,效果展示可以支持8个方位,太多了,这里就不粘贴了,后续大家可以直接看相关Demo即可。

如何实现

原理很简单,默认情况下,所有的卫星菜单都是缩小为0,点击主菜单的时候,让卫星菜单在平移的时候,放大为1即可,唯独需要考虑的就是,卫星菜单的移动位置,需要按照圆的形式进行平移。

算法如下,起始角度和结束角度,可以控制卫星菜单的展示位置,radius半径可以确定卫星菜单和主菜单的距离,平移位置,由于是按圆的形式进行移动,所以,这里需要确认平移角度,利用Math.PI来实现。

TypeScript 复制代码
/**
 * 在圆的指定角度范围内均匀排列小球(修复全圆问题)
 * @param {number} centerX - 圆心X
 * @param {number} centerY - 圆心Y
 * @param {number} radius - 半径
 * @param {number} n - 小球数量
 * @param {number} startAngle - 起始角度(弧度)
 * @param {number} endAngle - 结束角度(弧度)
 * @param {boolean} isFullCircle - 是否是完整圆(特殊处理)
 * @returns {Array} 小球坐标数组
 */
function calculateArcPoints(centerX: number, centerY: number, radius: number, n: number, startAngle: number,
  endAngle: number, isFullCircle = false) {
  const points: ArcPoints[] = [];

  if (n <= 0) {
    return points;
  }

  // 确保角度范围正确
  let angleRange = endAngle - startAngle;
  if (angleRange < 0) {
    angleRange += 2 * Math.PI;
  }

  // 特殊处理:完整圆时,我们希望最后一个点不和第一个点重合
  // 因此角度间隔为 angleRange / n
  // 非完整圆时,角度间隔为 angleRange / (n - 1)
  const angleStep = isFullCircle
    ? angleRange / n
    : (n > 1 ? angleRange / (n - 1) : 0);

  for (let i = 0; i < n; i++) {
    const angle = startAngle + (angleStep * i);
    const x = centerX + radius * Math.cos(angle);
    const y = centerY + radius * Math.sin(angle);

    points.push(new ArcPoints(x, y));
  }

  return points;
}

class ArcPoints {
  x?: number
  y?: number

  constructor(x?: number, y?: number) {
    this.x = x
    this.y = y
  }
}

快速实现

目前我已经封装好了组件,也上传至了中心仓库中,大家如果想快速的实现,可以直接使用。

中心仓库地址:

ohpm.openharmony.cn/#/cn/detail...

依赖

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

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

TypeScript 复制代码
ohpm install @abner/circle_navigation

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

TypeScript 复制代码
"dependencies": { "@abner/circle_navigation": "^1.0.1"}

代码使用

需要实现三个属性,parentLayout属性是,父布局,也就是触发的视图,childLayout是子布局,是圆形导航菜单,clickStatus是展示状态,当然了,也有默认的一套UI,如果符合,也可以直接使用默认的。

TypeScript 复制代码
CircleNavigation({
  clickStatus: this.clickStatus,
  parentLayout: () => {
    this.parentLayout()
  },
  childLayout: (position: number) => {
    this.childLayout(position)
  }
})

完整案例

TypeScript 复制代码
@Entry
  @ComponentV2
  struct FullPage {
    @Local clickStatus: boolean = false

    @Builder
    parentLayout() {
      Column() {

      }
      .width(100)
        .height(100)
        .borderRadius(100)
        .backgroundColor(Color.Blue)
        .onClick(() => {
          //点击
          this.clickStatus = !this.clickStatus
        })
    }

    @Builder
    childLayout(position: number) {
      Column() {
        Text((position + 1).toString())
          .fontColor(Color.White)
          .fontWeight(FontWeight.Bold)
      }
      .justifyContent(FlexAlign.Center)
        .width(50)
        .height(50)
        .borderRadius(50)
        .backgroundColor(Color.Blue)
    }

    build() {
      RelativeContainer() {
        ActionBar({ title: "全圆" })
          .alignRules({
            middle: { anchor: '__container__', align: HorizontalAlign.Center }
          })
        CircleNavigation({
          clickStatus: this.clickStatus,
          parentLayout: () => {
            this.parentLayout()
          },
          childLayout: (position: number) => {
            this.childLayout(position)
          }
        })
          .alignRules({
            center: { anchor: '__container__', align: VerticalAlign.Center },
            middle: { anchor: '__container__', align: HorizontalAlign.Center }
          })
      }
      .height('100%')
        .width('100%')
    }
  }

相关属性

CircleType

圆形导航菜单位置

相关总结

一个特别简单的卫星菜单,本身并不难,唯独需要掌握就是,卫星菜单移动的圆形位置,其他都是简单的属性动画,希望可以帮助到您。

相关推荐
robotx1 小时前
安卓线程相关
android
RickeyBoy1 小时前
独立 App 配置阿里云 CDN 记录
ios
消失的旧时光-19432 小时前
Android 面试高频:JSON 文件、大数据存储与断电安全(从原理到工程实践)
android·面试·json
dalancon2 小时前
VSYNC 信号流程分析 (Android 14)
android
dalancon3 小时前
VSYNC 信号完整流程2
android
dalancon3 小时前
SurfaceFlinger 上帧后 releaseBuffer 完整流程分析
android
不爱吃糖的程序媛3 小时前
OpenHarmony 工程结构剖析
harmonyos
白玉cfc4 小时前
接口与API设计
ios·objective-c
用户69371750013844 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
程序员Android4 小时前
Android 刷新一帧流程trace拆解
android