Skip to content

piemonte/BookLayout

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

10 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

BookLayout

BookLayout Demo

A custom UICollectionView layout that creates a realistic book page-turning user interface effect.

Overview

This project contains a standalone implementation of a book-like page layout for iOS. The layout creates a 3D page-turning effect where pages flip like a real book, with proper shadows and perspective transforms.

Components

BookLayout

A custom UICollectionViewFlowLayout that handles the 3D transforms and page positioning.

Features:

  • Realistic 3D page turning effect
  • Configurable layout styles (centered or equal margins)
  • Automatic page sizing based on collection view bounds
  • Smooth scrolling with paging enabled
  • Left and right pages with proper anchor points
  • Customizable edge margins

BookPageModel

A data model representing a single page in the book.

Page Types:

  • .invisible - Hidden pages (used for proper book opening)
  • .blank - Empty white pages
  • .cover - Book cover with title and subtitle
  • .content(String) - Page with text content
  • .colored(UIColor) - Page with custom background color
  • .decorative(iconNames: [String], iconSize: CGFloat, spacing: CGFloat) - Decorative pattern page with SF Symbols arranged in a staggered diagonal grid

BookPageCell

A UICollectionViewCell that displays individual pages with:

  • Rounded corners
  • Dynamic shadows based on page position
  • Support for different page types
  • Proper anchor point handling for left/right pages

BookViewController

A view controller that manages the book's pages using the BookLayout.

Properties:

  • bookLayout: BookLayout? - Access to the underlying BookLayout for configuration
  • collectionView: UICollectionView - The collection view displaying the pages
  • delegate: BookViewControllerDelegate? - Delegate for page selection events

Methods:

  • setPages(_ pages: [BookPageModel], animated: Bool) - Set the book's pages
  • openToPage(at index: Int, animated: Bool) - Open to a specific page

Usage

Basic Setup

// Create the book view controller
let bookViewController = BookViewController()
bookViewController.delegate = self

// Add it to your view hierarchy
addChild(bookViewController)
view.addSubview(bookViewController.view)
bookViewController.didMove(toParent: self)

// Create pages
let pages: [BookPageModel] = [
    BookPageModel(pageType: .invisible),
    BookPageModel(pageType: .invisible),
    BookPageModel(pageType: .cover, title: "The Hacker's Manifesto", subtitle: "A Demo"),
    BookPageModel(
        pageType: .decorative(
            iconNames: ["star.fill", "heart.fill", "circle.fill", "square.fill"],
            iconSize: 32,
            spacing: 16
        )
    ),
    BookPageModel(pageType: .content("Page 1"), subtitle: "First page content"),
    BookPageModel(pageType: .blank),
    BookPageModel(pageType: .colored(.systemBlue), title: "Blue Page"),
    BookPageModel(pageType: .blank)
]

// Set the pages
bookViewController.setPages(pages, animated: false)

// Open to a specific page
bookViewController.openToPage(at: 4, animated: true)

Layout Configuration

BookLayout supports two layout styles for positioning the book:

Classic Layout (Default)

bookViewController.bookLayout?.layoutStyle = .classic
bookViewController.bookLayout?.edgeMargin = 20  // Default is 20pt
  • Equal margins on both left and right sides
  • Spine positioned 20pt from the left edge
  • Right page edge positioned 20pt from the right edge
  • Ensures all content remains within screen bounds
  • Traditional, balanced book appearance

Centered Layout

bookViewController.bookLayout?.layoutStyle = .centered
  • Spine centered in the middle of the screen
  • Pages may extend beyond the screen edges
  • More immersive reading experience
  • Natural page-turning feel

Example:

let bookViewController = BookViewController()

// Use classic layout with equal margins (default)
bookViewController.bookLayout?.layoutStyle = .classic
bookViewController.bookLayout?.edgeMargin = 20  // Adjust as needed

// Or use centered layout
bookViewController.bookLayout?.layoutStyle = .centered

Page Turn Style

BookLayout supports two page turning styles that control how pages animate:

Elevated Style (Default)

bookViewController.bookLayout?.pageTurnStyle = .elevated
  • Pages rest with a subtle lift on the left edge
  • Creates a realistic book appearance where turned pages are slightly elevated
  • Smooth interpolation during page turns
  • More authentic physical book feel

Standard Style

bookViewController.bookLayout?.pageTurnStyle = .standard
  • Simple linear page turning animation
  • Pages lay completely flat when at rest
  • Cleaner, more minimalist appearance
  • Faster rendering with simpler transforms

Example:

let bookViewController = BookViewController()

// Configure layout and page turn style
bookViewController.bookLayout?.layoutStyle = .classic
bookViewController.bookLayout?.pageTurnStyle = .elevated  // Default

// Or use standard turning for a simpler effect
bookViewController.bookLayout?.pageTurnStyle = .standard

Understanding the Layout

The BookLayout works with a section-based collection view:

  • Each page is a separate section with 1 item
  • Even sections (0, 2, 4...) are right pages
  • Odd sections (1, 3, 5...) are left pages
  • Pages should always come in pairs for proper book effect

Page Structure

For a proper book effect, structure your pages like this:

  1. Two invisible pages (indices 0-1) - allows the book to start "closed"
  2. Cover page (right side, index 2)
  3. Blank or inside cover (left side, index 3)
  4. Content pages in pairs (right, left, right, left...)
  5. Back inside cover (last page)

Auto-Opening the Book

For a polished presentation effect, you can automatically open the book after a brief delay:

private var autoOpenTimer: Timer?

private func scheduleAutoOpen() {
    // Only auto-open if the book is at the beginning (closed)
    guard bookViewController.collectionView.contentOffset.x <= 0.0 else { return }

    autoOpenTimer?.invalidate()
    autoOpenTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { [weak self] _ in
        self?.autoOpenBook()
    }
}

private func autoOpenBook() {
    autoOpenTimer?.invalidate()
    autoOpenTimer = nil
    // Open to the first content page (after invisible pages and cover)
    bookViewController.openToPage(at: 4, animated: true)
}

// Call after setting pages
bookViewController.setPages(pages, animated: false)
scheduleAutoOpen()

This creates a book-like presentation where the book starts closed and automatically opens after 1 second, similar to opening a physical book.

Demo

See Example/BookLayoutExample/ViewController.swift for a complete working example.

Installation

Swift Package Manager

Add BookLayout to your project using Swift Package Manager:

  1. In Xcode, select File > Add Package Dependencies
  2. Enter the repository URL: https://github.com/piemonte/BookLayout.git
  3. Select the version you want to use
  4. Add the BookLayout product to your target

Or add it to your Package.swift:

dependencies: [
    .package(url: "https://github.com/piemonte/BookLayout.git", from: "0.0.2")
]

Manual Integration

To manually integrate these components into your project:

  1. Copy all .swift files from the Sources directory
  2. Add them to your Xcode project
  3. Use BookViewController in your view controller hierarchy
  4. Customize BookPageCell to fit your design needs

Example Project

An example iOS app is available in the Example directory. To run it:

Using XcodeGen (Recommended)

cd Example
./setup.sh
open BookLayoutExample.xcodeproj

The setup script will install XcodeGen if needed and generate the Xcode project.

Manual Setup

If you prefer to set up manually:

  1. Install XcodeGen: brew install xcodegen
  2. Navigate to the Example directory
  3. Run xcodegen generate
  4. Open BookLayoutExample.xcodeproj in Xcode

See Example/README.md for more details.

Customization

Custom Page Types

Extend BookPageModel.PageType with your own page types:

public enum PageType {
    case invisible
    case blank
    case cover
    case content(String)
    case colored(UIColor)
    case custom(MyCustomData)  // Add your own
}

Custom Cell Appearance

Modify BookPageCell.configure(with:) to customize how pages are displayed:

case .custom(let data):
    pageView.isHidden = false
    // Add your custom UI setup here

Layout Parameters

Adjust the page size calculation in BookLayout.collectionViewPageSize:

public var collectionViewPageSize: CGSize {
    guard let collectionView = collectionView else {
        return .zero
    }
    // Customize these values
    return CGSize(
        width: (0.5 * collectionView.bounds.width) - 20,
        height: collectionView.bounds.height - 50
    )
}

Requirements

  • Swift 5.0+
  • UIKit

License

See original source files for copyright information.

Resources