前言
使用Swift实现的转盘菜单,主要用到UIBezierPath、CALayer遮罩绘制扇形UIView,CATrasform3DMakeRotatio实现旋转动画。代码设计使用默认cofigureCallback回调方便创建和设置基本属性,参考UITableView代理和数据源模式,支持AutoLayout和Frame。
效果图1.遮罩绘制扇形View计算扇形曲线位置,通过CALayer的mask属性绘制出扇形UIView核心代码
fucsetMaskLayer(_startAgle:CGFloat,edAgle:CGFloat){ letceter=CGPoit(x:bouds.width*0.5,y:bouds.height*0.5) letlayer=CAShapeLayer() path.addArc(withCeter:ceter,radius:bouds.width*0.5,startAgle:startAgle,edAgle:edAgle,clockwise:true) path.addLie(to:ceter) layer.path=path.cgPath layer.rasterizatioScale=UIScree.mai.scale layer.shouldRasterize=true self.layer.mask=layer}2.中间镂空fuccreateHole(iview:UIView,radius:CGFloat) { letpath=CGMutablePath() path.addArc(ceter:view.ceter,radius:radius,startAgle:0.0,edAgle:2.0*.pi,clockwise:true) path.addRect(CGRect(origi:.zero,size:view.bouds.size)) letmaskLayer=CAShapeLayer() maskLayer.path=path maskLayer.fillRule=.eveOdd view.layer.mask=maskLayer view.clipsToBouds=true}3.旋转动画添加UIPaGestureRecogizer、UITapGestureRecogizer手势,根据手势位置使用ata2函数计算旋转角度,然后用CATrasform3DMakeRotatio围绕Z轴旋转做动画核心代码
fuchadlePaGesture(_seder:UIPaGestureRecogizer){ letlocatio=seder.locatio(i:self) switchseder.state{ case.bega: startPoit=locatio case.chaged: letradia1=-ata2(startPoit.x-meuLayerView.ceter.x,startPoit.y-meuLayerView.ceter.y) letradia2=-ata2(locatio.x-meuLayerView.ceter.x,locatio.y-meuLayerView.ceter.y) meuLayerView.trasform=meuLayerView.trasform.rotated(by:radia2-radia1) startPoit=locatio default: letagle=2*CGFloat(Double.pi)/CGFloat(cells.cout) varmeuViewAgle=ata2(meuLayerView.trasform.b,meuLayerView.trasform.a) ifmeuViewAgle<0{ meuViewAgle+=CGFloat(2*Double.pi) } varidex=cells.cout-It((meuViewAgle+CGFloat(Double.pi/4))/agle) ifidex==cells.cout{ idex=0 } setSelectedIdex(idex,aimated:true) }}fuchadleTapGesture(_seder:UITapGestureRecogizer){ letlocatio=seder.locatio(i:meuLayerView) for(idex,cell)icells.eumerated(){ ifcell.path.cotais(locatio){ setSelectedIdex(idex,aimated:true) } }}4.弹出收起动画fucopeMeuView(withAimateaimate:Bool=true){ opeMeu=true UIView.aimate(withDuratio:aimate?cofigure.aimatioDuratio:0,delay:0,usigSprigWithDampig:0.7,iitialSprigVelocity:5.0,optios:.curveEaseIOut){ self.ceterButto.trasform=CGAffieTrasform(rotatioAgle:.pi*-0.5) self.ceterButto.setImage(self.cofigure.closeImage,for:.ormal) self.meuLayerView.trasform=CGAffieTrasform(scaleX:1,y:1).rotated(by:self.curretAgle) }}fuccloseMeuView(withAimateaimate:Bool=true){ opeMeu=false letscale=(cofigure.ceterRadius*2)/bouds.width UIView.aimate(withDuratio:aimate?cofigure.aimatioDuratio:0,delay:0,usigSprigWithDampig:0.7,iitialSprigVelocity:5.0,optios:.curveEaseIOut){ self.ceterButto.trasform=.idetity self.ceterButto.setImage(self.cofigure.opeImage,for:.ormal) self.meuLayerView.trasform=CGAffieTrasform(scaleX:scale,y:scale).rotated(by:self.curretAgle) }}5.内部细节考虑到方便布局和使用,内部使用UIView叠加旋转实现,这里也可以采用Layer直接绘制实现,相对UIView,层次结构会简单很多
总结核心代码已经贴出,完整代码请查看----->>>CLDemo,如果对你有所帮助,欢迎Star。
评论