SwiftUI:ScrollView 中的帖子分页

问题描述 投票:0回答:1

在我的 SwiftUI 项目中,我有一个名为 SearchViewModel 的文件,其中定义了一个名为 fetchRandomPosts() 的函数。此函数负责从 Firestore 随机检索帖子。我的问题在于这些帖子在用户界面中的加载方式。目前,所有帖子都会立即显示,这对于应用程序来说并不是最佳选择。我的目标是实现更高效的加载,从 18 个帖子开始初始加载。然后,当用户向下滚动屏幕时,将加载 6 个额外的帖子,依此类推。

SearchViewModel代码:

@Published var posts: [PostModel] = []

// fetchRandomPosts() is to fetch posts randomly
func fetchRandomPosts() {
        db.collectionGroup("user_posts")
            .getDocuments { querySnapshot, error in
                guard let documents = querySnapshot?.documents else {
                    print("Error fetching documents: \(error?.localizedDescription ?? "Unknown error")")
                    return
                }
                
                let posts = documents.compactMap { document -> PostModel? in
                    do {
                        let post = try document.data(as: PostModel.self)
                        return post
                    } catch {
                        print("Error decoding post: \(error.localizedDescription)")
                        return nil
                    }
                }

                let randomPosts = posts.shuffled()

                self.posts = randomPosts
            }
    }


// dividePostsIntoGroups() sets the layout of the post rows in the UI view
func dividePostsIntoGroups() -> [[PostModel]] {
        var groups: [[PostModel]] = []
        var remainingPosts = posts
        
        while !remainingPosts.isEmpty {
            if remainingPosts.count >= 3 {
                groups.append(Array(remainingPosts.prefix(3)))
                remainingPosts = Array(remainingPosts.dropFirst(3))
            } else if remainingPosts.count == 2 {
                groups.append(Array(remainingPosts.prefix(2)))
                remainingPosts = []
            } else if remainingPosts.count == 1 {
                groups.append([remainingPosts.first!])
                remainingPosts = []
            }
        }
        
        return groups
    }

搜索查看代码:

ScrollView(.vertical, showsIndicators: false) {
    VStack {
        let groups = searchViewModel.dividePostsIntoGroups()
        
        ForEach(groups.indices, id: \.self) { index in
            let caseIndex = index % 5
            
            switch caseIndex {
            case 0:
                let post = groups[index].first
                let remainingPosts = Array(groups[index].dropFirst())
                
                HStack(spacing: 7) {
                    KFImage(URL(string: post?.postImage ?? ""))
                            .resizable()
                            .modifier(ImagePostLargeModifier(post: post!))
                    
                    VStack(spacing: 7) {
                        ForEach(remainingPosts.prefix(2)) { post in
                            KFImage(URL(string: post.postImage))
                                .modifier(ImagePostMinModifier(post: post))
                        }
                    }
                }
                
            case 1, 2, 4:
                let posts = groups[index]
                
                HStack(spacing: 7) {
                    ForEach(posts) { post in
                        KFImage(URL(string: post.postImage))
                            .modifier(ImagePostMinModifier(post: post))
                    }
                }
                
            case 3:
                let post = groups[index].last
                let remainingPosts = Array(groups[index].dropLast())
                
                HStack(spacing: 7) {
                    VStack(spacing: 7) {
                        ForEach(remainingPosts.prefix(2)) { post in
                            KFImage(URL(string: post.postImage))
                                .modifier(ImagePostMinModifier(post: post))
                        }
                    }
                    
                    KFImage(URL(string: post?.postImage ?? ""))
                        .modifier(ImagePostLargeModifier(post: post!))
                }
                
            default:
                EmptyView()
            } 
        } 
        .animation(.spring(), value: searchViewModel.posts)
    }
}

我已经使用 GeometryReader 或 ScrollViewReader 寻找了几种解决方案,但到目前为止我找不到执行此任务的正确方法。正如我之前所说,首先带来 18 个帖子,当用户到达屏幕末尾时,会出现另外 6 个帖子,依此类推(基本上是它在社交网络上的工作原理)。

swift swiftui pagination scrollview
1个回答
0
投票

您首先需要在

LazyVStack
中使用
VStack
而不是
ScrollView

此外,你需要实现这样的东西:

struct InfiniteListView: View {
    @State private var items: [Int] = Array(1...18)
    @State private var isFinished = false
    @State private var isLoading = false

    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(items, id: \.self) { item in
                    Text("Item \(item)")
                        .onAppear {
                            if item == items.last && !isFinished {
                                loadMoreItems()
                            }
                        }
                }
                
                if isLoading {
                    ProgressView()
                }
            }
        }
    }

    func loadMoreItems() {
        isLoading = true
        // Simulate an asynchronous call
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            let moreItems = items.count + 1...items.count + 6
            items.append(contentsOf: moreItems)
            
            if items.count > 250 {
                isFinished = true
            }
            
            isLoading = false
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.