Rotate View around an other View SwiftUI

Hello

I created a custom shape in SwiftUI and I am trying to rotate it around a circle, but it works just on the top part of the circle, can you help me make it rotate exactly around the circle?

(And also can I get the same effect using radians? How?)

Here is the code:

import SwiftUI

struct MyGameView: View {
    
    @State private var degress: Double = 0
    
    let timer = Timer.publish(every: 0.05, on: .main, in: .common).autoconnect()
    
    var body: some View {
        VStack{
            ZStack{
                Circle()
                    .frame(width: 80)
                
                ZStack{
                    Circle()
                        .stroke(lineWidth: 1)
                        .frame(width: 300)
                    
                    BallonShape()
                        .scaledToFit()
                        .scaleEffect(0.2)
                        .foregroundColor(.red)
                        .rotationEffect(.degrees(degress), anchor: .bottom)
                        .offset(x: 0, y: -170)
                }
            }
        }
        .onReceive(timer) { input in
            withAnimation(.easeIn(duration: 0.05).speed(10)){
                 degress += 1
            }
        }
    }
}

struct BallonShape: Shape {
    func path(in rect: CGRect) -> Path {
        Path { path in
            path.move(to: CGPoint(x: rect.midX, y: (rect.maxY + rect.midY) / 2))
            path.addCurve(to: CGPoint(x: rect.midX, y: rect.minY), control1: CGPoint(x: (rect.midX + rect.minX) / 2, y: rect.minY), control2: CGPoint(x: (rect.midX + rect.minX) / 2, y: rect.minY))
            path.addCurve(to: CGPoint(x: rect.midX, y: (rect.maxY + rect.midY) / 2), control1: CGPoint(x: (rect.midX + rect.maxX) / 2, y: rect.minY), control2: CGPoint(x: (rect.midX + rect.maxX) / 2, y: rect.minY))
        }
    }
}

Thank You very much!

Answered by OOPer in 687621022

Please try this:

struct MyGameView: View {
    
    @State private var degress: Double = 0
    
    let timer = Timer.publish(every: 0.05, on: .main, in: .common).autoconnect()
    
    var body: some View {
        VStack{
            ZStack{
                Circle()
                    .frame(width: 80)
                
                ZStack{
                    Circle()
                        .stroke(lineWidth: 1)
                        .frame(width: 300)
                    
                    BallonShape()
                        .scaledToFit()
                        .scaleEffect(0.2)
                        .foregroundColor(.red)
                        .offset(x: 0, y: -170)
                        //Uncomment to clarify what is rotating around what
                        //.background(Color(.displayP3, red: 0.7, green: 0, blue: 0.3, opacity: 0.5))
                        .rotationEffect(.degrees(degress), anchor: .center) //<- Move `rotationEffect` after `offset` and use `.center`
                }
            }
        }
        .onReceive(timer) { input in
            withAnimation(.easeIn(duration: 0.05).speed(10)){
                degress += 1
            }
        }
    }
}

You should better try with various sizes of devices or simulators to check if the code works as expected in all the sizes.

I tested your code and it works perfectly. The orange triangle is not always at the same distance, but it turns all around. Tested with

  • Xcode 13.0ß5
  • iPhone 12 Pro Max - iOS 15.0 simulator.

Here are some screen shots:

So, what is the problem ? Is it the distance to the circle ?

Replacing offset

                        .offset(x: 0, y: -170)

with

                        .offset(x: 0, y: -220)

keeps equal distance. Then you will have to adapt path to stick to the circle.

To get in radians, just replace

.rotationEffect(.degrees: degrees) , …

by

.rotationEffect(.radians(someradValue), …
Accepted Answer

Please try this:

struct MyGameView: View {
    
    @State private var degress: Double = 0
    
    let timer = Timer.publish(every: 0.05, on: .main, in: .common).autoconnect()
    
    var body: some View {
        VStack{
            ZStack{
                Circle()
                    .frame(width: 80)
                
                ZStack{
                    Circle()
                        .stroke(lineWidth: 1)
                        .frame(width: 300)
                    
                    BallonShape()
                        .scaledToFit()
                        .scaleEffect(0.2)
                        .foregroundColor(.red)
                        .offset(x: 0, y: -170)
                        //Uncomment to clarify what is rotating around what
                        //.background(Color(.displayP3, red: 0.7, green: 0, blue: 0.3, opacity: 0.5))
                        .rotationEffect(.degrees(degress), anchor: .center) //<- Move `rotationEffect` after `offset` and use `.center`
                }
            }
        }
        .onReceive(timer) { input in
            withAnimation(.easeIn(duration: 0.05).speed(10)){
                degress += 1
            }
        }
    }
}

You should better try with various sizes of devices or simulators to check if the code works as expected in all the sizes.

It works, Thank You OOPer!

Rotate View around an other View SwiftUI
 
 
Q