首页 > 解决方案 > 如何在 SwiftUI 中制作动态 PageViewController?

问题描述

有人知道如何在 SwiftUI、iOS 14 中制作动态 pageView 控制器吗?显示与日期相关的页面的东西,以便人们可以向左或向右滚动以查看过去、现在和未来的数据。

struct DatePg: View
{
    let date: Date
    
    var body: some View {
        Text(date.description)
    }
}

有一个新的 API 允许使用 TabView 和 viewModifier 创建一个 PageViewController。但我见过的唯一例子是静态的。这是一个静态 PageView 的示例。

import SwiftUI

struct SwiftUIPageView: View
{
    @State private var selection = 0
    
    var body: some View {
        TabView(selection: $selection) {
            Text("Hello")
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .background(Color.blue)
                .tag(0)
            Text("World")
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .background(Color.red)
                .tag(1)
        }.tabViewStyle(PageTabViewStyle())
        .indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
    }
}

已经有一些使用 UIHostingController 的东西,但是通过 UIKit 对象传递 NSManageObjectContext 正在引起问题。

这就是我目前所处的位置。还是行不通。

import SwiftUI

@main struct PagerApp: App
{
    var body: some Scene {
        WindowGroup { DatePageView() }
    }
}

struct DatePageView: View
{
    @StateObject var dateData = DateData(present: Date())
    @State var index: Int = 1

    var body: some View {
        TabView(selection: $index) {
            ForEach(dateData.dates, id: \.self) { date in
                Text(date.description)
                    .onAppear { dateData.current(date: date) }
                    .tag(dateData.tag(date: date))
            }
        }
        .tabViewStyle(PageTabViewStyle())
        .indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
    }
}

class DateData: ObservableObject
{
    @Published var dates: [Date]
    
    init(present: Date) {
        let past = present.previousDay()
        let future = present.nextDay()
        self.dates = [past, present, future]
    }
    
    func current(date: Date) {
        //center around
        guard let i = dates.firstIndex(of: date) else { fatalError() }
        self.dates = [ dates[i].previousDay(), dates[i], dates[i].nextDay() ]
        print("make item at \(i) present")
    }
    
    func tag(date: Date) -> Int {
        guard let i = dates.firstIndex(of: date) else { fatalError() }
        return i
    }
}

标签: swiftui

解决方案


您可以使用数组和动态创建视图ForEach

下面是一个使用字符串数组的示例:

// See edited section

您可以在 View 初始化程序中传递所需的项目

编辑:
这是每次到达最后一个页面时添加新页面的示例:

struct SwiftUIPageView: View
{
    @State private var selection = "0"
    
    @State var items: [String] = ["0", "1", "2", "3"]
    
    var body: some View {
        TabView(selection: $selection) {
            ForEach(items, id: \.self) { item in
                Text(item)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .background(Color.red)
                    .tag(item)
            }
        }.tabViewStyle(PageTabViewStyle())
        .indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
        .onChange(of: selection, perform: { value in
            if Int(value) == (self.items.count - 1) {
                self.items.append("\(self.items.count)")
            }
        })
        .id(items)
    }
}

最后id(items)一点很重要,因为它会在数组更改时强制视图重新加载。


推荐阅读