Вложенный заголовок ForEach + ScrollView вызывает сбои

Внутри Scrollview я использую LazyVStack с закрепленным заголовком, и в зависимости от положения прокрутки я управляю масштабом этого заголовка.

В LazyVStack у меня есть ForEach, перебирающий некоторый список элементов. Однако, если я использую вложенный цикл ForEach (чтобы, скажем, элементы были сгруппированы по месяцам), прокрутка становится чрезвычайно глючной/дерганой.

Минимальный воспроизводимый код:

      struct Nested: View {
    @State var yValueAtMinScale: Double = 100 // y value at which header is at minimum scale (used for linear interpolation)
    @State var headerScale = 1.0
    var restingScrollYValue = 240.0 // y value of scroll notifier when scrollview is at top
    
    var body: some View {
        ZStack {
            ScrollView {
                LazyVStack(pinnedViews: [.sectionHeaders]) {
                    Section(
                        header:
                            Circle()
                                .fill(Color.red)
                                .frame(width: 150, height: 150)
                                .scaleEffect(CGFloat(headerScale), anchor: .top)
                                .zIndex(-1)
                    ) {
                        
                        // scroll position notifier
                        // i set the header's scale based on this view's global y-coordinate
                        GeometryReader { geo -> AnyView in
                            let frame = geo.frame(in: .global)
                            print("miny", frame.minY)
                            DispatchQueue.main.async {
                                self.headerScale = calculateHeaderScale(frameY: frame.minY)
                            }
                            return AnyView(Rectangle()) // hack
                        }
                        .frame(height: 0) // zero height hack
                        
                        
                        ForEach(1...10, id: \.self) { j in
                            Section {
                                Text("\(j)")
                                // works without nested loop
                                ForEach(1...3, id: \.self) { i in
                                    Rectangle()
                                        .frame(height: 50)
                                        .padding(.horizontal)
                                        .id(UUID())
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    
    // interpolates some linear value bounded between 0.75 and 1.5x, based on the scroll value
    func calculateHeaderScale(frameY: CGFloat) -> Double {
        let minScale = 0.75
        let linearValue = (1-minScale) * (Double(frameY) - yValueAtMinScale) / (restingScrollYValue - yValueAtMinScale) + minScale
        return max( 0.75, min(1.5, linearValue) )
    }
}

Удаление внутреннего вложенного цикла ForEach устраняет проблему. Что здесь может происходить? Я полагал, что обновление шкалы заголовка при каждом обновлении прокрутки будет слишком большим количеством обновлений представления и вызовет сбои, но это не объясняет, почему это работает с одним циклом ForEach.

0 ответов

Другие вопросы по тегам