SwiftUI: Как прокрутить список программно [решение]? - PullRequest
7 голосов
/ 25 марта 2020

Похоже, что в текущих инструментах / системе, только что выпущенных Xcode 11.4 / iOS 13.4, в List не будет встроенной поддержки SwiftUI для функции «прокрутка». Поэтому, даже если они, Apple, предоставят его в следующих основных выпущенных версиях, мне потребуется обратная поддержка для iOS 13.x.

Так как бы я сделал это в самых простых и легкий путь?

  • прокрутка списка до конца
  • прокрутка списка к началу
  • и другие

(мне не нравится полное заполнение UITableView инфраструктура в UIViewRepresentable/UIViewControllerRepresentable, как было предложено ранее для SO).

См. мой вариант решения ниже в ответе.

1 Ответ

7 голосов
/ 25 марта 2020

Вот упрощенный вариант подхода, который работает, выглядит уместно и занимает пару экранов кода. Протестировано с Xcode 11.2+ / iOS 13.2 +.

Демонстрация использования:

struct ContentView: View {
    private let scrollingProxy = ListScrollingProxy() // proxy helper

    var body: some View {
        VStack {
            HStack {
                Button(action: { self.scrollingProxy.scrollTo(.top) }) { // < here
                    Image(systemName: "arrow.up.to.line")
                      .padding(.horizontal)
                }
                Button(action: { self.scrollingProxy.scrollTo(.end) }) { // << here
                    Image(systemName: "arrow.down.to.line")
                      .padding(.horizontal)
                }
            }
            Divider()
            List {
                ForEach(0 ..< 200) { i in
                    Text("Item \(i)")
                        .background(
                           ListScrollingHelper(proxy: self.scrollingProxy) // injection
                        )
                }
            }
        }
    }
}

demo

Решение :

Представление Light View, внедряемое в List, дает доступ к иерархии представлений UIKit. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Простой прокси-сервер, который находит UIScrollView (необходимо сделать один раз), а затем перенаправляет необходимые действия «прокрутки» к этому сохраненному scrollview

class ListScrollingProxy {
    enum Action {
        case end
        case top
        case point(point: CGPoint)     // << bonus !!
    }

    private var scrollView: UIScrollView?

    func catchScrollView(for view: UIView) {
        if nil == scrollView {
            scrollView = view.enclosingScrollView()
        }
    }

    func scrollTo(_ action: Action) {
        if let scroller = scrollView {
            var rect = CGRect(origin: .zero, size: CGSize(width: 1, height: 1))
            switch action {
                case .end:
                    rect.origin.y = scroller.contentSize.height +
                        scroller.contentInset.bottom + scroller.contentInset.top - 1
                case .point(let point):
                    rect.origin.y = point.y
                default: {
                    // default goes to top
                }()
            }
            scroller.scrollRectToVisible(rect, animated: true)
        }
    }
}

extension UIView {
    func enclosingScrollView() -> UIScrollView? {
        var next: UIView? = self
        repeat {
            next = next?.superview
            if let scrollview = next as? UIScrollView {
                return scrollview
            }
        } while next != nil
        return nil
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...