iOS开发之转盘菜单—Swift
程序员文章站
2022-03-20 22:44:42
前言使用Swift实现的转盘菜单,主要用到UIBezierPath、CALayer遮罩绘制扇形UIView,CATransform3DMakeRotation实现旋转动画。代码设计使用默认configureCallback回调方便创建和设置基本属性,参考UITableView代理和数据源模式,支持AutoLayout和Frame。效果图1.遮罩绘制扇形View计算扇形曲线位置,通过CALayer的mask属性绘制出扇形UIView核心代码func setMaskLayer(_ startAng...
前言
使用Swift实现的转盘菜单,主要用到UIBezierPath
、CALayer
遮罩绘制扇形UIView
,CATransform3DMakeRotation
实现旋转动画。代码设计使用默认configureCallback
回调方便创建和设置基本属性,参考UITableView
代理和数据源模式,支持AutoLayout
和Frame
。
效果图
1.遮罩绘制扇形View
计算扇形曲线位置,通过CALayer
的mask
属性绘制出扇形UIView
核心代码
func setMaskLayer(_ startAngle: CGFloat, endAngle: CGFloat) {
let center = CGPoint(x: bounds.width * 0.5, y: bounds.height * 0.5)
let layer = CAShapeLayer()
path.addArc(withCenter: center, radius: bounds.width * 0.5, startAngle: startAngle, endAngle: endAngle, clockwise: true)
path.addLine(to: center)
layer.path = path.cgPath
layer.rasterizationScale = UIScreen.main.scale
layer.shouldRasterize = true
self.layer.mask = layer
}
2.中间镂空
func createHole(in view : UIView, radius: CGFloat) {
let path = CGMutablePath()
path.addArc(center: view.center, radius: radius, startAngle: 0.0, endAngle: 2.0 * .pi, clockwise: true)
path.addRect(CGRect(origin: .zero, size: view.bounds.size))
let maskLayer = CAShapeLayer()
maskLayer.path = path
maskLayer.fillRule = .evenOdd
view.layer.mask = maskLayer
view.clipsToBounds = true
}
3.旋转动画
添加UIPanGestureRecognizer
、UITapGestureRecognizer
手势,根据手势位置使用atan2
函数计算旋转角度,然后用CATransform3DMakeRotation
围绕Z
轴旋转做动画
核心代码
func handlePanGesture(_ sender: UIPanGestureRecognizer) {
let location = sender.location(in: self)
switch sender.state {
case .began:
startPoint = location
case .changed:
let radian1 = -atan2(startPoint.x - menuLayerView.center.x, startPoint.y - menuLayerView.center.y)
let radian2 = -atan2(location.x - menuLayerView.center.x, location.y - menuLayerView.center.y)
menuLayerView.transform = menuLayerView.transform.rotated(by: radian2 - radian1)
startPoint = location
default:
let angle = 2 * CGFloat(Double.pi) / CGFloat(cells.count)
var menuViewAngle = atan2(menuLayerView.transform.b, menuLayerView.transform.a)
if menuViewAngle < 0 {
menuViewAngle += CGFloat(2 * Double.pi)
}
var index = cells.count - Int((menuViewAngle + CGFloat(Double.pi / 4)) / angle)
if index == cells.count {
index = 0
}
setSelectedIndex(index, animated: true)
}
}
func handleTapGesture(_ sender: UITapGestureRecognizer) {
let location = sender.location(in: menuLayerView)
for (index, cell) in cells.enumerated() {
if cell.path.contains(location) {
setSelectedIndex(index, animated: true)
}
}
}
4.弹出收起动画
func openMenuView(withAnimate animate: Bool = true) {
openMenu = true
UIView.animate(withDuration: animate ? configure.animationDuration : 0, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 5.0, options: .curveEaseInOut) {
self.centerButton.transform = CGAffineTransform(rotationAngle: .pi * -0.5)
self.centerButton.setImage(self.configure.closeImage, for: .normal)
self.menuLayerView.transform = CGAffineTransform(scaleX: 1, y: 1).rotated(by: self.currentAngle)
}
}
func closeMenuView(withAnimate animate: Bool = true) {
openMenu = false
let scale = (configure.centerRadius * 2) / bounds.width
UIView.animate(withDuration: animate ? configure.animationDuration : 0, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 5.0, options: .curveEaseInOut) {
self.centerButton.transform = .identity
self.centerButton.setImage(self.configure.openImage, for: .normal)
self.menuLayerView.transform = CGAffineTransform(scaleX: scale, y: scale).rotated(by: self.currentAngle)
}
}
5.内部细节
考虑到方便布局和使用,内部使用UIView
叠加旋转实现,这里也可以采用Layer
直接绘制实现,相对UIView
,层次结构会简单很多
总结
核心代码已经贴出,完整代码请查看----->>>CLDemo,如果对你有所帮助,欢迎Star。
本文地址:https://blog.csdn.net/weixin_34614165/article/details/110525315
上一篇: Lua教程(十六):系统库(os库)
下一篇: ps怎么设计带有创意边框的印章?
推荐阅读
-
IOS开发(41)之关于NSString和NSMutableString的retainCount
-
IOS开发(43)之10个迷惑新手的Cocoa&Objective-c开发问题
-
IOS开发(40)之objective-C 的内存管理之-引用计数
-
IOS开发(42)之IOS设计UI工具大全
-
IOS开发(39)之KVC KVO KVB
-
IOS开发(47)之iOS Block学习
-
IOS开发(59)之Block Object的调用
-
IOS开发(54)之Storyboard之传值
-
IOS开发(48)之由init、loadView、viewDidLoad、viewDidUnload、dealloc的关系说起
-
IOS开发(56)之并发简介