✨ New beta is out! Features a new and improved API for SwiftUI Try it now.
Features
Parchment lets you page between view controllers while showing any type of generic indicator that scrolls along with the content. Here are some benefits of using Parchment:
Highly customizable The menu items are built using
UICollectionView, which means you can display pretty much whatever you want. You can even subclass the layout to create completely custom behaviours.
Memory-efficient: Parchment only allocates view controllers when they’re needed, meaning if you have a lot of view controllers you don’t have to initialize them all up-front.
Infinite scrolling: Because view controllers are only allocated as you are scrolling, you can create data sources that are infinitely large. This is perfect for things like calendars.
Parchment is built around the PagingViewController class. You can initialize it with an array of view controllers and it will display menu items for each view controller using their title property.
let firstViewController = UIViewController()
let secondViewController = UIViewController()
let pagingViewController = PagingViewController(viewControllers: [
firstViewController,
secondViewController
])
Initializing PagingViewController with an array of view controllers is fine in most cases, but if you have more than a few view controllers you probably don’t want to allocate them all up-front. If you’re going to display a fixed number of view controllers, you can setup your own data source by implementing PagingViewControllerDataSource:
Then you need to set the dataSource property and select the initial item:
let pagingViewController = PagingViewController()
pagingViewController.dataSource = self
pagingViewController.select(index: 0)
Using the data source means Parchment will only allocate view controllers for the currently selected item and any of its siblings. This is a lot more memory efficient than using PagingViewController(viewControllers:) if you have many view controllers.
Using PagingViewControllerDataSource means you need to know how many view controllers to display. If you’re creating something like a calendar, the number of view controllers can be infinitely large. In that case you can use the PagingViewControllerInfiniteDataSource protocol:
Then set the infiniteDataSource property and select the initial item:
let pagingViewController = PagingViewController()
pagingViewController.infiniteDataSource = self
pagingViewController.select(pagingItem: Item(index: 0))
This pattern is very similar to the
UIPageViewControllerDataSource
protocol. The main difference is that instead of returning view controllers directly, you have to return an instance conforming to the PagingItem protocol. Parchment will recursively call these methods for the selected PagingItem until the available space is filled up.
override func viewDidLoad() {
super.viewDidLoad()
if let first = pagingViewController.children.first as? PagingItem {
pagingViewController.select(pagingItem: first)
}
}
Or if you have set the dateSource property, you can select items based on their index:
func select(index: Int, animated: Bool = false)
Reloading data
You can reload data using this method:
func reloadData()
This will keep the previously selected item if it’s still part of the
updated data. If not, it will select the first item in the list. It
will also reload the view controllers displayed in the page view
controller. If you only want to reload the menu items, you can use
this method:
func reloadMenu()
Calling reloadData() will not work when using
PagingViewControllerInfiniteDataSource, as we then need to know what
the initial item should be. In that case you should use this method:
func reloadData(around: PagingItem)
This will mark the given paging item as selected and generate new items around it.
Delegate
Parchment provides delegate methods for every step of the transition process through the PagingViewControllerDelegate protocol.
By default, the size of the menu items is controlled by the menuItemSize property. If you need to control width of each menu item individually you can use the PagingControllerSizeDelegate protocol:
Then set the sizeDelegate on the PagingViewController:
let pagingViewController = PagingViewController()
pagingViewController.sizeDelegate = self
Customization
Parchment is built to be very flexible. The menu items are displayed using UICollectionView, so they can display pretty much whatever you want. If you need any further customization you can even subclass the collection view layout. All customization is handled by the properties listed below.
Custom cells
To use custom cells you need to subclass PagingCell and register the cell type for a given PagingItem:
let pagingViewController = PagingViewController()
pagingViewController.register(CalendarPagingCell.self, for: CalendarItem.self)
Parchment will then dequeue your custom cell when you return the given PagingItem in your data source. You can register multiple cell types for different PagingItems.
Properties
All customization properties are set on PagingViewController:
The size of the menu items. When using sizeDelegate the width will be ignored.
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)
}
Default: .sizeToFit(minWidth: 150, height: 40)
menuItemSpacing
The spacing between the menu items.
Default: 0
menuItemLabelSpacing
The horizontal constraints of menu item label.
Default: 20
menuInsets
The insets around all of the menu items.
Default: 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: .default
menuTransition
Determine the transition behaviour of menu items while scrolling the content.
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
}
Default: .scrollAlongside
menuInteraction
Determine how users can interact with the menu items.
enum PagingMenuInteraction {
case scrolling
case swipe
case none
}
Default: .scrolling
menuLayoutClass
The class type for collection view layout. Override this if you want to use your own subclass of the layout. Setting this property will initialize the new layout type and update the collection view.
Default: PagingCollectionViewLayout.Type
selectedScrollPosition
Determine how the selected menu item should be aligned when it is selected. Effectively the same as the 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
}
Default: .preferCentered
indicatorOptions
Add an indicator view to the selected menu item. The indicator width will be equal to the selected menu items width. Insets only apply horizontally.
enum PagingIndicatorOptions {
case hidden
case visible(
height: CGFloat,
zIndex: Int,
spacing: UIEdgeInsets,
insets: UIEdgeInsets)
}
Getting Started | Customization | Installation
✨ New beta is out! Features a new and improved API for SwiftUI Try it now.
Features
Parchment lets you page between view controllers while showing any type of generic indicator that scrolls along with the content. Here are some benefits of using Parchment:
Highly customizable
The menu items are built using
UICollectionView, which means you can display pretty much whatever you want. You can even subclass the layout to create completely custom behaviours.Memory-efficient:
Parchment only allocates view controllers when they’re needed, meaning if you have a lot of view controllers you don’t have to initialize them all up-front.
Infinite scrolling:
Because view controllers are only allocated as you are scrolling, you can create data sources that are infinitely large. This is perfect for things like calendars.
Table of contents
Getting started
Basic usage
Parchment is built around the
PagingViewControllerclass. You can initialize it with an array of view controllers and it will display menu items for each view controller using theirtitleproperty.See more: Basic usage
Data source
Initializing
PagingViewControllerwith an array of view controllers is fine in most cases, but if you have more than a few view controllers you probably don’t want to allocate them all up-front. If you’re going to display a fixed number of view controllers, you can setup your own data source by implementingPagingViewControllerDataSource:Then you need to set the
dataSourceproperty and select the initial item:Using the data source means Parchment will only allocate view controllers for the currently selected item and any of its siblings. This is a lot more memory efficient than using
PagingViewController(viewControllers:)if you have many view controllers.Read more: Using the data source
Infinite data source
Using
PagingViewControllerDataSourcemeans you need to know how many view controllers to display. If you’re creating something like a calendar, the number of view controllers can be infinitely large. In that case you can use thePagingViewControllerInfiniteDataSourceprotocol:Then set the
infiniteDataSourceproperty and select the initial item:This pattern is very similar to the UIPageViewControllerDataSource protocol. The main difference is that instead of returning view controllers directly, you have to return an instance conforming to the
PagingItemprotocol. Parchment will recursively call these methods for the selectedPagingItemuntil the available space is filled up.Read more: Using the infinite data source
Selecting items
You can select items programatically using:
Let’s say you want to select the first item:
Or if you have set the
dateSourceproperty, you can select items based on their index:Reloading data
You can reload data using this method:
This will keep the previously selected item if it’s still part of the updated data. If not, it will select the first item in the list. It will also reload the view controllers displayed in the page view controller. If you only want to reload the menu items, you can use this method:
Calling
reloadData()will not work when usingPagingViewControllerInfiniteDataSource, as we then need to know what the initial item should be. In that case you should use this method:This will mark the given paging item as selected and generate new items around it.
Delegate
Parchment provides delegate methods for every step of the transition process through the
PagingViewControllerDelegateprotocol.Size delegate
By default, the size of the menu items is controlled by the
menuItemSizeproperty. If you need to control width of each menu item individually you can use thePagingControllerSizeDelegateprotocol:Then set the
sizeDelegateon thePagingViewController:Customization
Parchment is built to be very flexible. The menu items are displayed using UICollectionView, so they can display pretty much whatever you want. If you need any further customization you can even subclass the collection view layout. All customization is handled by the properties listed below.
Custom cells
To use custom cells you need to subclass
PagingCelland register the cell type for a givenPagingItem:Parchment will then dequeue your custom cell when you return the given
PagingItemin your data source. You can register multiple cell types for differentPagingItems.Properties
All customization properties are set on
PagingViewController:menuItemSizeThe size of the menu items. When using
sizeDelegatethe width will be ignored.Default:
.sizeToFit(minWidth: 150, height: 40)menuItemSpacingThe spacing between the menu items.
Default:
0menuItemLabelSpacingThe horizontal constraints of menu item label.
Default:
20menuInsetsThe insets around all of the menu items.
Default:
UIEdgeInsets()menuHorizontalAlignmentDefault:
.defaultmenuTransitionDetermine the transition behaviour of menu items while scrolling the content.
Default:
.scrollAlongsidemenuInteractionDetermine how users can interact with the menu items.
Default:
.scrollingmenuLayoutClassThe class type for collection view layout. Override this if you want to use your own subclass of the layout. Setting this property will initialize the new layout type and update the collection view.
Default:
PagingCollectionViewLayout.TypeselectedScrollPositionDetermine how the selected menu item should be aligned when it is selected. Effectively the same as the
UICollectionViewScrollPosition.Default:
.preferCenteredindicatorOptionsAdd an indicator view to the selected menu item. The indicator width will be equal to the selected menu items width. Insets only apply horizontally.
Default:
indicatorClassThe class type for the indicator view. Override this if you want your use your own subclass of
PagingIndicatorView.Default:
PagingIndicatorView.selfindicatorColorThe background color for the indicator view.
Default:
UIColor(red: 3/255, green: 125/255, blue: 233/255, alpha: 1)borderOptionsAdd a border at the bottom of the menu items. The border will be as wide as all the menu items. Insets only apply horizontally.
Default:
borderClassThe class type for the border view. Override this if you want your use your own subclass of
PagingBorderView.Default:
PagingBorderView.selfborderColorThe background color for the border view.
Default:
UIColor(white: 0.9, alpha: 1)includeSafeAreaInsetsUpdates the content inset for the menu items based on the
.safeAreaInsetsproperty.Default:
truefontThe font used for title label on the menu items.
Default:
UIFont.systemFont(ofSize: 15, weight: UIFont.Weight.medium)selectedFontThe font used for title label on the currently selected menu item.
Default:
UIFont.systemFont(ofSize: 15, weight: UIFont.Weight.medium)textColorThe color of the title label on the menu items.
Default:
UIColor.blackselectedTextColorThe text color for the currently selected menu item.
Default:
UIColor(red: 3/255, green: 125/255, blue: 233/255, alpha: 1)backgroundColorThe background color for the menu items.
Default:
UIColor.whiteselectedBackgroundColorThe background color for the selected menu item.
Default:
UIColor.clearmenuBackgroundColorThe background color for the view behind the menu items.
Default:
UIColor.whiteInstallation
Parchment will be compatible with the lastest public release of Swift.
Requirements
CocoaPods
Parchment is available through CocoaPods. To install it, add the following to your
Podfile:Swift Package Manager
Parchment is available through Swift Package Manager. Add Parchment as a dependency to your
Package.swift:Carthage
Parchment also supports Carthage. To install it, add the following to your
Cartfile:See this guide for more details on using Carthage.
Changelog
This can be found in the CHANGELOG file.
Licence
Parchment is released under the MIT license. See LICENSE for details.