A simple but highly customizable `UICollectionViewLayout` for `UICollectionView`.

Overview

CollectionViewPagingLayout

License platforms pod Carthage compatible Swift Package Manager compatible

Layout Designer


SnapshotTransformView

ScaleTransformView

StackTransformView

Custom implementations

About

This is a simple but powerful framework that lets you make complex layouts for your UICollectionView.
The implementation is quite simple. Just a custom UICollectionViewLayout that gives you the ability to apply transforms to the cells.
No UICollectionView inheritance or anything like that.
For more details, see How to use

Installation

This framework doesn't contain any external dependencies.

CocoaPods

# Podfile
use_frameworks!

target 'YOUR_TARGET_NAME' do
    pod 'CollectionViewPagingLayout'
end

Replace YOUR_TARGET_NAME and then, in the Podfile directory, type:

$ pod install

Carthage

Add this to Cartfile

github "CollectionViewPagingLayout"

and then, in the Cartfile directory, type:

$ carthage update

Swift Package Manager

using Xcode:

File > Swift Packages > Add Package Dependency

Manually

Just add all the files under Lib directory to your project

How to use

Using Layout Designer

There is a macOS app to make it even easier for you to build your custom layout.
It allows you to tweak many options and see the result in real-time.
It also generates the code for you. So, you can copy it to your project.

You can purchase the app from App Store and support this repository, or you can build it yourself from the source.
Yes, the macOS app is open-source too!.

Manually

  • First, make sure you imported the framework
import CollectionViewPagingLayout
  • Set up your UICollectionView as you always do (you need a custom class for cells)
  • Set the layout for your collection view: (in most cases you want a paging effect so enable that too)
let layout = CollectionViewPagingLayout()
collectionView.collectionViewLayout = layout
collectionView.isPagingEnabled = true // enabling paging effect

Note: Go to Prepared Transformable Protocols if you want to use prepared effects! to make a custom effect contiune.

  • Now, you just need to conform your cell class to TransformableView and start implementing your custom transforms. for instance:
class YourCell: UICollectionViewCell { /*...*/ }
extension YourCell: TransformableView {
  func transform(progress: CGFloat) {
    // apply changes on any view of your cell
  }
}

As you see above, you get a progress value. Use that to apply any changes you want.

progress is a float value that represents the current position of your cell in the collection view.
When it's 0 that means the current position of the cell is exactly in the center of your collection view.
the value could be negative or positive and that represents the distance to the center of your collection view.
for instance 1 means the distance between the center of the cell and the center of your collection view is equal to your collection view width.

you can start with a simple transform like this:

extension YourCell: TransformableView {
    func transform(progress: CGFloat) {
        let transform = CGAffineTransform(translationX: bounds.width/2 * progress, y: 0)
        let alpha = 1 - abs(progress)

        contentView.subviews.forEach { $0.transform = transform }
        contentView.alpha = alpha
    }
}
  • Don't forget to set numberOfVisibleItems, by default it's null and that means all of the cells will be loaded in the memory.
layout.numberOfVisibleItems = ...

Prepared Transformable Protocols

There are some prepared transformable protocols to make it easier to use this framework.
Using them is simple. You only need to conform your UICollectionViewCell to the protocol.
You can use the options property to tweak it as you want.
There are three types:

  • ScaleTransformView (orange previews)
  • SnapshotTransformView (green previews)
  • StackTransformView (blue previews)
    These protocols are highly customizable, you can make tons of different effects using them.
    Here is a simple example for ScaleTransformView which gives you a simple paging with scaling effect:
extension YourCell: ScaleTransformView {
    var scaleOptions = ScaleTransformViewOptions(
        minScale: 0.6,
        scaleRatio: 0.4,
        translationRatio: CGPoint(x: 0.66, y: 0.2),
        maxTranslationRatio: CGPoint(x: 2, y: 0),
    )
}

There is an "options" property for each of these protocols where you can customize the effect, check the struct to find out what each parameter does.
A short comment on the top of each parameter explains what that does.
ScaleTransformView -> ScaleTransformViewOptions
SnapshotTransformView -> SnapshotTransformViewOptions
StackTransformView -> StackTransformViewOptions

See the examples in the samples app.
Check here to see used options for each: /PagingLayoutSamples/Modules/Shapes/ShapeCell/

Target view

You may wonder how does it find out the subview in your cell to apply transforms on.
If you check the transformable protocols, you find the target view for each. like ScaleTransformView.scalbleView.

The default value is the first subview of "contentView":

public extension ScaleTransformView where Self: UICollectionViewCell {
    
    /// Default `scalableView` for `UICollectionViewCell` is the first subview of
    /// `contentView` or the content view itself if there is no subview
    var scalableView: UIView {
        contentView.subviews.first ?? contentView
    }
}

If that's not what you want, you can implement it.

Customize Prepared Transformables

Yes, you can customize them or even combine them.
To do that, implement TransformableView.transform function and call the transformable function manually, like this:

extension LayoutTypeCollectionViewCell: ScaleTransformView {
    
    func transform(progress: CGFloat) {
        applyScaleTransform(progress: progress)
        // customize views here, like this:
        titleLabel.alpha = 1 - abs(progress)
        subtitleLabel.alpha = titleLabel.alpha
    }

}

As you see, applyScaleTransform applies the scale transforms and right after that we change the alpha for titleLabel and subtitleLabel.
To find the public function(s) of each protocol check the definition of that.

Other features

Control current page

You can control the current page by the following functions of CollectionViewPagingLayout:

  • func setCurrentPage(_ page: Int, animated: Bool = true)
  • func goToNextPage(animated: Bool = true)
  • func goToPreviousPage(animated: Bool = true)

These are safe wrappers around setting the ContentOffset of UICollectionview.
You can get the current page by a public variable CollectionViewPagingLayout.currentPage.
Listen to the changes via CollectionViewPagingLayout.delegate:

public protocol CollectionViewPagingLayoutDelegate: class {
    func onCurrentPageChanged(layout: CollectionViewPagingLayout, currentPage: Int)
}

Select Item At

As explained in the Limitations, you can't use collectionview's didSelectItemAt for more than one cell.
But, you can use this instead:

  • Implement TransformableView.selectableView and pass the view that you want to be selectable (by default it's the first subview of UICollectionViewCell.contentView)
  • Call layout.configureTapOnCollectionView() AFTER setting the layout for you collection view.
  • That's it. Now you get similar functionality by using CollectionViewPagingLayout.delegate instead of CollectionView.delegate
  • The method is func collectionViewPagingLayout(_ layout: CollectionViewPagingLayout, didSelectItemAt indexPath: IndexPath)

Limitations

  • Specify the number of visible cells:

You need to specify the number of visible cells.
Since this layout gives you the flexibility to show the next and previous cells,
By default, it loads all of the cells in the collectionview's frame, which means iOS keeps all of them in the memory.
Based on your design, you can specify the number of cells that you need to show.

  • didSelectItemAt:

The way that this library works is by putting all of the cells in the collectionview's frame and applying transforms on the target-view
(StackTransformView.cardView, ScaleTransformView.scalableView and SnapshotTransformView.targetView).

So, you can use func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) but if you have multiple cells on screen only one of them is selectable! (because the others are below it).

You can implement func zPosition(progress: CGFloat) -> Int to specify which cell should be on the top.

This also means you can't handle any gesture for multiple cells.
But, there is a built-in solution to this, see Select Item At

  • It doesn't support RTL layouts

License

CollectionViewPagingLayout is available under the MIT license. See LICENSE file for more info.

Issues
  • Crash in modal view controller when swiping up on the controller.

    Crash in modal view controller when swiping up on the controller.

    Crashes when swiping up on the controller when having a collectionView with this layout presented modally. Only happens when the view is initially loaded and the first thing you do is swipe up.

    Will not crash when you swipe to a different card and swipe up. When you swipe up and it doesn't crash you get other cards reloading from the top left and expanding back into place every time you swipe.

    If you comment out viewDidLayoutSubviews code it will not crash but other issues are present.

    Error: [UICollectionViewData isIndexPathValid:validateItemCounts:]: message sent to deallocated instance

    opened by BubblyNetDev 13
  • Is there a way to have multiple cells appear on the collection view at once?

    Is there a way to have multiple cells appear on the collection view at once?

    Hi, thanks for the project, its super impressive. I saw some other issues people are having with the project and tried to use the suggestions you provided, but I am still facing some issues myself.

    It seems like, by design, the cells always take the entire collection view space. Is there any way that I can have multiple cells appear in the collection view?

    The issue i'm having is that the appearance is like this:

    Screen Shot 2021-03-29 at 2 05 26 PM

    The animations of the cells (scaling as I Scroll) work fine, but the other cells appear off screen.

    I think that if my collection view had a larger height, then it would appear normal, but I need to have a small collection view size. I tried manipulating the card size like in other examples you had, but it seems like just the card would get smaller and the cell would remain the same size as the collection view.

    opened by alanpridestar 10
  • Extensions must not contain stored properties

    Extensions must not contain stored properties

    Screen Shot 2020-10-11 at 09 40 24

    Hi Amir, How can I fix this error?

    opened by tranquocviet226 8
  • setCurrentPage(animated: false) with ScaleTransformView causes a stack of cells to form

    setCurrentPage(animated: false) with ScaleTransformView causes a stack of cells to form

    I have a ScaleTransformView, with a layout of 3 visible cells, that seems to work as expected.

    However, when calling setCurrentPage(animated = false), each of the 'visible cells' occupy the same frame as the 'primary' cell, causing a stack of three cells. As soon as you start dragging the primary cell, each of the 'visible cells' fall to their correct locations respectively.

    Setting animated: true results in expected behavior, however having it as true isn't ideal for my use case. I've already tried calling layoutIfNeeded(), but that seems to have no effect.

    opened by elrond140 7
  • Next cell is not tappable.

    Next cell is not tappable.

    I've build an app which will allow user to like and share quotes by using your library but the problem is that after a swipe next cell action buttons are not capable. We've tried to fix this issue by using your delegate method but it is not working.

    Video attached - https://youtu.be/yVZlXM_TXbE

    opened by xLuciferSx 7
  • iOS 8 warning in Xcode 12

    iOS 8 warning in Xcode 12

    In the latest version of Xcode 12, there is a warning associated with this package if installed via SwiftPM. This is because Xcode 12 drops support for iOS 8 and this package still supports it. Screenshot

    opened by CristianMoisei 5
  • Type of expression is ambiguous without more context (\.attributes)

    Type of expression is ambiguous without more context (\.attributes)

    in collectionviewpaginglayoutdelegate problem occurs Screen Shot 2020-07-13 at 1 24 28 AM

    opened by belalmedhat97 5
  • How to get top most card's index

    How to get top most card's index

    I want to get the topmost card's index which is being displayed. Pl guide me on how I can get it with your library. Thanks.

    opened by Travloper 4
  • Build failed in Xcode 13 / iOS 15 Beta

    Build failed in Xcode 13 / iOS 15 Beta

    I'm using Xcode 13 (Beta 5) and iOS 15 Beta and have just started using this package. However, as soon as I include the package in my project I'm getting "Build Failed" and a couple of warnings.

    In total I get 10 swift compiler errors related to CollectionViewPagingLayout and two warnings, see attached print screen.

    Any ideas?

    Thanks!

    Build Error
    opened by skegget 1
Releases(1.0.2)
  • 1.0.2(Jun 13, 2021)

  • 1.0.1(May 18, 2021)

    • Fix a bug in animation completion closure, Use NSKeyValueObservation on contentOffset instead of CATransaction.setCompletionBlock
    • Fix an issue for selection not being updated if data gets reload
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Apr 25, 2021)

    New features:

    • Add SwiftUI support
    • ZPosition can be handled via CALayer or layout attribute or both, see CollectionViewPagingLayout.zPositionHandler
    • ViewAnimator: You can set the animation duration or implement your custom animator.
    • You can use the predefined layout options using an enum. for instance, ScaleTransformViewOptions.Layout.coverFlow
    • SnapshotTransformView.canReuse(snapshot:) You can define when the existing snapshots invalidate.

    Changes:

    • By default, zIndex will apply to the attribute and the CALayer, you can change it using CollectionViewPagingLayout.zPositionHandler
    • configureTapOnCollectionView and didSelectItemAt methods removed. You can use the built-in collectionview delegate instead!
    • Fix a problem: a page blinks before the transform effects apply on it, to fix it the attributes have alpha=0 by default before the cell is loaded. You can change it by setting "transparentAttributeWhenCellNotLoaded" to false
    • An bounds observer added for the collection view so, you don't need to call "invalidateLayout" on "viewDidLayoutSubviews"
    • If you are on page 1 and call setCurrentPage(4). the delegate method only gets called for page 4. previously, it was 2,3 and 4
    • ScaleTransformView.blurHost renamed to ScaleTransformView.scaleBlurHost
    • StackTransformView.blurHost renamed to StackTransformView.stackBlurHost
    • SnapshotTransformView.identifier renamed to SnapshotTransformView.snapshotIdentifier
    • Change default implementation of snapshotIdentifier to consider contentOffset of a possible scrollview inside a page
    Source code(tar.gz)
    Source code(zip)
  • 0.4.1(Mar 10, 2021)

  • 0.3.0(Jul 5, 2020)

    • Breaking change: use minTranslateRatios and maxTranslateRatios instead of minTranslates and maxTranslates for ScaleTransformView, it helps us to use the library on different screen sizes without changing the options, translateRatio is also works differently:
    translateX = progress * translates.x * targetView.width
    translateY = progress * translates.y * targetView.height
    translateZ = progress * translates.z * targetView.width
    // same for min and max
    
    • Layout designer code generator completed
    • Fix setCurrentPage related issues
    Source code(tar.gz)
    Source code(zip)
  • 0.2.0(Jul 4, 2020)

    • Introduce new iPad/Mac(Catalyst) app for designing layouts
    • New delegate function func collectionViewPagingLayout(_ layout: CollectionViewPagingLayout, didSelectItemAt indexPath: IndexPath) for using this func configureTapOnCollectionView(goToSelectedPage: Bool = false) needs to be called after assigning layout to the collection view - will be added to the ReadMe
    • Fix not change current page on animated page change
    • Fix zero sections
    Source code(tar.gz)
    Source code(zip)
  • 0.1.6(Jun 27, 2020)

  • 0.1.5(May 18, 2020)

  • 0.1.4(May 4, 2020)

  • 0.1.3(Apr 21, 2020)

  • 0.1.2(Apr 11, 2020)

  • 0.1.0(Apr 4, 2020)

    • Introducing Premade Transformable as a way to use the library faster
    • Introducing three Premade Transformables (Scale, Stack, Snapshot) with samples
    • Change the samples project to use the library as a Development Pod dependency
    • Introducing the new main page
    • Fix some issues and improve CollectionViewPagingLayout
    Source code(tar.gz)
    Source code(zip)
  • 0.0.6(Mar 10, 2020)

    • Fix issues with out of bounds layout attributes https://github.com/amirdew/CollectionViewPagingLayout/issues/5
    • Rename method name goToPrevPage -> goToPreviousPage
    Source code(tar.gz)
    Source code(zip)
Owner
Amir Khorsandi
Amir Khorsandi
QOwnNotes is a plain-text file notepad and todo-list manager with markdown support and Nextcloud / ownCloud integration.

QOwnNotes Installation | Changelog | Issues | Shortcuts | Documentation | Screenshots | Nextcloud API | Nextcloud App Page | ownCloud API | Telegram G

Patrizio Bekerle 2.2k Sep 20, 2021
Elegant Microsoft To-Do desktop app

Ao Elegant Microsoft To-Do desktop app Description Ao is an unofficial, featureful, open source, community-driven, free Microsoft To-Do app, used by p

Klaus Sinani 1.9k Sep 15, 2021
A simple Timer app for Mac

A simple Timer app for Mac Download here Drag the blue arrow to set a timer. Release to start! Click to pause. When the time is up, a notification wil

Michael Villar 1.9k Sep 20, 2021
Screenshot Tracker for Mac - Rewatch what you've worked on

Simple Mac Screenshot Tracker Become more productive by reviewing what you've been working on. This application runs in the background and creates low

InstanceLabs 31 Sep 13, 2021
Personal db information management system.

The Information Management System This tool is so simple that most people don't understand how to use it. TL;DR This is a personal database which stor

null 43 Sep 23, 2021
Clean and simple clipboard manager for developers

Flycut Description: Flycut is a clean and simple clipboard manager for developers. It's based on an open source app called Jumpcut. On the Mac, every

Gennadii Potapov 1.8k Sep 14, 2021
Lightweight clipboard manager for macOS

Maccy Maccy is a lightweight clipboard manager for macOS. It keeps the history of what you copy and lets you quickly navigate, search, and use previou

Alex Rodionov 3k Sep 23, 2021
Simple macOS app to keep TODO-list in status bar

status-bar-todo Simple macOS app to keep TODO-list in status bar. This app can do limited number of tasks: Add TODO Mark/unmark TODO as completed Dele

Onix-Systems 84 Sep 20, 2021
A simple unofficial wrapper application for Trello.com

TrelloApp An unofficial wrapper application for Trello.com written in Swift. This is almost a "Hello World" for a site specific browser. License Copyr

John W. Long 17 Sep 16, 2021
Your next meeting always before your eyes in the macOS menu bar

MeetingBar is a menu bar app for your calendar meetings (macOS 10.15+). Integrated with 20+ meeting services so you can quickly join meetings from eve

Andrii Leitsius 2.4k Sep 17, 2021
ControlPlane - context-sensitive computing for OS X

ControlPlane What is ControlPlane ControlPlane, a fork of MarcoPolo, brings context and location sensitive awareness to OS X. With ControlPlane you ca

Dustin Rue 1.6k Sep 14, 2021
Itsycal is a tiny calendar for your Mac's menu bar. http://www.mowglii.com/itsycal

I've learned a lot by looking at other people's code so maybe someone can learn something from looking at mine. = = = = = = = = Itsycal is a tiny ca

Sanjay 2.2k Sep 23, 2021
A macOS/iOS apps to treat ideas as links of concepts.

Linked Ideas A macOS application to write down and connect ideas and an iOS application to read documents. Objective Linked Ideas is an application to

Felipe Espinoza 300 Sep 12, 2021
 Middleclick with triple click/tap for MacBook trackpad and Magic Mouse.

MiddleClick Emulate a scroll wheel click with three finger Click or Tap on MacBook trackpad and Magic Mouse with macOS Catalina10.15 support! !_ Disco

Art Ginzburg 278 Sep 23, 2021
A macOS app for organizing folders

macOrganizer macOrganizer is an OS X application that helps you organize your files or remove unnecessary files. Usage Download latest version (1.0) U

Shubham Batra 67 Sep 20, 2021
The break time reminder app

Stretchly The break time reminder app Stretchly is a cross-platform Electron app that reminds you to take breaks when working on your computer. Table

Jan Hovancik 2.8k Sep 22, 2021
To-do list time tracker for programmers and other digital workers with Jira, Github, and Gitlab integration

Please help us improve the app's usability! Organize your daily tasks in one place while making time tracking a lot less annoying. Super Productivity

Johannes Millan 4.1k Sep 24, 2021