0

Why has only the orange Color a right animation? Green and Red is laying under the list while the animation, but why?

With VStavk there is no problem but with list. Want an animation when switching from list View to Grid View.

struct Colors: Identifiable{
    var id = UUID()
    var col: Color
}



struct ContentView: View {
    @State var on = true
    @Namespace var ani


    var colors = [Colors(col: .green),Colors(col: .orange),Colors(col: .red)]

    var body: some View {
        VStack {
            if on {
                List{
                ForEach(colors){col in
                    col.col
                        .matchedGeometryEffect(id: "\(col.id)", in: ani)
                        .animation(.easeIn)
                }
                .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
               }
               .listStyle(InsetGroupedListStyle())
               .frame(height: 400)
            } else {
                LazyVGrid(columns: [GridItem(.fixed(200)),GridItem(.fixed(200))], content: {
                    ForEach(colors){col in
                        col.col
                            .matchedGeometryEffect(id: "\(col.id)", in: ani)
                            .animation(.easeIn)
                    }
                })
                .frame(height: 400)

            }
            Button("toggle"){
                withAnimation(.easeIn){
                    on.toggle()
                }
            }
        }
    }
sheldor
  • 115
  • 12
  • 2
    Because you remove not matched views but entire List and List is a complex view (which internal implementation is uncontrolled and unpredictable - how they insert/remove cells is unknown). Instead you have to use either VStack or ScrollView (with own custom cells), those containers are much more lightweight and would allow to have desired effect. – Asperi Jul 24 '21 at 09:09
  • @Asperi Ok that makes sense, thank you – sheldor Jul 25 '21 at 19:34

1 Answers1

0

Thanks to the comment of @Asperi and this post: Individually modifying child views passed to a container using @ViewBuilder in SwiftUI with the answer of @Tushar Sharma I tried something like this:

import SwiftUI

struct SomeContainerView<Content: View>:View {
var ani: Namespace.ID
var model:[Model] = []

init(namespace: Namespace.ID,model:[Model],@ViewBuilder content: @escaping (Model) -> Content) {
    self.content = content
    self.model = model
    ani = namespace
}

let content: (Model) -> Content

var body: some View {
    VStack{
        ForEach(model,id:\.id){model in
            content(model)
                .background(Color.gray.matchedGeometryEffect(id: model.id, in: ani))
        }
    }
}
}

struct ContentView:View {
@ObservedObject var modelData = Objects()
@Namespace var ani
@State var show = true

var body: some View{
    VStack{
        Toggle("toggle", isOn: $show.animation())
        if show{
            SomeContainerView(namespace: ani,model: modelData.myObj){ data in
                HStack{
                    Text("\(data.name)")
                    data.color.frame(width: 100,height : 100)
                }
                
            }
        }else{
            LazyVGrid(columns: [GridItem(.fixed(110)),GridItem(.fixed(110))],spacing: 10){
                ForEach(modelData.myObj){model in
                    Text("\(model.name)")
                        .frame(width: 100,height: 100)
                        .background(Color.gray.matchedGeometryEffect(id: model.id, in: ani))
                }
            }
        }
    }
    
}
}

struct Model: Identifiable{

var id = UUID().uuidString
var name:String
var color:Color

init(name:String,color:Color) {
    self.name = name
    self.color = color
}

}

class Objects:ObservableObject{

@Published var myObj:[Model] = []

init() {
    initModel()
}

func initModel(){
    let model = Model(name: "Jack", color: .green)
    let model1 = Model(name: "hey Jack", color: .red)
    let model2 = Model(name: "hey billy", color: .red)
    
    myObj.append(model)
    myObj.append(model1)
    myObj.append(model2)
}

}



struct ContentView_Previews: PreviewProvider {
static var previews: some View {
    ContentView()
}
}
sheldor
  • 115
  • 12