SwiftUI 上拉分页加载更多

261 阅读1分钟

GeometryReader实现的上拉加载更多

**struct** CustomScrollView<Content: View>: View {

    

    @Binding var refresh: Bool

    

    @ViewBuilder **var** content: Content

    

    @State **var** upOffset: CGFloat = .zero

    @State **var** downOffset: CGFloat = .zero

    @State **var** contentMax: Bool = **false**

    @State **private** **var** topMinY: CGFloat = .zero

    @State **private** **var** middleMaxY: CGFloat = .zero

    @State **private** **var** bottomMinY: CGFloat = .zero

    

    **var** body: **some** View {

        VStack(spacing: 0) {

            Color.clear

                .frame(height: 0)

                .background(

                    GeometryReader { proxy -> Color **in**

                        **let** rect = proxy.frame(in: .global)

                        DispatchQueue.main.async {

                            topMinY = rect.minY

                        }

                        **return** Color.clear

                    }

                )

            ScrollView {

                content

                    .background(

                        GeometryReader { proxy -> Color **in**

                            **let** rect = proxy.frame(in: .global)

                        

                            DispatchQueue.main.asyncAfter(deadline: .now()){

                                middleMaxY = rect.maxY

                                

                                upOffset = bottomMinY - middleMaxY

                                downOffset = topMinY-rect.minY

                                

                                contentMax = bottomMinY - topMinY < rect.height

                                **if** contentMax {

                                    **if** upOffset > 80 {

                                        refresh = **true**

                                    } **else** {

                                        refresh = **false**

                                    }

                                } **else** {

                                    **if** downOffset > 80 {

                                        refresh = **true**

                                    } **else** {

                                        refresh = **false**

                                    }

                                }

                            }

                            **return** Color.clear

                        }

                    )

            }

            Color.clear

                .frame(height: 0)

                .background(

                    GeometryReader { proxy -> Color **in**

                        **let** rect = proxy.frame(in: .global)

                        DispatchQueue.main.async {

                            bottomMinY = rect.minY

                        }

                        **return** Color.clear

                    }

                )

        }

    }

}

测试代码

**struct** CustomScrollViewTest: View {

    

    @State **var** refresh: Bool =  **false**

  


    **var** body: **some** View {

        NavigationStack {

            VStack {

                CustomScrollView(refresh: $refresh) {

                    LazyVStack(spacing: 15, content: {

                        ForEach(1 ... 3, id: \.**self**) { index **in**

                            HStack(spacing: 15, content: {

                                Circle()

                                    .fill(Color.gray.opacity(0.6))

                                    .frame(width: 70, height: 70)

                                    .overlay {

                                        Text("\(index)")

                                    }

                                LazyVStack(alignment: .leading, spacing: 15) {

                                    Rectangle()

                                        .fill(Color.gray.opacity(0.6))

                                        .frame(height: 15)

                                    Rectangle()

                                        .fill(Color.gray.opacity(0.6))

                                        .frame(height: 15)

                                        .padding(.trailing, 90)

                                }

                            })

                            .padding()

                        }

                    })

                    .padding(.top)

                }

            }

            .onChange(of: **self**.refresh) { _, newValue **in**

                **if** newValue {

                    print("可加载下一页数据")

                }

            }

            .navigationTitle("refresh=\(refresh.description)")

            .navigationBarTitleDisplayMode(.inline)

        }

    }

}