Home > Software engineering >  Swiftui animate on struct bool change
Swiftui animate on struct bool change

Time:02-28

I Have a struct called line, which contains a bool called isDone.

struct Line : Hashable {
   var isDone : Bool = false
   var text : String 
}

My viewmodel contains an array of these, once a line is entered the isDone is set to true.

class ViewModel: ObservableObject {
    @Published var lines : [Line] = []
    @Published var currentRowIndex : Int = 0

func EnterWord() {
    lines[currentRowIndex].isDone = true   
    currentRowIndex  = 1
}

}

When the line is entered I would like to have a 3D animation as seen below.

struct Line : View{
    var line : Line
    
var body: some View {
                Text(line.tex)
                    .rotation3DEffect(
                        Angle.degrees(line.isDone ? 180: 0),
                    axis: (1,0,0),
                    perspective: 0)
                 .animation(.linear(duration: 4.0), value: 180)
            }     
    }

struct MainView: View {
    @ObservedObject var viewModel : ViewModel = ViewModel()
    var body: some View {

        VStack(spacing:0){
            ForEach(viewModel.lines, id: \.self){ line in
                Line(line: line)
            }
            
            Button(action: {
                viewModel.Enter()
            })
            {
                Text("Add")
            }
        }
    }
}

The rotation is shown but not animated, does the lack of animation have something to do with me using a struct instead of an ObservableObject? or is the animation code itself wrong?

CodePudding user response:

You can't use the ForEach View struct with id:\.self when using value types, you have to either supply the name of the identifier property or make your data conform to Identifiable that has an id property. e.g.

struct Line : Identifiable {
   let id = UUID()
   var isDone = false
   var text: String 
}

ForEach(model.lines) { line in 

This is because the ForEach needs to know the identifier to track changes, because with value types they are copied around and there is no reference to track.

Also you shouldn't init your model lifetime manager object with @ObservableObject because it creates a new object every time the View is init which is on every state change of the parent. You can use @StateObject instead if you want the object to be destroyed when this View dissapears. If you want it for the lifetime of your app you can init it as a singleton or global and then use @ObservedObject var = Model.shared.

CodePudding user response:

remove perspective and try like this .rotation3DEffect(.degrees(line.isDone ? 180: 0), axis: (x: 1, y: 0, z: 0))

  • Related