preface
Use Swift implementation of the rotary table menu, the main use UIBezierPath, CALayer mask drawing fan UIView, CATransform3DMakeRotation rotation animation. The code design uses the default configureCallback callback to facilitate the creation and setting of basic properties, referring to the UITableView proxy and data source schema, supporting AutoLayout and Frame.
rendering
1. Mask to draw sector View
Calculate the position of sector curve and draw the core code of sector UIView through the mask attribute of CALayer
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 }Copy the code
2. Hollow out in the middle
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: Origin) .zero, size: view.bounds.size)) let maskLayer = CAShapeLayer() maskLayer.path = path maskLayer.fillRule = .evenOdd view.layer.mask = maskLayer view.clipsToBounds = true }Copy the code
3. Rotate animation
Add UIPanGestureRecognizer, UITapGestureRecognizer gestures, according to the sign position using the atan2 function to calculate rotation Angle, and then made animation CATransform3DMakeRotation revolve around the Z axis core code
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)
}
}
}
Copy the code
4. Pop up the folding animation
func openMenuView(withAnimate animate: Bool = true) { openMenu = true UIView.animate(withDuration: animate ? Configure. AnimationDuration: 0, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 5.0, the options: .curveEaseInOut) { self.centerButton.transform = CGAffineTransform(rotationAngle: . PI * 0.5) self. CenterButton. SetImage (self. The 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, the 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) } }Copy the code
5. Internal details
Considering the convenience of layout and use, the internal use of UIView overlay rotation, here can also be directly drawn Layer implementation, compared with UIView, the hierarchy will be much simpler
conclusion
The core code has been posted, the complete code please see —–>>>CLDemo, if you help, welcome Star.