ElegantPages

Platforms License: MIT

ElegantPages 是一个使用 SwiftUI 编写的高效且可定制的全屏页面视图。


简介

ElegantPages 包含两种类型的组件,ElegantPagesViewElegantListView

为了更简单的使用,推荐使用 ElegantPagesView,因为它会立即加载所有页面视图。

为了更复杂的使用,推荐使用 ElegantListView,因为它会按需加载页面视图(了解更多)。

这两个视图的优点在于它们的工作方式与分页组件应有的方式一致。 在 SwiftUI 中经常出现的一个错误是,ScrollViewList 或任何 Gesture 几乎肯定会干扰视图中的其他手势。 然而,ElegantPages 修复了这个问题,即使嵌入了 Gestures,滚动分页组件也非常流畅。

基本用法

ElegantPagesView 组件可以通过 ElegantHPagesElegantVPages 来使用。

import ElegantPages

struct ElegantVPagesExample: View {

    let manager = ElegantPagesManager(startingPage: 1, pageTurnType: .earlyCutOffDefault)

    var body: some View {
        ElegantVPages(manager: manager) {
            CustomButtonView()
            CustomView()
            CustomListView()
        }
    }

}

ElegantListView 组件可以通过 ElegantHListElegantVList 来使用。

import ElegantPages

let listData = (1...40).map { _ in "Ideally, this should be more dynamic content to make the most use out of this list" }

struct ElegantVListExample: View {

    let manager = ElegantListManager(pageCount: vListData.count, pageTurnType: .earlyCutOffDefault)
    
    var body: some View {
        ElegantVList(manager: manager,
                     pageTurnType: .earlyCutOffDefault) { page in 
            ExampleView(page: page).erased
        }
    }

}

struct ExampleView: View {

    let page: Int

    var body: some View {
        VStack {
            Text("Page \(page)")
                .font(.largeTitle)
            Text(listData[page])
                .font(.title)
        }
        .padding()
    }
    
}

工作原理

ElegantPagesView 非常简单。 它使用 函数构建器 来收集页面视图,并将它们放入 HStackVStack 中,具体取决于所选的 ElegantPages 视图类型。 因此,所有视图都会立即创建。

ElegantListView 非常有趣。 为了获得更大的灵活性,它使用 @ViewBuilder 来获取任何给定页面的视图 (它是 ElegantVList 声明末尾的闭包)。 首次初始化时,它最多调用此闭包 3 次,以获取起始页面的视图。 这些视图用于初始化最多包含 3 个 UIHostingControllers 的数组,它们的 rootViews 设置为 UIViewController 中的特定原点。 关键在于,在任何给定时刻,最多只有 3 个页面被加载。 当用户滚动到下一页时,旧页面将被删除,新页面将被插入;视图本身会随着它们的起始位置随着翻页而改变而被调整。 这可以降低整体内存使用率,并使滚动速度极快。 如果您有兴趣,可以 偷看一下

自定义

任何 ElegantPages 组件的以下方面都可以自定义

pageTurnType:确定是提前滚动到下一页,还是直到用户松开拖动才滚动

public enum PageTurnType {

    case regular(pageTurnDelta: CGFloat)
    case earlyCutoff(config: EarlyCutOffConfiguration)

}

public struct EarlyCutOffConfiguration {

    public let scrollResistanceCutOff: CGFloat
    public let pageTurnCutOff: CGFloat
    public let pageTurnAnimation: Animation
    
}

常规翻页仅在用户结束拖动后翻页。

当用户在屏幕上拖动一定距离时,提前截止翻页会翻页。

如果 scrollResistanceCutOff 不清楚,这里有一个例子。 假设我们有一个可以水平拖动的视图。 如果您向右拖动 80 像素,那么您可见的偏移量也是 80 像素。 您滚动的量等于可见偏移量。 但是,如果您有一个 40 像素的滚动阻力,在向右拖动 80 像素后,您只会看到该视图向右移动了 40 像素。 这就是它被称为阻力的原因。

###$ viewForPage:每次显示新页面时调用的数据源方法,用于请求新页面的视图。 仅适用于 ElegantList 组件

// Use as a function
ElegantVList(..., viewForPage: exampleView)

func exampleView(for page: Int) -> AnyView { ExampleView(...) }

// Use as a closure
ElegantHList(...) { page in ExampleView(...) }
    

onPageChanged:每当显示新页面时调用。 适用于所有 ElegantPages 组件。

ElegantVList(...)
    .onPageChanged(...)

ElegantHList(...)
    .onPageChanged(...)
    
ElegantHPages(...)
    .onPageChanged(...)
    
ElegantVPages(...)
    .onPageChanged(...)
    

frame:用于为 ElegantList 组件设置自定义高度或宽度

// You may want a smaller width for the VList. However, height for the VList will always be the screen height
ElegantVList(...)
    .frame(width: ...)

// You may want a smaller height for the HList. However, width for the HList will always be the screen width
ElegantHList(...)
    .frame(height: ...)
    

演示

GIF 中显示的演示可以在 ElegantCalendar 上查看。

对于更简单的演示,请查看 示例仓库

安装

可以使用 Swift Package Manager 获取 ElegantPages

使用 Xcode 11,转到 File -> Swift Packages -> Add Package Dependency 并输入 https://github.com/ThasianX/ElegantPages

如果您正在使用 Package.swift,您也可以轻松地将 ElegantPages 添加为依赖项。

let package = Package(
  name: "TestProject",
  dependencies: [
    .package(url: "https://github.com/ThasianX/ElegantPages", from: "1.4.0")
  ],
  targets: [
    .target(name: "TestProject", dependencies: ["ElegantPages"])
  ]
)

要求

贡献

如果您发现错误,或者想建议一项新功能或改进,如果您能先搜索问题跟踪器,那将非常棒。虽然我们不介意重复,但保持问题的唯一性有助于我们节省时间并整合精力。 如果您找不到您的问题,请随时提交新问题

许可证

本项目根据 MIT 许可证获得许可 - 有关详细信息,请参阅 LICENSE 文件