Why isn't onPreferenceChange being called if it's inside a ScrollView in SwiftUI?

前端 未结 5 2036
逝去的感伤
逝去的感伤 2021-01-02 02:57

I\'ve been seeing some strange behavior for preference keys with ScrollView. If I put the onPreferenceChange inside the ScrollView it won\'t be cal

5条回答
  •  囚心锁ツ
    2021-01-02 03:24

    It seems like the issue is not necessarily with ScrollView, but with your usage of PreferenceKey. For instance, here is a sample struct in which a PreferenceKey is set according to the width of a Rectangle, and then printed using .onPreferenceChange(), all inside of a ScrollView. As you drag the Slider to change the width, the key is updated and the print closure is executed.

    struct ContentView: View {
        @State private var width: CGFloat = 100
    
        var body: some View {
            VStack {
                Slider(value: $width, in: 100...200)
    
                ScrollView(.vertical) {
                    Rectangle()
                        .background(WidthPreferenceKeyReader())
                        .onPreferenceChange(WidthPreferenceKey.self) {
                            print($0)
                    }
                }
                .frame(width: self.width)
            }
        }
    }
    
    struct WidthPreferenceKeyReader: View {
        var body: some View {
            GeometryReader { geometry in
                Rectangle()
                    .fill(Color.clear)
                    .preference(key: WidthPreferenceKey.self, value: geometry.size.width)
            }
        }
    }
    

    As you noted, the first time the key tries to set, the console prints "Bound preference WidthPreferenceKey tried to update multiple times per frame," but a real value is immediately set afterward, and it continues to update dynamically.

    What value are you actually trying to set, and what are you trying to do in .onPreferenceChange()?

提交回复
热议问题