HarmonyOS鸿蒙Next中如何实现卫星菜单,点击主菜单后让子菜单动画移动
HarmonyOS鸿蒙Next中如何实现卫星菜单,点击主菜单后让子菜单动画移动 目前有一个需求,点击主菜单后,让几个子菜单由小变大,并且实现平移动画,在鸿蒙开发中,如何实现这样的一个功能呢?
类似下面的功能效果:

更多关于HarmonyOS鸿蒙Next中如何实现卫星菜单,点击主菜单后让子菜单动画移动的实战教程也可以访问 https://www.itying.com/category-93-b0.html
在最近上架的应用趣谜语中,有一个功能,点击悬浮菜单后,弹出子菜单,效果如下:

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

显示在左半边

显示在上半边

当然了,效果展示可以支持8个方位,太多了,这里就不粘贴了,后续大家可以直接看相关Demo即可。
如何实现
原理很简单,默认情况下,所有的卫星菜单都是缩小为0,点击主菜单的时候,让卫星菜单在平移的时候,放大为1即可,唯独需要考虑的就是,卫星菜单的移动位置,需要按照圆的形式进行平移。
算法如下,起始角度和结束角度,可以控制卫星菜单的展示位置,radius半径可以确定卫星菜单和主菜单的距离,平移位置,由于是按圆的形式进行移动,所以,这里需要确认平移角度,利用Math.PI来实现。
/**
* 在圆的指定角度范围内均匀排列小球(修复全圆问题)
* @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
}
}
快速实现
目前我已经封装好了组件,也上传至了中心仓库中,大家如果想快速的实现,可以直接使用。
中心仓库地址:
[https://ohpm.openharmony.cn/#/cn/detail/@abner%2Fcircle_navigation](https://ohpm.openharmony.cn/#/cn/detail/@abner%2Fcircle_navigation)
依赖
方式一:在Terminal窗口中,执行如下命令安装三方包,DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。
建议:在使用的模块路径下进行执行命令。
ohpm install [@abner](/user/abner)/circle_navigation
方式二:在模块的oh-package.json5中设置三方包依赖,配置示例如下:
"dependencies": { "[@abner](/user/abner)/circle_navigation": "^1.0.1"}
代码使用
需要实现三个属性,parentLayout属性是,父布局,也就是触发的视图,childLayout是子布局,是圆形导航菜单,clickStatus是展示状态,当然了,也有默认的一套UI,如果符合,也可以直接使用默认的。
CircleNavigation({
clickStatus: this.clickStatus,
parentLayout: () => {
this.parentLayout()
},
childLayout: (position: number) => {
this.childLayout(position)
}
})
完整案例
@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
圆形导航菜单位置

相关总结
一个特别简单的卫星菜单,本身并不难,唯独需要掌握就是,卫星菜单移动的圆形位置,其他都是简单的属性动画,希望可以帮助到您。
更多关于HarmonyOS鸿蒙Next中如何实现卫星菜单,点击主菜单后让子菜单动画移动的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,实现点击主菜单后子菜单从小变大并平移动画,核心是使用ArkUI的@State、@Builder和动画API。以下是关键实现思路和代码示例:
1. 定义状态与数据
使用@State装饰器控制菜单的展开状态和每个子菜单的位置信息。
@State isExpanded: boolean = false
// 存储每个子菜单的最终偏移量(极坐标或直角坐标)
private childrenPositions: Array<{ x: number, y: number }> = []
2. 计算子菜单位置
在aboutToAppear或点击事件中,根据主菜单位置和展开半径,计算每个子菜单的目标位置(平移动画的终点)。可以使用三角函数计算圆形分布的位置。
3. 构建动画UI
使用@Builder装饰器构建子菜单组件,并应用组合动画。
// 子菜单构建器
@Builder
MenuItemBuilder(index: number) {
// 应用组合动画:缩放 + 平移
Column() {
// 你的子菜单内容,例如Image或Text
}
.scale({
x: this.isExpanded ? 1 : 0.3, // 从小变大
y: this.isExpanded ? 1 : 0.3
})
.translate({
x: this.isExpanded ? this.childrenPositions[index]?.x || 0 : 0,
y: this.isExpanded ? this.childrenPositions[index]?.y || 0 : 0
})
// 配置动画参数:指定动画曲线和时长
.animation({
duration: 300,
curve: Curve.EaseOut
})
// 其他样式...
}
4. 触发动画
通过点击主菜单,改变isExpanded的状态值,ArkUI框架会自动触发关联的动画。
Column() {
// 主菜单按钮
Button('主菜单')
.onClick(() => {
this.isExpanded = !this.isExpanded
})
// 条件渲染子菜单
if (this.isExpanded) {
ForEach(this.menuData, (item, index) => {
this.MenuItemBuilder(index)
})
}
}
关键点说明
- 动画组合:
.scale()和.translate()可以同时应用,形成组合动画效果。 - 状态驱动:动画的触发完全由
isExpanded这个状态变量驱动,无需手动操作动画对象。 - 性能:ArkUI的动画系统是高性能的,但应避免在动画过程中进行频繁的复杂布局计算。
通过以上方式,你可以高效地实现主菜单点击后,子菜单带缩放和平移的卫星式展开动画。


