有什么办法可以在SwiftUI中制作页面滚动式ScrollView吗?

Bra*_*rad 2 uiscrollview swiftui

我一直在浏览每个Beta版本的文档,但没有找到制作传统的分页ScrollView的方法。我对AppKit不熟悉,所以我想知道SwiftUI中是否不存在此控件,因为它主要是UIKit构造。无论如何,有没有人举这个例子,或者有人可以告诉我这绝对是不可能的,所以我可以停止寻找自己的作品了吗?

小智 11

您现在可以使用 TabView 并将 .tabViewStyle 设置为 PageTabViewStyle()

TabView {
            View1()
            View2()
            View3()
        }
        .tabViewStyle(PageTabViewStyle())
Run Code Online (Sandbox Code Playgroud)


Jun*_*ang 8

苹果的官方教程以这个为例。我发现它很容易遵循并且适合我的情况。我真的建议您检查一下并尝试了解如何与 UIKit 交互。由于 SwiftUI 还很年轻,因此目前不会涵盖 UIKit 中的所有功能。与 UIKit 接口应该可以满足大多数(如果不是全部)需求。

https://developer.apple.com/tutorials/swiftui/interface-with-uikit

  • 该教程的问题在于它仅涵盖使用页面视图控制器的非常基本的功能。当您开始添加添加或删除页面等功能时,教程中提供的代码很快就会过时。 (4认同)

ars*_*ius 7

从Beta 3开始,没有用于页面调度的本机SwiftUI API。我已提出反馈,建议您也这样做。他们将ScrollViewAPI从Beta 2 更改为Beta 3,看到进一步的更新我不会感到惊讶。

现在可以包装a UIScrollView以便提供此功能。不幸的是,您必须将UIScrollView包装在中UIViewController,进一步包装UIViewControllerRepresentable以支持SwiftUI内容。

要点在这里

class UIScrollViewViewController: UIViewController {

    lazy var scrollView: UIScrollView = {
        let v = UIScrollView()
        v.isPagingEnabled = true
        return v
    }()

    var hostingController: UIHostingController<AnyView> = UIHostingController(rootView: AnyView(EmptyView()))

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(self.scrollView)
        self.pinEdges(of: self.scrollView, to: self.view)

        self.hostingController.willMove(toParent: self)
        self.scrollView.addSubview(self.hostingController.view)
        self.pinEdges(of: self.hostingController.view, to: self.scrollView)
        self.hostingController.didMove(toParent: self)

    }

    func pinEdges(of viewA: UIView, to viewB: UIView) {
        viewA.translatesAutoresizingMaskIntoConstraints = false
        viewB.addConstraints([
            viewA.leadingAnchor.constraint(equalTo: viewB.leadingAnchor),
            viewA.trailingAnchor.constraint(equalTo: viewB.trailingAnchor),
            viewA.topAnchor.constraint(equalTo: viewB.topAnchor),
            viewA.bottomAnchor.constraint(equalTo: viewB.bottomAnchor),
        ])
    }

}

struct UIScrollViewWrapper<Content: View>: UIViewControllerRepresentable {

    var content: () -> Content

    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }

    func makeUIViewController(context: Context) -> UIScrollViewViewController {
        let vc = UIScrollViewViewController()
        vc.hostingController.rootView = AnyView(self.content())
        return vc
    }

    func updateUIViewController(_ viewController: UIScrollViewViewController, context: Context) {
        viewController.hostingController.rootView = AnyView(self.content())
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用它:

    var body: some View {
        GeometryReader { proxy in
            UIScrollViewWrapper {
                VStack {
                    ForEach(0..<1000) { _ in
                        Text("Hello world")
                    }
                }
                .frame(width: proxy.size.width) // This ensures the content uses the available width, otherwise it will be pinned to the left
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 是否可以滚动到某个位置?我尝试了scrollView.contentOffset = ...但它不起作用。如何实现滚动视图滚动到某个位置? (2认同)

Анд*_*ній 6

您可以使用这样的自定义修饰符:

struct ScrollViewPagingModifier: ViewModifier {
    func body(content: Content) -> some View {
        content
            .onAppear {
                UIScrollView.appearance().isPagingEnabled = true
            }
            .onDisappear {
                UIScrollView.appearance().isPagingEnabled = false
            }
    }
}

extension ScrollView {
    func isPagingEnabled() -> some View {
        modifier(ScrollViewPagingModifier())
    }
}
Run Code Online (Sandbox Code Playgroud)


Jef*_* C. 6

iOS 17 中正式支持分页ScrollView,并在 WWDC 2023 上引入。

您可以使用以 a 作为参数的newscrollTargetBehavior修饰符(文档ScrollTargetBehavior) 。出于分页目的,请传递它.paging

他们在“超越滚动视图”会话中详细介绍了其工作原理。


McG*_*ire 5

不确定这是否对您的问题有帮助,但目前,当 Apple 正在努力在 SwiftUI 中添加分页视图时,我编写了一个实用程序库,在使用UIPageViewController隐藏的引擎盖时为您提供 SwiftUI 感觉。

你可以这样使用它:

Pages {
    Text("Page 1")
    Text("Page 2")
    Text("Page 3")
    Text("Page 4")
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您的应用程序中有一个模型列表,您可以像这样使用它:

struct Car {
    var model: String
}

let cars = [Car(model: "Ford"), Car(model: "Ferrari")]

ModelPages(cars) { index, car in
    Text("The \(index) car is a \(car.model)")
        .padding(50)
        .foregroundColor(.white)
        .background(Color.blue)
        .cornerRadius(10)
}
Run Code Online (Sandbox Code Playgroud)