在我的 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 个帖子,依此类推(基本上是它在社交网络上的工作原理)。
您首先需要在
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
}
}
}