SwiftUI обнаруживает дно при прокрутке - PullRequest
0 голосов
/ 21 июня 2020

Я реализовал свой Custom UIScrollView в SwiftUI, используя UIViewRepresentable, и я хочу определить нижнюю часть моего списка, чтобы я мог загрузить следующий пакет данных. Я нашел некоторые ответы, но они, похоже, не работают в моем UIViewRepresentable.

Я реализовал это в своем Координаторе, но ничего не происходит, когда я достигаю дна.

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if (scrollView.contentOffset.y + 1) >= (scrollView.contentSize.height - scrollView.frame.size.height) {
        print("bottom reached")
        // not working
    }
}

Может проблема в моем Swift View, а не в 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)
                    }
                }
            }
        }
    }

1 Ответ

1 голос
/ 21 июня 2020

Вы не устанавливаете делегата в 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())
...