问题
I am attempting to plot circular buttons in a ring like this.
I have 6 UI buttons which all have a corner-radius of 360 degrees, what I am attempting to do in Swift is plot them equally around a central button/point just like the image above. Each circle is equally spaced from its neighbour. What is the best way of achieving this functionality? Should I create a bezier curve and then use math to plot the buttons around said curve or is there another way which you would suggest?
A side note is that I am not looking for a radial menu of any kind there is no animation required. I am just trying to plot my existing UI Buttons in the format above.
Thanks!
回答1:
I would suggest using math (trigonometry) to compute the horizontal and vertical offsets from the center button and then use layout anchors to position the buttons.
Here is a self contained example:
class ViewController: UIViewController {
func createButton(size: CGFloat) -> UIButton {
let button = UIButton(type: .custom)
button.backgroundColor = .red
button.translatesAutoresizingMaskIntoConstraints = false
button.widthAnchor.constraint(equalToConstant: size).isActive = true
button.heightAnchor.constraint(equalToConstant: size).isActive = true
button.layer.cornerRadius = size / 2
return button
}
func setUpButtons(count: Int, around center: UIView, radius: CGFloat) {
// compute angular separation of each button
let degrees = 360 / CGFloat(count)
for i in 0 ..< count {
let button = createButton(size: 50)
self.view.addSubview(button)
// use trig to compute offsets from center button
let hOffset = radius * cos(CGFloat(i) * degrees * .pi / 180)
let vOffset = radius * sin(CGFloat(i) * degrees * .pi / 180)
// set new button's center relative to the center button's
// center using centerX and centerY anchors and offsets
button.centerXAnchor.constraint(equalTo: center.centerXAnchor, constant: hOffset).isActive = true
button.centerYAnchor.constraint(equalTo: center.centerYAnchor, constant: vOffset).isActive = true
}
}
override func viewDidLoad() {
super.viewDidLoad()
let centerButton = createButton(size: 50)
self.view.addSubview(centerButton)
// use anchors to place center button in the center of the screen
centerButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
centerButton.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
setUpButtons(count: 6, around: centerButton, radius: 100)
}
}
Notes:
If you don't need the center button, just set up the buttons around
self.view
:setupButtons(count: 6, around: self.view, radius: 100)
or around an arbitrary point:
let point = CGPoint(x: 180, y: 300) let centerView = UIView(frame: CGRect(origin: point, size: CGSize.zero)) self.view.addSubview(centerView) setUpButtons(count: 6, around: centerView, radius: 140)
- Using a
UIView
as the center instead of a point is more flexible because you can dynamically move thatUIView
and the buttons will follow.
Here it is running in the simulator:
回答2:
You don't need a bezierpath for that, just a bit of calculation.
I am not a math genius or something so I took an already answered question and changed it to my needs.
func place(buttons: [UIView], around center: CGPoint, radius: CGFloat) {
var currentAngle: CGFloat = 0
let buttonAngle: CGFloat = (CGFloat(360 / buttons.count)) * .pi / 180
for button in buttons {
let buttonCenter = CGPoint(x: center.x + cos(currentAngle) * radius, y: center.y + sin(currentAngle) * radius)
// (1)
//button.transform = CGAffineTransform(rotationAngle: currentAngle)
// (2)
//view.addSubview(button)
button.center = buttonCenter
currentAngle += buttonAngle
}
}
Use an array of UIView so you are flexible. If you want to add the buttons from code, just uncomment (1). If you want the buttons to rotate according to their rotation around the center, uncomment (2).
Btw it is not necessary to add 360 degree cornerradius to the buttons for a round shape. Please have a read on the documentation here.
Happy coding!
来源:https://stackoverflow.com/questions/54234082/how-to-plot-circular-buttons-around-a-central-point-in-a-ring