开始使用 | 自定义 | 安装


Cities Example Unsplash Example Calendar Example

特性

Parchment 允许您在视图控制器之间分页,同时显示随内容滚动的任何类型的通用指示器。以下是使用 Parchment 的一些好处

目录

开始使用

基本用法

Parchment 是围绕 PagingViewController 类构建的。您可以使用视图控制器数组初始化它,它将使用每个视图控制器的 title 属性为每个视图控制器显示菜单项。

let firstViewController = UIViewController()
let secondViewController = UIViewController()

let pagingViewController = PagingViewController(viewControllers: [
  firstViewController,
  secondViewController
])

了解更多: 基本用法

数据源

在大多数情况下,使用视图控制器数组初始化 PagingViewController 都可以,但是如果您有多个视图控制器,您可能不想预先分配它们。如果您要显示固定数量的视图控制器,您可以通过实现 PagingViewControllerDataSource 来设置您自己的数据源

extension ViewController: PagingViewControllerDataSource {
    func numberOfViewControllers(in pagingViewController: PagingViewController) -> Int {
        return 10
    }

    func pagingViewController(_ pagingViewController: PagingViewController, viewControllerAt index: Int) -> UIViewController {
        return ChildViewController(index: index)
    }

    func pagingViewController(_: PagingViewController, pagingItemAt index: Int) -> PagingItem {
        return PagingTitleItem(title: "View \(index)", index: index)
    }
}

然后您需要设置 dataSource 属性并选择初始项目

let pagingViewController = PagingViewController()
pagingViewController.dataSource = self
pagingViewController.select(index: 0)

使用数据源意味着 Parchment 将仅为当前选定的项目及其任何同级项目分配视图控制器。如果您有很多视图控制器,那么这比使用 PagingViewController(viewControllers:) 更节省内存。

阅读更多: 使用数据源

无限数据源

使用 PagingViewControllerDataSource 意味着您需要知道要显示多少个视图控制器。如果您正在创建类似 日历 的东西,则视图控制器的数量可以是无限大的。在这种情况下,您可以使用 PagingViewControllerInfiniteDataSource 协议

extension ViewController: PagingViewControllerInfiniteDataSource {
    func pagingViewController(_: PagingViewController, viewControllerFor pagingItem: PagingItem) -> UIViewController {
        return ItemViewController(item: pagingItem)
    }

    func pagingViewController(_: PagingViewController, itemBefore pagingItem: PagingItem) -> PagingItem? {
        guard let item = pagingItem as? Item else { return nil }
        return Item(index: item.index - 1)
    }

    func pagingViewController(_ : PagingViewController, itemAfter pagingItem: PagingItem) -> PagingItem? {
        guard let item = pagingItem as? Item else { return nil }
        return Item(index: item.index + 1)
    }
}

然后设置 infiniteDataSource 属性并选择初始项目

let pagingViewController = PagingViewController()
pagingViewController.infiniteDataSource = self
pagingViewController.select(pagingItem: Item(index: 0))

此模式与 UIPageViewControllerDataSource 协议非常相似。主要区别在于,您不必直接返回视图控制器,而是必须返回一个符合 PagingItem 协议的实例。Parchment 将为选定的 PagingItem 递归调用这些方法,直到可用空间被填满。

阅读更多: 使用无限数据源

选择项目

您可以使用编程方式选择项目

func select(pagingItem: PagingItem, animated: Bool = false)

假设您要选择第一个项目

override func viewDidLoad() {
  super.viewDidLoad()
  if let first = pagingViewController.children.first as? PagingItem {
    pagingViewController.select(pagingItem: first)
  }
}

或者,如果您已设置 dateSource 属性,则可以根据其索引选择项目

func select(index: Int, animated: Bool = false)

重新加载数据

您可以使用此方法重新加载数据

func reloadData()

如果先前选择的项目仍然是更新数据的一部分,这将保留先前选择的项目。如果不是,它将选择列表中的第一个项目。它还将重新加载页面视图控制器中显示的视图控制器。如果您只想重新加载菜单项,则可以使用此方法

func reloadMenu()

当使用 PagingViewControllerInfiniteDataSource 时,调用 reloadData() 将不起作用,因为那时我们需要知道初始项目应该是什么。在这种情况下,您应该使用此方法

func reloadData(around: PagingItem)

这将标记给定的分页项目为已选中,并在其周围生成新项目。

委托

Parchment 通过 PagingViewControllerDelegate 协议为过渡过程的每个步骤提供委托方法。

protocol PagingViewControllerDelegate: class {

    func pagingViewController(
        _: PagingViewController,
        isScrollingFromItem currentPagingItem: PagingItem,
        toItem upcomingPagingItem: PagingItem?,
        startingViewController: UIViewController,
        destinationViewController: UIViewController?,
        progress: CGFloat)

    func pagingViewController(
        _: PagingViewController,
        willScrollToItem pagingItem: PagingItem,
        startingViewController: UIViewController,
        destinationViewController: UIViewController)

    func pagingViewController(
        _ pagingViewController: PagingViewController,
        didScrollToItem pagingItem: PagingItem,
        startingViewController: UIViewController?,
        destinationViewController: UIViewController,
        transitionSuccessful: Bool)

    func pagingViewController(
        _ pagingViewController: PagingViewController,
        didSelectItem pagingItem: PagingItem)
}

尺寸委托

默认情况下,菜单项的大小由 menuItemSize 属性控制。如果您需要单独控制每个菜单项的宽度,则可以使用 PagingControllerSizeDelegate 协议

protocol PagingViewControllerSizeDelegate: class {
    func pagingViewController(
        _: PagingViewController,
        widthForPagingItem pagingItem: PagingItem,
        isSelected: Bool) -> CGFloat
}

然后在 PagingViewController 上设置 sizeDelegate

let pagingViewController = PagingViewController()
pagingViewController.sizeDelegate = self

自定义

Parchment 的构建非常灵活。菜单项是使用 UICollectionView 显示的,因此它们几乎可以显示任何您想要的内容。如果您需要任何进一步的自定义,您甚至可以子类化集合视图布局。所有自定义都由下面列出的属性处理。

自定义单元格

要使用自定义单元格,您需要子类化 PagingCell 并为给定的 PagingItem 注册单元格类型

let pagingViewController = PagingViewController()
pagingViewController.register(CalendarPagingCell.self, for: CalendarItem.self)

然后,当您在数据源中返回给定的 PagingItem 时,Parchment 将取消排队您的自定义单元格。您可以为不同的 PagingItem 注册多种单元格类型。

属性

所有自定义属性都在 PagingViewController 上设置

let pagingViewController = PagingViewController()
pagingViewController.menuItemSize = .fixed(width: 40, height: 40)
pagingViewController.menuItemSpacing = 10

menuItemSize

菜单项的大小。当使用 sizeDelegate 时,宽度将被忽略。

enum PagingMenuItemSize {
  case fixed(width: CGFloat, height: CGFloat)

  // Automatically calculate the size of the menu items based on the
  // cells intrinsic content size. Try to come up with an estimated
  // width that's similar to the expected width of the cells.
  case selfSizing(estimatedWidth: CGFloat, height: CGFloat)

  // Tries to fit all menu items inside the bounds of the screen.
  // If the items can't fit, the items will scroll as normal and
  // set the menu items width to `minWidth`.
  case sizeToFit(minWidth: CGFloat, height: CGFloat)
}

默认值:.sizeToFit(minWidth: 150, height: 40)

menuItemSpacing

菜单项之间的间距。

默认值:0

menuItemLabelSpacing

菜单项标签的水平约束。

默认值:20

menuInsets

菜单项周围的插距。

默认值:UIEdgeInsets()

menuHorizontalAlignment

enum PagingMenuHorizontalAlignment {
  case `default`

  // Allows all paging items to be centered within the paging menu
  // when PagingMenuItemSize is .fixed and the sum of the widths
  // of all the paging items are less than the paging menu
  case center
}

默认值:.default

menuTransition

确定滚动内容时菜单项的过渡行为。

enum PagingMenuTransition {
  // Update scroll offset based on how much the content has
  // scrolled. Makes the menu items transition smoothly as you scroll.
  case scrollAlongside

  // Animate the menu item position after a transition has completed.
  case animateAfter
}

默认值:.scrollAlongside

menuInteraction

确定用户如何与菜单项交互。

enum PagingMenuInteraction {
  case scrolling
  case swipe
  case none
}

默认值:.scrolling

menuLayoutClass

集合视图布局的类类型。如果您想使用您自己的布局子类,请覆盖此项。设置此属性将初始化新的布局类型并更新集合视图。

默认值:PagingCollectionViewLayout.Type

selectedScrollPosition

确定选定的菜单项在被选中时应如何对齐。实际上与 UICollectionViewScrollPosition 相同。

enum PagingSelectedScrollPosition {
  case left
  case right

  // Centers the selected menu item where possible. If the item is
  // to the far left or right, it will not update the scroll position.
  // Effectivly the same as .centeredHorizontally on UIScrollView.
  case preferCentered
}

默认值:.preferCentered

indicatorOptions

向选定的菜单项添加指示器视图。指示器宽度将等于选定的菜单项宽度。插距仅水平应用。

enum PagingIndicatorOptions {
  case hidden
  case visible(
    height: CGFloat,
    zIndex: Int,
    spacing: UIEdgeInsets,
    insets: UIEdgeInsets)
}

默认

.visible(
  height: 4,
  zIndex: Int.max,
  spacing: UIEdgeInsets.zero,
  insets: UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 8))

indicatorClass

指示器视图的类类型。如果您想使用您自己的 PagingIndicatorView 子类,请覆盖此项。

默认值:PagingIndicatorView.self

indicatorColor

指示器视图的背景颜色。

默认值:UIColor(red: 3/255, green: 125/255, blue: 233/255, alpha: 1)

borderOptions

在菜单项底部添加边框。边框将与所有菜单项一样宽。插距仅水平应用。

enum PagingBorderOptions {
  case hidden
  case visible(
    height: CGFloat,
    zIndex: Int,
    insets: UIEdgeInsets)
}

默认

.visible(
  height: 1,
  zIndex: Int.max - 1,
  insets: UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 8))

borderClass

边框视图的类类型。如果您想使用您自己的 PagingBorderView 子类,请覆盖此项。

默认值:PagingBorderView.self

borderColor

边框视图的背景颜色。

默认值:UIColor(white: 0.9, alpha: 1)

includeSafeAreaInsets

根据 .safeAreaInsets 属性更新菜单项的内容插距。

默认值:true

font

用于菜单项上标题标签的字体。

默认值:UIFont.systemFont(ofSize: 15, weight: UIFont.Weight.medium)

selectedFont

用于当前选定的菜单项上标题标签的字体。

默认值:UIFont.systemFont(ofSize: 15, weight: UIFont.Weight.medium)

textColor

菜单项上标题标签的颜色。

默认值:UIColor.black

selectedTextColor

当前选定的菜单项的文本颜色。

默认值:UIColor(red: 3/255, green: 125/255, blue: 233/255, alpha: 1)

backgroundColor

菜单项的背景颜色。

默认值:UIColor.white

selectedBackgroundColor

选定的菜单项的背景颜色。

默认值:UIColor.clear

menuBackgroundColor

菜单项后面的视图的背景颜色。

默认值:UIColor.white

安装

Parchment 将与 Swift 的最新公共版本兼容。

要求

CocoaPods

Parchment 可通过 CocoaPods 获得。要安装它,请将以下内容添加到您的 Podfile

pod 'Parchment', '~> 3.2'

Swift Package Manager

Parchment 可通过 Swift Package Manager 获得。将 Parchment 作为依赖项添加到您的 Package.swift

.package(url: "https://github.com/rechsteiner/Parchment", from: "3.2.0")

Carthage

Parchment 也支持 Carthage。要安装它,请将以下内容添加到您的 Cartfile

github "rechsteiner/Parchment" ~> 3.2

有关使用 Carthage 的更多详细信息,请参阅本指南

更新日志

这可以在 CHANGELOG 文件中找到。

许可证

Parchment 在 MIT 许可证下发布。有关详细信息,请参阅 LICENSE