圆形扩散菜单这几年在APP中比较少见了记得15年左右APP都有各种各样炫酷的动画效果看到设计搞出来的动画效果就头大因为我不会在当时。这份内容讲一下实现原理已经完整代码。最终效果点击主按钮子菜单沿圆形轨迹向外扩散展开再次点击菜单平滑收回、缩放、渐隐包含位移、透明度、缩放组合动画支持自定义菜单数量、半径、起始角度、间隔角度核心原理布局使用Stack堆叠容器实现菜单居中叠加坐标计算以主按钮为圆心子菜单中心距离主按钮中心为半径通过三角函数将角度转为坐标 这样很容易得到子菜单的中心点。动画translate opacity scale 弹簧曲线组合动效。通信父组件控制开关子组件负责渲染动画Prop父子通信完整代码import{curves}fromkit.ArkUI;// 坐标类型x yinterfaceMenuPoint{x:number;y:number;}Componentexportstruct SpreadMenu{// 接收父组件传菜单是否打开 菜单列表Prop isOpen:boolean;Prop menuList:string[];// 配置privateradius:number90;privatestartAngle:number180;privateangleStep:number45;build(){Stack(){// 自动生成菜单ForEach(this.getMenuPositions(),(item:MenuPoint,index:number){this.buildItem(item.x,item.y,this.menuList[index]);})}.width(100%).height(100%);}// 获取所有坐标privategetMenuPositions():MenuPoint[]{constpositions:MenuPoint[][];for(leti:number0;ithis.menuList.length;i){// 开始角度 偏移角度constangle:numberthis.startAnglei*this.angleStep;// 存储每一个子菜单的中心点positions.push({x:this.getX(angle),y:this.getY(angle)});}returnpositions;}// 角度 XprivategetX(angle:number):number{constradian:number(angle-90)*Math.PI/180;returnthis.radius*Math.cos(radian);}// 角度 YprivategetY(angle:number):number{constradian:number(angle-90)*Math.PI/180;returnthis.radius*Math.sin(radian);}// 子菜单BuilderbuildItem(x:number,y:number,label:string){Column(){Text(label).fontColor(Color.White).fontSize(12)}.width(50).height(50).backgroundColor(#007AFF).borderRadius(25).justifyContent(FlexAlign.Center).translate({x:this.isOpen?x:0,y:this.isOpen?y:0}).opacity(this.isOpen?1:0).scale({x:this.isOpen?1:0.5,y:this.isOpen?1:0.5}).animation({duration:350,curve:curves.springMotion()});}}Entry Component struct SpreadMenuPage{State isOpen:booleanfalse;State menuList:string[][用户,搜索,添加,删除,分享];build(){Stack({alignContent:Alignment.Center}){// 菜单组件父组件控制状态SpreadMenu({isOpen:this.isOpen,menuList:this.menuList})// 主按钮外置Button({stateEffect:true,buttonStyle:ButtonStyleMode.NORMAL}){Text(菜单).fontColor(Color.White).textAlign(TextAlign.Center)}.width(60).height(60).backgroundColor(#007AFF).borderRadius(30).onClick((){this.isOpen!this.isOpen;}).zIndex(999)// 周期1阻尼0.25 稍微来点弹簧效果.animation({curve:curves.springMotion(1,0.25),duration:1000})}.width(100%).height(100%).backgroundColor(#f5f5f5);}}菜单动画参数说明translate沿圆形轨迹移动opacity渐显渐隐scale缩放动画springMotion弹簧曲线发挥奇思妙想拓展能力是不是可以增加用手拨动旋转菜单呢。制作炫酷的动画需要一丢丢数学和对动画路径的熟悉。