Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change anchor of rotation angle to center with CGAffineTransform?

For some raisons, in my app in SwiftUI, I need to use transformEffect modifier with CGAffineTransform and rotationAngle property. But the result is la this:

Screen sho of arrow image

How can I set the anchor of rotation angle to center of my arrow image? I see in the document that can we use CGPoint?

My code:

import SwiftUI
import CoreLocation

struct Arrow: View {

  var locationManager = CLLocationManager()
  @ObservedObject var heading: LocationManager = LocationManager()

  private var animationArrow: Animation {
    Animation
      .easeInOut(duration: 0.2)
  }

  var body: some View {
    VStack {
      Image("arrow")
        .resizable()
        .aspectRatio(contentMode: .fit)
        .frame(width: 300, height: 300)
        .overlay(RoundedRectangle(cornerRadius: 0)
        .stroke(Color.white, lineWidth: 2))
        .animation(animationArrow)
        .transformEffect(
        CGAffineTransform(rotationAngle: CGFloat(-heading.heading.degreesToRadians))
          .translatedBy(x: 0, y: 0)
        )

      Text(String(heading.heading.degreesToRadians))
        .font(.system(size: 30))
        .fontWeight(.light)
    }
  }
} 
like image 247
Guillaume Avatar asked Dec 22 '22 21:12

Guillaume


1 Answers

If you want to do it with a transform matrix, you'll need to translate, rotate, translate. But you can perform a rotationEffect with an anchor point. Note that the default anchor point is center. I am just including it explicity, so it works if you want to rotate anchoring somewhere else.

The anchor point is specified in UnitPoint, which means coordinates are 0 to 1. With 0.5 meaning center.

struct ContentView: View {
    @State private var angle: Double = 0

    var body: some View {
        VStack {
            Rectangle().frame(width: 100, height: 100)
                .rotationEffect(Angle(degrees: angle), anchor: UnitPoint(x: 0.5, y: 0.5))

            Slider(value: $angle, in: 0...360)
        }
    }
}

The same effect, using matrices, is uglier, but also works:

struct ContentView: View {
    @State private var angle: Double = 0

    var body: some View {
        VStack {
            Rectangle().frame(width: 100, height: 100)
                .transformEffect(
                    CGAffineTransform(translationX: -50, y: -50)
                        .concatenating(CGAffineTransform(rotationAngle: CGFloat(angle * .pi / 180)))
                        .concatenating(CGAffineTransform(translationX: 50, y: 50)))

            Slider(value: $angle, in: 0...360)
        }
    }
}
like image 194
kontiki Avatar answered May 16 '23 05:05

kontiki