SwiftUI 滚动时检测底部
SwiftUI Detect bottom while scrolling
我已经使用 UIViewRepresentable
在 SwiftUI 中实现了我的自定义 UIScrollView
,我想检测列表的底部以便加载下一批数据.我找到了一些答案,但它们似乎在我的 UIViewRepresentable
.
中不起作用
我已经在我的 Coordinator 中实现了这个,但是当我到达底部时没有任何反应。
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.y + 1) >= (scrollView.contentSize.height - scrollView.frame.size.height) {
print("bottom reached")
// not working
}
}
问题可能出在我的 Swift 视图中而不是 UIViewRepresentable
中吗?
struct CustomScrollView<Content: View, VM: LoadProtocol> : UIViewRepresentable {
var width : CGFloat
var height : CGFloat
var viewModel: VM
let content: () -> Content
func makeCoordinator() -> Coordinator {
Coordinator(self, viewModel: viewModel)
}
func makeUIView(context: Context) -> UIScrollView {
let control = UIScrollView()
control.refreshControl = UIRefreshControl()
control.refreshControl?.addTarget(context.coordinator, action: #selector(Coordinator.handleRefreshControl), for: .valueChanged)
let childView = UIHostingController(rootView: content())
childView.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
control.addSubview(childView.view)
return control
}
func updateUIView(_ uiView: UIScrollView, context: Context) { }
class Coordinator: NSObject {
var control: CustomScrollView<Content, VM>
var viewModel: VM
init(_ control: CustomScrollView, viewModel: VM) {
self.control = control
self.viewModel = viewModel
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.y + 1) >= (scrollView.contentSize.height - scrollView.frame.size.height) {
print("bottom reached")
// not working
}
}
@objc func handleRefreshControl(sender: UIRefreshControl) {
sender.endRefreshing()
viewModel.refresh()
}
}
}
struct SeeAllView: View {
@ObservedObject var seeAllViewModel: SeeAllViewModel
var body: some View {
VStack {
GeometryReader { geometry in
CustomScrollView(width: geometry.size.width, height: geometry.size.height, viewModel: self.seeAllViewModel) {
SeeAllListView(seeAllViewModel: self.seeAllViewModel)
}
}
}
}
}
您没有在 makeUIView
中设置委托。以下更改将修复您的代码 - 我已经删除了一些缺少的依赖项以编译代码。它在 Playground 中按预期工作。
import SwiftUI
import PlaygroundSupport
struct CustomScrollView<Content: View> : UIViewRepresentable {
var width : CGFloat
var height : CGFloat
let content: () -> Content
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UIScrollView {
let control = UIScrollView()
control.refreshControl = UIRefreshControl()
control.refreshControl?.addTarget(context.coordinator, action: #selector(Coordinator.handleRefreshControl), for: .valueChanged)
control.delegate = context.coordinator
let childView = UIHostingController(rootView: content())
childView.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
control.addSubview(childView.view)
return control
}
func updateUIView(_ uiView: UIScrollView, context: Context) { }
class Coordinator: NSObject, UIScrollViewDelegate {
var control: CustomScrollView<Content>
init(_ control: CustomScrollView) {
self.control = control
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.y + 1) >= (scrollView.contentSize.height - scrollView.frame.size.height) {
print("bottom reached")
// not working
}
}
@objc func handleRefreshControl(sender: UIRefreshControl) {
sender.endRefreshing()
}
}
}
struct SeeAllView: View {
var body: some View {
VStack {
GeometryReader { geometry in
CustomScrollView(width: geometry.size.width, height: geometry.size.height) {
List {
Text("1")
Text("2")
Text("3")
}
}
}
}
}
}
PlaygroundPage.current.setLiveView(SeeAllView())
我已经使用 UIViewRepresentable
在 SwiftUI 中实现了我的自定义 UIScrollView
,我想检测列表的底部以便加载下一批数据.我找到了一些答案,但它们似乎在我的 UIViewRepresentable
.
我已经在我的 Coordinator 中实现了这个,但是当我到达底部时没有任何反应。
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.y + 1) >= (scrollView.contentSize.height - scrollView.frame.size.height) {
print("bottom reached")
// not working
}
}
问题可能出在我的 Swift 视图中而不是 UIViewRepresentable
中吗?
struct CustomScrollView<Content: View, VM: LoadProtocol> : UIViewRepresentable {
var width : CGFloat
var height : CGFloat
var viewModel: VM
let content: () -> Content
func makeCoordinator() -> Coordinator {
Coordinator(self, viewModel: viewModel)
}
func makeUIView(context: Context) -> UIScrollView {
let control = UIScrollView()
control.refreshControl = UIRefreshControl()
control.refreshControl?.addTarget(context.coordinator, action: #selector(Coordinator.handleRefreshControl), for: .valueChanged)
let childView = UIHostingController(rootView: content())
childView.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
control.addSubview(childView.view)
return control
}
func updateUIView(_ uiView: UIScrollView, context: Context) { }
class Coordinator: NSObject {
var control: CustomScrollView<Content, VM>
var viewModel: VM
init(_ control: CustomScrollView, viewModel: VM) {
self.control = control
self.viewModel = viewModel
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.y + 1) >= (scrollView.contentSize.height - scrollView.frame.size.height) {
print("bottom reached")
// not working
}
}
@objc func handleRefreshControl(sender: UIRefreshControl) {
sender.endRefreshing()
viewModel.refresh()
}
}
}
struct SeeAllView: View {
@ObservedObject var seeAllViewModel: SeeAllViewModel
var body: some View {
VStack {
GeometryReader { geometry in
CustomScrollView(width: geometry.size.width, height: geometry.size.height, viewModel: self.seeAllViewModel) {
SeeAllListView(seeAllViewModel: self.seeAllViewModel)
}
}
}
}
}
您没有在 makeUIView
中设置委托。以下更改将修复您的代码 - 我已经删除了一些缺少的依赖项以编译代码。它在 Playground 中按预期工作。
import SwiftUI
import PlaygroundSupport
struct CustomScrollView<Content: View> : UIViewRepresentable {
var width : CGFloat
var height : CGFloat
let content: () -> Content
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UIScrollView {
let control = UIScrollView()
control.refreshControl = UIRefreshControl()
control.refreshControl?.addTarget(context.coordinator, action: #selector(Coordinator.handleRefreshControl), for: .valueChanged)
control.delegate = context.coordinator
let childView = UIHostingController(rootView: content())
childView.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
control.addSubview(childView.view)
return control
}
func updateUIView(_ uiView: UIScrollView, context: Context) { }
class Coordinator: NSObject, UIScrollViewDelegate {
var control: CustomScrollView<Content>
init(_ control: CustomScrollView) {
self.control = control
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.y + 1) >= (scrollView.contentSize.height - scrollView.frame.size.height) {
print("bottom reached")
// not working
}
}
@objc func handleRefreshControl(sender: UIRefreshControl) {
sender.endRefreshing()
}
}
}
struct SeeAllView: View {
var body: some View {
VStack {
GeometryReader { geometry in
CustomScrollView(width: geometry.size.width, height: geometry.size.height) {
List {
Text("1")
Text("2")
Text("3")
}
}
}
}
}
}
PlaygroundPage.current.setLiveView(SeeAllView())