Below I have three Text views, the location of View 3
will be dynamic every time the app loads, and what I would like to be able to do is animate View 2
to the exact position of View 3
regardless of where View 3
is on the screen.
I found this thread but I'm not sure how to use ReometryReader
to accomplish what I need.
How can I get the current position of View 3
?
How can I assign the x and y position of the View 3
to xPosition
and yPosition
respectively inside the withAnimation method?
struct PositioningViews: View {
@State private var xPosition:CGFloat = 0
@State private var yPosition:CGFloat = 0
var body: some View {
HStack {
Text("View 1")
.background(.purple)
Text("View 2")
.background(.orange)
.offset(x: xPosition, y: yPosition)
.onAppear {
withAnimation(Animation.easeOut(duration: 0.3).delay(0.5)) {
self.xPosition = 50
self.yPosition = 0
}
}
Text("View 3")
.background(.blue)
}
}
}
Complete Working Code:
struct PositioningViews: View {
@State private var xPosition2:CGFloat = 0
@State private var yPosition2:CGFloat = 0
@State private var xPosition3:CGFloat = 0
@State private var yPosition3:CGFloat = 0
@State private var offsetValueX = 0.0
@State private var offsetValueY = 0.0
var body: some View {
HStack {
Text("View 1")
.background(.purple)
Text("View 2")
.background(.orange)
.overlay(
GeometryReader{ geo -> AnyView in
AnyView(Color.clear
.onAppear(){
xPosition2 = geo.frame(in: .global).midX
yPosition2 = geo.frame(in: .global).midY
})
}
)
.background(.blue)
.offset(x: offsetValueX, y: offsetValueY)
.onAppear(){
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
withAnimation {
offsetValueX = xPosition3 - xPosition2
offsetValueY = yPosition3 - yPosition2
}
}
}
.zIndex(2)
Text("View 3")
.background(.blue)
.overlay(
GeometryReader{ geo -> AnyView in
AnyView(Color.clear
.onAppear(){
xPosition3 = geo.frame(in: .global).midX
yPosition3 = geo.frame(in: .global).midY
})
}
)
.zIndex(1)
}
}
}
EDIT, Without AnyView:
struct PositioningViews: View {
@State private var xPosition2:CGFloat = 0
@State private var yPosition2:CGFloat = 0
@State private var xPosition3:CGFloat = 0
@State private var yPosition3:CGFloat = 0
@State private var offsetValueX = 0.0
@State private var offsetValueY = 0.0
var body: some View {
HStack {
Text("View 1")
.background(.purple)
Text("View 2")
.background(.orange)
.overlay(
GeometryReader{ geo in
Color.clear
.onAppear(){
xPosition2 = geo.frame(in: .global).midX
yPosition2 = geo.frame(in: .global).midY
}
}
)
.background(.blue)
.offset(x: offsetValueX, y: offsetValueY)
.onAppear(){
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
withAnimation {
offsetValueX = xPosition3 - xPosition2
offsetValueY = yPosition3 - yPosition2
}
}
}
.zIndex(2)
Text("View 3")
.background(.blue)
.overlay(
GeometryReader{ geo in
Color.clear
.onAppear(){
xPosition3 = geo.frame(in: .global).midX
yPosition3 = geo.frame(in: .global).midY
}
}
)
.zIndex(1)
}
}
}
import SwiftUI
@available(macOS 13.0, *)
public extension View {
func getFrameInfo(_ space: CoordinateSpace ,_ pos: Binding<CGRect>) -> some View {
self.modifier(GetFrameInfo(space: space, pos: pos))
}
}
@available(macOS 13.0, *)
private struct GetFrameInfo: ViewModifier {
let space: CoordinateSpace
@Binding var pos: CGRect
func body(content: Content) -> some View {
content
.onGeometryChange (for: CGRect.self) {
$0.frame(in: space)
} action: { newValue in
pos = newValue
}
}
}
usage:
struct Test: View {
@State private var frame: CGRect = .zero
var body: some View {
Text("hello")
.getFrameInfo(.global, $frame)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With