can I get the position of a `View` after layout in SwiftUI?
To export the "as rendered" view coordinates, I created a set of arrays for the x,y coordinates, and saved them in the Model object. However, I had to NOT encapsulate them in @Published var, instead kept them as just "var", otherwise you get into an infinite loop of updating the coordinates and then re-rendering the view.
Using Apple's 'landmark' tutorial, the Model object was modified as follows:
import SwiftUI
import Combine
final class UserData: ObservableObject {
@Published var showFavoritesOnly = false
@Published var landmarks = landmarkData
var circleImageX = Array(repeating: 0.0, count:20)
var circleImageY = Array(repeating: 0.0, count:20)
}
Then, write to those arrays each time the CircleImage.swift is rendered using the following code, again from the 'landmark.swift' tutorial, saving the frame midpoints.
import SwiftUI
struct CircleImage: View {
@EnvironmentObject var userData: UserData
var landmark: Landmark
var landmarkIndex: Int {
userData.landmarks.firstIndex(where: {$0.id == landmark.id})!
}
var body: some View {
ZStack {
landmark.image
.clipShape(Circle())
.overlay(Circle().stroke(Color.white, lineWidth: 4))
.shadow(radius: 10)
VStack {
GeometryReader { geometry -> Text in
let frame = geometry.frame(in: CoordinateSpace.global)
self.userData.circleImageX[self.landmarkIndex] = Double(frame.midX)
return
Text("\(frame.midX)")
.foregroundColor(.red)
.bold()
.font(.title)
}
.offset(x: 0.0, y: 50.0)
GeometryReader { geometry -> Text in
let frame = geometry.frame(in: CoordinateSpace.global)
self.userData.circleImageY[self.landmarkIndex] = Double(frame.midY)
return
Text("\(frame.midY)")
.foregroundColor(.red)
.bold()
.font(.title)
}
.offset(x: 0.0, y: -50.0)
}
}
}
}`
Not only does this save the rendered coordinates, it also renders them as a Text view overlaid with the image as suggested by Jake. Naturally you can delete the Text overlay view once you're satisfied the coordinates are correct. Hope this helps
Use a GeometryReader
to get the frame of each view and use the frame to determine the points for a path between the two views.
struct ContentView : View {
var body: some View {
GeometryReader { geometry -> Text in
let frame = geometry.frame(in: CoordinateSpace.local)
return Text("\(frame.origin.x), \(frame.origin.y), \(frame.size.width), \(frame.size.height)")
}
}
}