Search code examples
iosswiftmenuuibuttonnslayoutconstraint

Is there any way to layout buttons in circular arrangement?


I'm trying to make a round button in the corner and when you press on it, 3 buttons pop up around it. Something like Pinterest's menu when you hold on a pin. I've looked up using UIBezierPath but it's not what I'm looking for. I know there are GitHub libraries but I'm trying to make it from scratch.

Here's an example of what I'm trying to make from scratch:

example

I figured out how to make round buttons by using the corner radius. And I have a specific function that it's going to animate the buttons but I can't figure out how to properly get them in a circle. I used constraints but that makes more of a square layout than a round one.


Solution

  • You said:

    but I can't figure out how to properly get them in a circle.

    It’s just a little trigonometry to figure out where the center of the new buttons should be in relationship to the existing button. If r is the distance from the center x, y of the existing circle, and circle i is at an angle of θᵢ, then xᵢ = x + r * cos(θᵢ) and yᵢ = y + r * sin(θᵢ). (In this arrangement angles are measured in radians from 3 o’clock, proceeding clockwise, or going negative to go counter clockwise.)

    For example, if using constraints:

    let r: CGFloat = 150               // let's say you want center of the circles to be 150 points away from center of existing button
    let range = -CGFloat.pi / 2 ... 0  // and we want the angles to range from -π/2 to 0
    let howMany = 5                    // and you want five of them
    
    for i in 0 ..< howMany {
        let angle = range.lowerBound + CGFloat(i) / CGFloat(howMany - 1) * (range.upperBound - range.lowerBound)
        let offset = CGPoint(x: r * cos(angle), y: r * sin(angle))
        let button = ...
        button.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(button)
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: mainButton.centerXAnchor, constant: offset.x),
            button.centerYAnchor.constraint(equalTo: mainButton.centerYAnchor, constant: offset.y),
            button.widthAnchor.constraint(equalToConstant: 40),
            button.heightAnchor.constraint(equalToConstant: 40)
        ])
    }
    

    enter image description here