Broken Animation SwiftUI

痴心易碎 提交于 2020-03-03 14:02:49

问题


I initially had this question here. The solution proposed by @arsenius was working for this toy example. However, my application is more complex and it took me forever to find out where the animation breaks. In the example I used two animated HStack. But if I replace these HStack with two different (!) custom views, the animation is broken again.

Here is the code:

class State:ObservableObject{
    @Published var showSolution = false
}

struct ContentView: View {
    @EnvironmentObject var state:State

    var body:some View {
        VStack {
            if state.showSolution{
                CustomToggleOne()
                    .background(Color.red)
                    .id("one")
                    .animation(Animation.default)
                    .transition(.slide)
            } else {
                CustomToggleTwo()
                    .background(Color.yellow)
                    .id("two")
                    .animation(Animation.default.delay(2))
                    .transition(.slide)
            }
        }
    }
}

struct CustomToggleOne: View{
    @EnvironmentObject var state:State

    var body:some View{
        HStack{
            Spacer()
            Button(action:{
                withAnimation {
                    self.state.showSolution.toggle()
                }
            }){
                Text("Next")
            }.padding()
            Spacer()
        }
    }
}

struct CustomToggleTwo: View{
    @EnvironmentObject var state:State

    var body:some View{
        HStack{
            Spacer()
            Button(action:{
                withAnimation {
                    self.state.showSolution.toggle()
                }
            }){
                Text("Next")
            }.padding()
            Spacer()
        }
    }
}

I added an instance of State to the ContentView in SceneDelegate.swift as an EnvironmentObject as follows:

let contentView = ContentView().environment(\.managedObjectContext, context).environmentObject(State())

The expected animation can be seen when we use CustomToggleOne() twice in the ContentView instead of CustomToggleTwo().


回答1:


Here is the approach that is correct, some explanations below and in comments. Tested with Xcode 11.2 / iOS 13.2

Reminder: don't test transitions in Preview - only on Simulator or Device

// !! Don't name your types as API,
// State is SwiftUI type, might got unpredictable weird issues
class SolutionState:ObservableObject{
    @Published var showSolution = false
}

struct TestBrokenAnimation: View {
    @EnvironmentObject var state:SolutionState

    var body:some View {
        VStack {
            if state.showSolution{
                CustomToggleOne()
                    .background(Color.red)
                    .id("one")
                    .transition(.slide) // implicit animations confuse transition, don't use it
            } else {
                CustomToggleTwo()
                    .background(Color.yellow)
                    .id("two")
                    .transition(.slide)
            }
        }
    }
}
public func withAnimation<Result>(_ animation: Animation? = .default, 
              _ body: () throws -> Result) rethrows -> Result

as it seen withAnimation is not state, which just activate animations defined via modifier, it explicitly applies specified animation, own, so having more in modifiers will definitely result in some conflicts.

So using only explicit animations with transitions.

struct CustomToggleOne: View{
    @EnvironmentObject var state:SolutionState

    var body:some View{
        HStack{
            Spacer()
            Button(action:{
                withAnimation(Animation.default.delay(2)) {
                    self.state.showSolution.toggle()
                }
            }){
                Text("Next")
            }.padding()
            Spacer()
        }
    }
}

struct CustomToggleTwo: View{
    @EnvironmentObject var state:SolutionState

    var body:some View{
        HStack{
            Spacer()
            Button(action:{
                withAnimation() {
                    self.state.showSolution.toggle()
                }
            }){
                Text("Next")
            }.padding()
            Spacer()
        }
    }
}


来源:https://stackoverflow.com/questions/60464094/broken-animation-swiftui

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!