0

I have a really simple list with text that when the user taps on it, it expands with a datepicker inside.

The problem is that the animation looks really broken, not sure what I can do about this besides doing the entire thing from scratch, that at this point I'd rather just use UIKit.

enter image description here

If you have an idea of how this can be fixed I'd really appreciate.

Here's the code:

struct ContentView: View {
    let items = ["123", "345", "678"]
    @State private var selectedItems = Set<String>()
    @State private var test = Date()

    var body: some View {
        Form {
            ForEach(items.indices) { index in
                Button(action: {
                    withAnimation {
                        if selectedItems.contains(items[index]) {
                            selectedItems.remove(items[index])
                        } else {
                            selectedItems.insert(items[index])
                        }
                    }
                }, label: {
                    Text(items[index])
                        .foregroundColor(.primary)
                })
                if selectedItems.contains(items[index]) {
                    DatePicker(selection: $test, in: ...Date(), displayedComponents: .date) {
                            }
                    .datePickerStyle(WheelDatePickerStyle())
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Wak
  • 818
  • 2
  • 11
  • 18

2 Answers2

3

ForEach(content:) should only be used for static collections.

If you have a dynamic collection (such as in your example - you're adding/removing entries), you need to use ForEach(id:content:):

ForEach(items.indices, id: \.self) { index in

Note that if your collection can have duplicate items, then id: \.self will not work properly and you may need to create a struct conforming to Identifiable instead.

pawello2222
  • 46,897
  • 22
  • 145
  • 209
  • Changing to `ForEach(items.indices, id: \.self) { index in` made no difference on the animation glitch =/ – Wak Sep 26 '20 at 18:09
0

Use Section inside ForEach.

struct ContentView: View {
    let items = ["123", "345", "678"]
    @State private var selectedItems = Set<String>()
    @State private var test = Date()

    var body: some View {
        Form {
            ForEach(items.indices) { index in
                Section(header: header(index), content: {
                    if selectedItems.contains(items[index]) {
                        DatePicker(selection: $test, in: ...Date(), displayedComponents: .date) {
                                }
                        .datePickerStyle(WheelDatePickerStyle())
                    }
                })
            }
        }
    }
    
    private func header(_ index: Int) -> some View {
        Button(action: {
            withAnimation {
                if selectedItems.contains(items[index]) {
                    selectedItems.remove(items[index])
                } else {
                    selectedItems.insert(items[index])
                }
            }
        }, label: {
            Text(items[index])
                .foregroundColor(.primary)
        })
    }
}
JIE WANG
  • 1,875
  • 1
  • 17
  • 27