Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unwanted position animation in iOS 14 SwiftUI

Swift UI animations seem to behave differently regarding to the animation of a View position in its parent frame for iOS 14 versus iOS 13. My goal in the code snippet below is to only animate the resizing of the button text, which should happen on tapping it. Instead, in iOS 14, the displacement of the button, which is induced by the toggled visibility of an additional View in the VStack, is also being animated.

Identical code produces different outputs in iOS 13 (Xcode 11) and iOS 14 (Xcode 12 beta 6, on macOS 11 beta). In iOS 14, how can the old behavior be reproduced?

import SwiftUI
import PlaygroundSupport

struct ContentView: View {
    @State var toggle = false
    var body: some View {
        VStack{
            if self.toggle {
                Rectangle().frame(width: 200, height: 200)
            }
            Button(action: {
                self.toggle.toggle()
            }){
                Text("Tap me!")
                    .scaleEffect(self.toggle ? 2 : 1)
                    .animation(
                        Animation.easeInOut(duration: 1.5)
                    )
            }
        }
        .frame(width: 400, height: 400)
    }
}

PlaygroundPage.current.setLiveView(ContentView())

This is the desired behavior, as in iOS 13 iOS 13 behavior

This is the unwanted behavior, as in iOS 14 iOS 14 behavior

Note that, at least for me, the same unwanted behavior occurs not only in a Playground, but also for iOS 14 in Xcode Previews, as well as in the Simulator and on Device (see project files https://github.com/himbeles/PositionAnimationExample): iOS 14 behavior Xcode Preview

like image 649
lsrggr Avatar asked Sep 06 '20 16:09

lsrggr


People also ask

How do I change the position of a view in SwiftUI?

Shift the location of a view's content For example, the offset(x:y:) modifier uses the parameters of x and y to represent a relative location within the view's coordinate space. In SwiftUI, the view's coordinate space uses x to represent a horizontal direction and y to represent a vertical direction.

What is the default animation SwiftUI?

default is a basic animation with 0.35 seconds duration and an ease-in-ease-out timing curve.


1 Answers

This is a change in behavior that is visible in iOS 14, macOS Big Sur, and the Swift Playground if you’re using Xcode 12 on macOS Catalina or macOS Big Sur.

You only want the scaling to animate.

A workaround is to change to an explicit animation and use a different toggle to control the scaling. Then wrap the toggling of scale.toggle with withAnimation { }:

struct ContentView: View {
    @State var toggle = false
    @State var scale = false
    var body: some View {
        VStack{
            if self.toggle {
                Rectangle().frame(width: 200, height: 200)
            }
            Button(action: {
                self.toggle.toggle()
                withAnimation(.easeInOut(duration: 1.5)) {
                    self.scale.toggle()
                }
            }){
                Text("Tap me!")
                    .scaleEffect(self.scale ? 2 : 1)
            }
        }
        .frame(width: 400, height: 400)
    }
}
like image 140
vacawama Avatar answered Nov 15 '22 05:11

vacawama