SwiftUI conditional view will not animate/transition
Place your .transition
on the container of the views that will switch, not each conditional view. Here's a trivial example from some code I have done (which works).
In the main View that needs to transition conditionally:
import SwiftUI
struct AppWrapperView: View {
@State var showFirstRun:Bool = true
var body: some View {
ZStack {
if (showFirstRun) {
FirstRunView(showFirstRun: $showFirstRun)
} else {
Text("Some other view")
}
}
.transition(.slide)
}
}
Then, somewhere in the view that triggers the change in condition:
import SwiftUI
struct FirstRunView: View {
@Binding var showFirstRun:Bool
var body: some View {
Button(action: {
withAnimation {
self.showFirstRun = false
}
}) {
Text("Done")
}
}
}
Transition animation behavior is not as expected in SwiftUI with double If and if else conditional
I found a solution for this issue. The difference likely has to do with how the SwiftUI Result Builder translates the if-else statement into buildIf, buildEither, etc vs. how the if-else statements are translated. See: https://jasonzurita.com/swiftui-if-statement/
If you explicitly define asymmetric transitions in the if-else statement:
VStack {
homeHeader
columnTitles
if !showPortfolio {
allCoinsListView
.transition(.asymmetric(insertion: .move(edge: .leading),
removal: .move(edge: .trailing)))
} else {
portfolioListView
.transition(.asymmetric(insertion: .move(edge: .trailing),
removal: .move(edge: .leading)))
}
Spacer(minLength: 0)
}
I found the answer to this issue thanks to this post:
SwiftUI Switch Statement Transition Behavior is not as expected
SwiftUI Conditional View Transitions are not working
change
group
toZStack
add animation somewhere.
class ApplicationHostingViewModel: ObservableObject {
@Published var value: Bool = false
}
struct ApplicationHostingView: View {
// view model env obj
@ObservedObject var applicationHostingViewModel : ApplicationHostingViewModel
var body: some View {
ZStack {
if applicationHostingViewModel.value {
LoginView()
.transition(.move(edge: .leading))
} else {
IntroView(applicationHostingViewModel:applicationHostingViewModel)
}
}
}
}
struct IntroView: View {
// view model env obj
@ObservedObject var applicationHostingViewModel : ApplicationHostingViewModel
var body: some View {
Button(action: {
withAnimation(.default){
self.applicationHostingViewModel.value = true} }) {
Text("Continue")
}
}
}
struct LoginView: View {
var body: some View {
Text("Hello World").frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
Transition animation not working in SwiftUI
The problem is that when views come and go in a ZStack, their "zIndex" doesn't stay the same. What is happening is that the when "showMessage" goes from true to false, the VStack with the "Hello World" text is put at the bottom of the stack and the yellow color is immediately drawn over top of it. It is actually fading out but it's doing so behind the yellow color so you can't see it.
To fix it you need to explicitly specify the "zIndex" for each view in the stack so they always stay the same - like so:
struct ContentView: View {
@State private var showMessage = false
var body: some View {
ZStack {
Color.yellow.zIndex(0)
VStack {
Spacer()
Button(action: {
withAnimation(.easeOut(duration: 3)) {
self.showMessage.toggle()
}
}) {
Text("SHOW MESSAGE")
}
}.zIndex(1)
if showMessage {
Text("HELLO WORLD!")
.transition(.opacity)
.zIndex(2)
}
}
}
}
How to animate a view transition on a conditional view?
The .animation
modifier should be applied to a container owning conditional view, so it could animate appear/disapper transition, like
VStack {
if S1 {
VX("V1")
.transition(transition)
}
// ... other code
}
.animation(.easeOut, value: S1) // < here !!
Conditional animation in SwiftUI stops working
You can specify Animation
in the withAnimation
block and create separate functions for starting/stopping the animation.
Here is a possible solution:
struct ContentView: View {
@State private var done = false
@State private var animationAmount: CGFloat = 0
var body: some View {
VStack {
Toggle("Done", isOn: $done)
plusImage
.opacity(done ? 0.6 : 1)
.foregroundColor(done ? .gray : .green)
}
.onAppear(perform: startAnimation)
.onChange(of: done) { done in
if done {
stopAnimation()
} else {
startAnimation()
}
}
}
var plusImage: some View {
Image(systemName: "plus")
.font(.system(size: 40))
.padding()
.overlay(
Circle()
.stroke(Color.gray, lineWidth: 3)
.scaleEffect(1 + animationAmount)
)
}
}
private extension ContentView {
func startAnimation() {
withAnimation(Animation.easeInOut(duration: 1).repeatForever()) {
animationAmount = 0.1
}
}
func stopAnimation() {
withAnimation {
animationAmount = 0
}
}
}
SwiftUI Switch Statement Transition Behavior is not as expected
The difference likely has to do with how the SwiftUI result builder translates the if
statement into buildIf
, buildEither
, etc vs. how the switch
statements are translated. See: https://jasonzurita.com/swiftui-if-statement/
It looks like you can get the behavior to match the if
statements if you explicitly define asymmetric transitions in the switch
statement:
switch exampleStep {
case .stepOne:
Rectangle()
.foregroundColor(Color.green)
.frame(width: 100, height: 100)
.transition(.asymmetric(insertion: .move(edge: .leading), removal: .move(edge: .trailing)))
case .stepTwo:
Rectangle()
.foregroundColor(Color.red)
.frame(width: 100, height: 100)
.transition(.asymmetric(insertion: .move(edge: .trailing), removal: .move(edge: .leading)))
}
How to add transition for conditionally rendered view in SwiftUI?
It might be better to keep the animation-related logic (like withAnimation
) inside the view.
A possible solution is to create a custom Binding
:
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var binding: Binding<Bool> {
.init(get: {
viewModel.showRow
}, set: { newValue in
withAnimation {
viewModel.showRow = newValue
}
})
}
var body: some View {
List {
Text("Text")
Toggle("Toggle", isOn: binding)
.toggleStyle(SwitchToggleStyle(tint: Color.red))
if viewModel.showRow {
Text("Hidden Text")
}
}
.listStyle(GroupedListStyle())
}
}
Related Topics
How to Catch an Exception in Swift
Abstract Class and Abstract Function in Swift
Execute Code on Main Thread from Async F#
Swift: Draw a Semi-Sphere in Mkmapview
How to Draw Something on a PDF in Swift
Verifying The Purchase (Receipt) of Another Application (Mac App Store)
How to Populate Table Rows, Using a [String] Array Sent from iPhone by Watch Connectivity
Preparing for Swift 4 - Unsafemutablepointer Migration to Unsafemutablebufferpointer
How to Get an Array of Days Between Two Dates in Swift
Uipickerviewdelegate Xcode 8 Swift 3
Macos Swift UI View Where There Is a Search Field in The Title Bar
How to Load Lcr Image in Tvos Apps
Query Value Between Two Other Values in Firebase
How to Find The Top 3 Maximum Values in a Swift Dictionary