Add multiple curve label's along with circular wheel that can rotate

73 Views Asked by At

enter image description here

I'm working on an ios project & I want to add a circular text label along with circular wheel using Swift language.The wheel can also rotate, and the labels with curved text will rotate to 360 degrees. I'm looking for any third party or any supporting file so that I can simulate the same behaviour.. Thanks in advance

I want to integrate the above functionality with swift language

For more reference please check the attached image:

2

There are 2 best solutions below

1
Navneet Kaur On
class CircularWheelView: UIView {
    
    private let imageLayer = CALayer()
    
    var image: UIImage? {
        didSet {
            setNeedsLayout()
        }
    }
    
    var labelTexts: [String] = [""] {
           didSet {
               drawTextLabels()
           }
       }
    override func layoutSubviews() {
        super.layoutSubviews()
        
        // Update the image layer when the image changes or the view's bounds change
        if let image = image {
            let imageSize = CGSize(width: bounds.width / 2, height: bounds.height / 2)
            imageLayer.frame = CGRect(x: (bounds.width - imageSize.width) / 2, y: (bounds.height - imageSize.height) / 2, width: imageSize.width, height: imageSize.height)
            imageLayer.contents = image.cgImage
        }
    }
    
    override func draw(_ rect: CGRect) {
        // Draw the circular ring
        let ringPath = UIBezierPath(ovalIn: bounds.insetBy(dx: 20, dy: 20))
        UIColor.lightGray.setStroke()
        ringPath.lineWidth = 40
        ringPath.stroke()
        
        // Draw the text labels along the circumference
        drawTextLabels()
    }
    
    private func drawTextLabels() {
        let center = CGPoint(x: bounds.midX, y: bounds.midY)
        let radius = min(bounds.width, bounds.height) / 2.3
        let labelCount = labelTexts.count // Number of text labels
        let labelAngle = CGFloat.pi * 2.0 / CGFloat(labelCount)
        
        for i in 0..<labelCount {
            let label = UILabel()
            label.text = labelTexts[i]
            label.sizeToFit()
            
            // Calculate label position
            let angle = CGFloat(i) * labelAngle
            let x = center.x + radius * cos(angle)
            let y = center.y + radius * sin(angle)
            
            // Adjust label position to make it circular
            label.center = CGPoint(x: x, y: y)
            label.transform = CGAffineTransform(rotationAngle: angle + CGFloat.pi / 2)
            
            addSubview(label)
        }
    }
    


    func rotateWheel() {
        let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation")
        rotationAnimation.fromValue = 0.0
        rotationAnimation.toValue = CGFloat.pi * 2.0
        rotationAnimation.duration = 2.0
        rotationAnimation.repeatCount = .infinity
        layer.add(rotationAnimation, forKey: "rotate")
    }
}

USAGE

let circularWheelView = CircularWheelView(frame: CGRect(x: 50, y: 100, width: 300, height: 300))
        circularWheelView.labelTexts = ["Settings 1", "Setting 2", "Setting 3", "Setting 4", "Setting 5"]
        circularWheelView.image = UIImage(resource: .letter)
        circularWheelView.backgroundColor = .clear
        view.addSubview(circularWheelView)
        
        // Start rotating the wheel
        circularWheelView.rotateWheel()

Please check video for reference

0
Benzy Neez On

The answer to SwiftUI: How to have equal spacing between letters in a curved text view? provides a SwiftUI solution for showing curved text (it was my answer).

Here is how it could be used to show curved labels like in your image:

struct ContentView: View {

    private let textRadius: CGFloat = 130
    @State private var rotationDegrees = 0.0

    private func curvedText(text: String, angleDegrees: Double) -> some View {

        // See https://stackoverflow.com/a/77280669/20386264
        CurvedText(string: text, radius: textRadius)
            .offset(y: -textRadius)
            .rotationEffect(.degrees(angleDegrees))
    }

    var body: some View {
        ZStack {
            Circle()
                .stroke(.white, lineWidth: 35)
                .frame(width: textRadius * 2, height: textRadius * 2)

            curvedText(text: "Krisje >", angleDegrees: 0)
            curvedText(text: "Settings >", angleDegrees: 90)
            curvedText(text: "Statistieken >", angleDegrees: 180)
            curvedText(text: "Stijn >", angleDegrees: 270)
        }
        .font(.custom("MarkerFelt-Thin", size: 24))
        .foregroundStyle(.black)
        .rotationEffect(.degrees(rotationDegrees))
        .animation(
            .linear(duration: 20).repeatForever(autoreverses: false),
            value: rotationDegrees
        )
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color(red: 0.53, green: 0.58, blue: 0.63))
        .onAppear { rotationDegrees = 360 }
    }
}

Animation