使用SwiftUI实现“加载更多”功能

10
我使用了带有HStack的ScrollView,现在需要在用户滚动到底部时加载更多数据。
var items: [Landmark]

我已经使用了一个项目数组,通过ForEach将其附加到HStack中。

ScrollView(showsHorizontalIndicator: false) {
    HStack(alignment: .top, spacing: 0) {
        ForEach(self.items) { landmark in
            CategoryItem(landmark: landmark)
        }
    }
}

在不使用自定义操作(如loadmore按钮)的情况下,管理SwiftUI中的"load more"最佳解决方案是什么?

2个回答

10

这种情况最好使用ForEach和List

struct ContentView : View {
    @State var textfieldText: String = "String "
    private let chunkSize = 10
    @State var range: Range<Int> = 0..<1

    var body: some View {
        List {
            ForEach(range) { number in
                Text("\(self.textfieldText) \(number)")
            }
            Button(action: loadMore) {
                Text("Load more")
            }
        }
    }

    func loadMore() {
        print("Load more...")
        self.range = 0..<self.range.upperBound + self.chunkSize
    }
}

在这个例子中,每次按下“加载更多”按钮,都会增加“State”属性的范围。对于BindableObject也是如此。如果你想要自动完成,可能需要了解一下拉下刷新按钮的相关信息(我不确定它是否适用于上拉)。
更新:作为一种选择,你可以在最后一个单元格上使用onAppear修饰符来下载新的项目(在本例中,它是一个静态按钮)。
var body: some View {
        List {
            ForEach(range) { number in
                Text("\(self.textfieldText) \(number)")
            }
            Button(action: loadMore) {
                Text("")
                }
                .onAppear {
                    DispatchQueue.global(qos: .background).asyncAfter(deadline: DispatchTime(uptimeNanoseconds: 10)) {
                        self.loadMore()
                    }
            }
        }
    }

请记住,使用dispatch是必要的,因为如果不使用它,您将会遇到一个错误,提示"在更新TableView时TableView正在更新"。可能您可以使用另一种异步方式来更新数据。


不,我不想添加按钮,我只想检测最后一个视图是否可见,如果可见,那么我将加载更多数据。 - PinkeshGjr
感谢您提供的解决方案。正如您所说,只有用户点击按钮才能正常工作,但需要检查如何在没有按钮的情况下完成。 - PinkeshGjr
@PinkeshGjr 但是这个按钮一直可见吗? - zerohedge
@zerohedge 是的,逻辑运行良好,因此我们也可以显示活动而不是按钮。 - PinkeshGjr
@PinkeshGjr - 所以您是有条件地在 onAppear 上显示显示活动吗? - zerohedge
显示剩余3条评论

2
如果您想继续使用带有Data而不是Range的List,您可以实现下一个脚本:
struct ContentView: View {

    @State var items: [Landmark]

    var body: some View {
        List {
            ForEach(self.items) { landmark in
                CategoryItem(landmark: landmark)
                   .onAppear {
                      checkForMore(landmark)
                   }
            }
        }
    }

    func checkForMore(_ item: LandMark) {
       guard let item = item else { return }

       let thresholdIndex = items.index(items.endIndex, offsetBy: -5)
        if items.firstIndex(where: { $0.id == item.id }) == thresholdIndex {
           // function to request more data
            getMoreLandMarks()
        }
    }
}

你可能应该在 ViewModel 中工作,并将逻辑与 UI 分离。

感谢 Donny Wals:完整示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接