Im trying to move an image right to left for an animation but can figure out how to change start and end position based on device type, iPad vs iPhone. I can't set xpos and ypos for start position within view otherwise I get a 'Type () cannot conform to View' error so I moved code to .onAppear which sets xpos and ypos based on device type but this code executes after start position is already set. Code is below
import Foundation
import SwiftUI
struct Home1View: View {
@State var xpos: CGFloat = 350
@State var ypos: CGFloat = 450
@State var opac: Double = 1.0
@State var dHeight: Int = 0
let layoutProperties:LayoutProperties
var body: some View {
GeometryReader { geometry in
ZStack {
ResponsiveView {properties in
VStack{
Text("XXXX")
Image("number-one")
.resizable()
.frame(width: layoutProperties.dimensValues.frameSz, height: layoutProperties.dimensValues.frameSz)
.position(x: xpos, y: ypos)
.opacity(opac)
.onAppear {
//ipad 13in width = 1032 height 870
print("display height on appear = ", geometry.size.height)
print("display width on appear = ", geometry.size.width)
xpos = geometry.size.width - 100
ypos = geometry.size.height - 150
withAnimation(Animation.easeInOut(duration: 3).repeatCount(2, autoreverses: false)) {
xpos = 100
//.position(x: layoutProperties.dimensValues.xpos, y: layoutProperties.dimensValues.ypos-250)
} completion: {
opac = 0.0
}
}
} //end ZStack
} //end geometry
}
}
Instead of trying to set an absolute initial .position
and then modifying this absolute position, I would suggest performing the animation using relative positioning techniques:
apply padding to the image to define the minimum gaps to the edges
set a .frame
of maximum size and use an alignment
parameter to define the corner or edge for alignment
perform the animation by changing the alignment
a GeometryReader
is not needed.
The updated version below starts with the image 100 points from the bottom and 50 points from the trailing edge. The animation moves it to 100 points from the top and 50 points from the leading edge (in other words, to the opposite corner, with the same gaps to the edges of the safe area). This works on all screen sizes.
@State private var imageAlignment = Alignment.bottomTrailing
Image("number-one")
.resizable()
.frame(width: layoutProperties.dimensValues.frameSz, height: layoutProperties.dimensValues.frameSz)
.padding(.horizontal, 50)
.padding(.vertical, 100)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: imageAlignment)
.opacity(opac)
.onAppear {
withAnimation(.easeInOut(duration: 3).repeatCount(2, autoreverses: false)) {
imageAlignment = .topLeading
} completion: {
opac = 0.0
}
}