Swift UI ScrollView 加List 实现一个列表 ,还需要包含 多组数据 以及上啦加载更多 下拉刷新

✅ 下拉刷新可以在 Banner 上方触发,会显示系统自带 loading。

✅ Banner 始终在最上方(随列表一起滚动,不被遮挡)。

✅ Section header 会悬浮在 Banner 下方,滚动时固定。

✅ 依旧支持上拉加载更多、底部提示。

importSwiftUI

struct Item: Identifiable {

    letid=UUID()

    lettitle:String

}

struct SectionData: Identifiable {

    letid=UUID()

    letheader:String

    varitems: [Item]

}

struct ContentView: View {

    @Stateprivatevarsections: [SectionData] = [

        SectionData(header:"分组1",items: (1...10).map{Item(title:"分组1-Item\($0)") }),

        SectionData(header:"分组2",items: (1...10).map{Item(title:"分组2-Item\($0)") })

    ]


    @State private var isLoadingMore = false

    @State private var hasMoreData = true


    varbody:someView{

        ScrollView{

            LazyVStack(alignment: .leading,pinnedViews: [.sectionHeaders]) {

                // ✅ Banner 放在 ScrollView 里面

                bannerView

                    .frame(height:100)

                    .frame(maxWidth: .infinity)

                    .background(Color.blue)


                // ✅ Sections 悬浮

                ForEach(sections) { sectionin

                    Section{

                        ForEach(section.items) { itemin

                            Text(item.title)

                                .padding(.horizontal)

                                .padding(.vertical,6)

                                .onAppear{

                                    ifsection.id ==sections.last?.id,

                                       item.id == section.items.last?.id {

                                        loadMore()

                                    }

                                }

                            Divider()

                        }

                    }header: {

                        Text(section.header)

                            .font(.headline)

                            .frame(maxWidth: .infinity,alignment: .leading)

                            .padding()

                            .background(.ultraThinMaterial)// 关键:悬浮时不透明

                    }

                }


                // ✅ 底部提示

                ifisLoadingMore{

                    HStack{

                        Spacer()

                        ProgressView("加载中...")

                        Spacer()

                    }

                    .padding()

                }elseif!hasMoreData{

                    HStack{

                        Spacer()

                        Text("没有更多数据了")

                            .foregroundColor(.secondary)

                            .font(.footnote)

                        Spacer()

                    }

                    .padding()

                }

            }

        }

        // ✅ 下拉刷新在 Banner 上方触发

        .refreshable{

            awaitrefreshData()

        }

    }


    private var bannerView: some View {

        VStack{

            Text("固定在顶部的 Banner")

                .foregroundColor(.white)

                .font(.title2)

        }

    }


    // 下拉刷新

    private func refreshData() async {

        try?awaitTask.sleep(nanoseconds:1_000_000_000)

        sections= [

            SectionData(header:"分组1",items: (1...10).map{Item(title:"刷新后-分组1-Item\($0)") }),

            SectionData(header:"分组2",items: (1...10).map{Item(title:"刷新后-分组2-Item\($0)") })

        ]

        hasMoreData=true

    }


    // 上拉加载更多

    private func loadMore() {

        guard !isLoadingMore, hasMoreData else { return }

        isLoadingMore = true


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

            ifvarlast =sections.last{

                letstart = last.items.count+1

                letmoreItems = (start..

                    Item(title:"\(last.header)-Item\($0)")

                }

                last.items.append(contentsOf: moreItems)

                sections[sections.count-1] = last


                iflast.items.count>=30{

                    hasMoreData=false

                }

            }

            isLoadingMore=false

        }

    }

}

#Preview {

    NavigationStack {

        ContentView()

    }

}

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容