Search code examples
listswiftuitaskswiftui-listonappear

Why last few items does't show onAppear in normal swiftui list?


Very simple code! When i scroll down the list, show onAppear(same as task) from 0 to 24, last few items(25-29) does't show. why?

I did some logic depending on this, and succeed with old version swiftui. but now, fail in latest version.

I think maybe for item reusing, but all these things should be hide for developer, We want something that is logical and intuitive.

why? any suggestion?

struct ListTest: View {
    @State private var nums: [Int] = Array(0..<30)
    
    var body: some View {
        VStack {
            List(nums, id: \.self) { i in
                Label("\(i)", systemImage: "\(i).circle")
                    .task {
                        print("task \(i)")
                    }
                    .onAppear {
                        print("onAppear \(i)")
                    }
                    .onDisappear {
                        print("onDisappear \(i)")
                    }
            }
        }
    }
}

logs:

onAppear 11
onAppear 10
onAppear 9
onAppear 8
onAppear 7
onAppear 6
onAppear 5
onAppear 4
onAppear 3
onAppear 2
onAppear 1
onAppear 0
task 11
task 10
task 9
task 8
task 7
task 6
task 5
task 4
task 3
task 2
task 1
task 0
onAppear 12
task 12
onDisappear 0
onAppear 13
task 13
onDisappear 1
onAppear 14
task 14
onDisappear 2
onAppear 15
task 15
onDisappear 3
onAppear 16
task 16
onDisappear 4
onAppear 17
task 17
onDisappear 5
onAppear 18
task 18
onDisappear 6
onAppear 19
task 19
onDisappear 7
onAppear 20
task 20
onDisappear 8
onAppear 21
task 21
onDisappear 9
onAppear 22
task 22
onDisappear 10
onAppear 23
task 23
onDisappear 11
onAppear 24
task 24
onDisappear 12
onDisappear 13
onDisappear 14
onDisappear 15
onDisappear 16
onDisappear 17
onDisappear 18
onDisappear 19
onDisappear 20

Solution

  • Making list item rebuilt can make item onappear act normal. here is my solution:

        @State private var nums: [Int] = Array(0..<30)
        
        var body: some View {
            VStack {
                List(nums, id: \.self) { i in
                    ItemView(num: num)
                }
            }
        }
    }
    
    struct ItemView: View {
        @State private var show: Bool = true
        let num: Int
        
        init(num: Int) {
            self.num = num
            print("init \(num)")
        }
        
        var body: some View {
            let _ = print("refresh \(num)")
            Group {
                if show { // <--- HERE
                    Label("\(num)", systemImage: "\(num).circle")
                } else {
                    Text("")
                }
            }
                .onAppear {
                    show = true
                    print("onAppear \(num)")
                }
                .onDisappear {
                    show = false
                    print(("onDisappear \(num)"))
                }
        }
    }