Search code examples
animationswiftui

Trying to set start position of Image animation based on device type iPhone vs iPad


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
    }
}

Solution

  • 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
            }
        }
    

    Animation