Zack
Zack

Reputation: 1574

How can I animate SwiftUI state changes from specific values to new state values?

I have a rectangle view that I animate the position when position state changes. This animates implicitly from original point to new state value.

@State var position: (Double, Double)

GeometryReader { geo in
  Rectangle()
      .fill(Color.red)
      .frame(width: 200, height: 200)
      .position(x: geo.size.width * CGFloat(position.0), y: geo.size.height * CGFloat(position.1))
}

How can I animate from specific position everytime position state changes. For example I would like to animate from (0.5, 0.5) instead of original position to new position state. This would make the view appear at position (0.5, 0.5) then animate to new position state.

This is the default animation

enter image description here

This is the animation I want to apply

enter image description here

Upvotes: 0

Views: 1211

Answers (1)

Gry
Gry

Reputation: 111

Here's an example of what i hope is what you needed, in the move function is where i added the start and end position change state logic.

i renamed and updated the position type because the 'position' name is already reserved by swiftui if you use it inside a View function. The var animate state is not needed most of the time, it's function is to disable the animation to move the rectangle on the desired animation offset but is just there in case you want to chain multiple change positions at the same time, otherwise you can remove it.

You can test changing the from and to values as you need.

struct ExampleView: View {
    @State var positionPoint: CGPoint = CGPoint.init(x: 0.5, y: 0.5)
    @State var animate: Bool = false

    var body: some View {
        ZStack {
            GeometryReader { geo in
                Rectangle()
                    .fill(Color.red)
                    .frame(width: 200, height: 200)
                    .position(x: geo.size.width * positionPoint.x,
                              y: geo.size.height * positionPoint.y)
                    .animation(animate ? .easeIn : nil)
            }
            
            VStack(spacing: 10) { // some test button
                Button(action: {
                    move(from: (0.2, 0.7), to: (0.8, 0.3))
                }, label: {
                    Text("from: (0.2, 0.7), to: (0.8, 0.3)")
                })
                Button(action: {
                    move(from: (1, 1), to: (0.1, 0.1))
                }, label: {
                    Text("from: (1, 1), to: (0.1, 0.1)")
                })
                Button(action: {
                    move(from: (0.6, 0.6), to: (0.5, 0.9))
                }, label: {
                    Text("from: (0.6, 0.6), to: (0.5, 0.9)")
                })
                Button(action: {
                    move(from: (0.8, 0.1), to: (0.3, 1))
                }, label: {
                    Text("from: (0.8, 0.1), to: (0.3, 1)")
                })
            }
        }
    }
    
    func move(from: (CGFloat, CGFloat), to: (CGFloat, CGFloat)) {
        animate = false
        positionPoint = CGPoint.init(x: from.0, y: from.1)
        withAnimation {
            animate = true
            positionPoint = CGPoint.init(x: to.0, y: to.1)
        }
    }

}

Upvotes: 0

Related Questions