Blueprints - A framework that is meant to make your life easier when working with collection view flow layouts.

Overview

Blueprints logo Blueprints Preview

CI Status Version Carthage Compatible Code Coverage License Platform Swift

Description

Blueprints Icon

Blueprints is a collection of flow layouts that is meant to make your life easier when working with collection view flow layouts. It comes with two built-in layouts that are highly flexible and easy to configure at the call-site. They support properties like items per row and items per column; this will calculate the layout attributes needed for fitting the number of views that you want to appear on the screen.

The framework also provides a good base for your custom implementations. By extending the core blueprint layout, you get built-in support for animations and layout attribute caching. The bundled default animator supports animations that look very similar to what you get from a vanilla table view. If you want to provide your collection view animator, no problem; you can inject an animator of your choosing when initializing the layout.

Features

  • 🍭 Animation support
  • 🀳🏻 Optimized for performance
  • πŸ“ Built-in vertical and horizontal layouts
  • πŸ“° Supports header and footers
  • πŸ– Supports sticky headers and footers
  • 🌈 Built-in mosiac layout
  • πŸ’¦ Built-in vertical layout that supports waterfall
  • πŸ“± iOS support
  • πŸ’» macOS support
  • πŸ“Ί tvOS support
  • πŸ¦– Objective-C support

Supporting the project

If you want to support the development of this framework, you can do so by becoming a sponsor. ❀️

Preview

iOS macOS
iOS PReview macOS Preview

How do items per row work?

If you specify how many items per row that you want to appear in a vertical layout, the width of the layout attribute will be calculated for you taking the section inset, item spacing into account to make sure that all views fit your design. For example, if you set that you want two items per row, then two views will appear on the same row side by side. If you want to create a table view layout, you would simply set the items per row value to be one. You can use this variable for horizontal layouts as well, but instead of creating a new row, the value is used to create a width to cover the desired area. If you want the width to span across the entire container then simply set it to one, if you want to create a carousel layout with hinting, setting a value like 1.1 will render at least one complete item and give a visual hint to the user that another view is available if the scroll horizontally.

How do items per column work?

Items per column are explicitly for horizontal layouts and are used to decide how many items that should be shown on screen but using a vertical axis. If you set it to two, it will display two views, one above and one below and then continue to build the rest of the views horizontally, following the same pattern.

How does item sizes work?

It works just like a regular flow layout, but with a twist. If you want to provide a static size using the regular item size, you are free to do so. As mentioned above, you can also provide the number of views that you want visible on the screen based on the container views width. To provide dynamic sizing, you can make your collection view delegate conform to UICollectionViewDelegateFlowLayout or NSCollectionViewDelegateFlowLayout. That way you can compute the values based on the data coming from the data source etc. Worth noting is that using itemsPerRow takes precedence over the other alternatives.

Dynamic sizing preview

Usage

Vertical layout

let blueprintLayout = VerticalBlueprintLayout(
  itemsPerRow: 1.0,
  height: 50,
  minimumInteritemSpacing: 10,
  minimumLineSpacing: 10,
  sectionInset: EdgeInsets(top: 10, left: 10, bottom: 10, right: 10),
  stickyHeaders: true,
  stickyFooters: false
)
let collectionView = UICollectionView(frame: .zero,
                                      collectionViewLayout: blueprintLayout)

Horizontal layout

let blueprintLayout = HorizontalBlueprintLayout(
  itemsPerRow: 1.0,
  itemsPerColumn: 2,
  height: 50,
  minimumInteritemSpacing: 10,
  minimumLineSpacing: 10,
  sectionInset: EdgeInsets(top: 10, left: 10, bottom: 10, right: 10),
  stickyHeaders: true,
  stickyFooters: true
)
let collectionView = UICollectionView(frame: .zero,
                                      collectionViewLayout: blueprintLayout)

Mosaic layout

let mosaicLayout = VerticalMosaicBlueprintLayout(
  patternHeight: 400,
  minimumInteritemSpacing: 2,
  minimumLineSpacing: 2,
  sectionInset: EdgeInsets(top: 2, left: 2, bottom: 2, right: 2),
  patterns: [
    MosaicPattern(alignment: .left, direction: .vertical, amount: 2, multiplier: 0.6),
    MosaicPattern(alignment: .left, direction: .horizontal, amount: 2, multiplier: 0.33),
    MosaicPattern(alignment: .left, direction: .vertical, amount: 1, multiplier: 0.5),
    MosaicPattern(alignment: .left, direction: .vertical, amount: 1, multiplier: 0.5)
  ])
let collectionView = UICollectionView(frame: .zero,
                                      collectionViewLayout: mosaicLayout)

Installation

Blueprints is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'Blueprints'

Blueprints is also available through Carthage. To install just write into your Cartfile:

github "zenangst/Blueprints"

Blueprints can also be installed manually. Just download and drop Sources folders in your project.

Author(s)

Contributing

We would love you to contribute to Blueprints, check the CONTRIBUTING file for more info.

License

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

Comments
  • Multiple Sections?

    Multiple Sections?

    Is there a way to use this with multiple sections? When I set the layout, it crashes and I get this error:

    Thread 1: Fatal error: Index out of range
    

    It traces back to the VerticalBlueprintLayout.swift's class prepare() method:

            if section == layoutAttributes.count {
              layoutAttributes.append([layoutAttribute])
            } else {
              layoutAttributes[section].append(layoutAttribute)
            }
    

    The objective was to make the 2nd and 3rd sections of the collection view use the VerticalBlueprintLayout while keeping the 1st section customized.

    bug 
    opened by HackShitUp 12
  • Mosaic Layout

    Mosaic Layout

    I'm having troubles understanding how the Mosaic Layout works...

    I don't understand why the first "block" isn't aligned on the right.

    simulator screen shot - iphone 8 - 2018-09-13 at 18 51 27

    let mosaicLayout = VerticalMosaicBlueprintLayout(
      itemSize: CGSize.init(width: 50, height: 400),
      minimumInteritemSpacing: 15,
      minimumLineSpacing: 15,
      sectionInset: EdgeInsets(top: 15, left: 15, bottom: 15, right: 15),
      patterns: [
        MosaicPattern(alignment: .left, direction: .vertical, amount: 2, multiplier: 0.5),
        MosaicPattern(alignment: .left, direction: .horizontal, amount: 2, multiplier: 0.33),
        MosaicPattern(alignment: .left, direction: .vertical, amount: 1, multiplier: 0.5),
        MosaicPattern(alignment: .right, direction: .vertical, amount: 2, multiplier: 0.5)
    ])
    
    bug 
    opened by guidev 12
  • Unable to scroll past all items in the collection view. Affects both horizontal and vertical layout when using dynamic heights.

    Unable to scroll past all items in the collection view. Affects both horizontal and vertical layout when using dynamic heights.

    I know changes haven't been made to the horizontal layout to fully support dynamic heights however I thought it worth mentioning here that both are affected in slightly different ways.

    Vertical: If the previous columns last item has a greater height than the last item in the last column, then the scrollview bounds are pinning against the last item. This stops the user from scrolling which in turn cuts off the collection view cell.

    screenshot 2018-12-13 at 13 16 50

    Horizontal:

    When scrolling around the cells disappear and re-appear, this is only an issue if items per rows is been used alongside items per column. However this may not be the intended use for a Horizontal layout and will probably be addressed in #43

    bug 
    opened by christoff-1992 9
  • #47 fix incorrect previous x offset been used

    #47 fix incorrect previous x offset been used

    Fixes #47

    Required or the wrong item is looked-up from the layoutAttributes when using headers.

    @zenangst - Have left the variable for sectionMaxY for the time been as I believe this will be required to resolve the issue with the incorrect position of the footer when multiple columns are used.

    opened by christoff-1992 8
  • Changing the dataSource can cause the cachedItems layoutAttributes to become nil, when the updated datasource has items for section at index.

    Changing the dataSource can cause the cachedItems layoutAttributes to become nil, when the updated datasource has items for section at index.

    I have observed the following behaviour when updating the dataSource and updating the collectionViewLayout. (As different cells are been used and they have a different height between the datasources)

    1. CollectionView with segmented control that changes the datasource.
    2. The first datasource has items, the second datasource has no items, the third datasource has items.
    3. When switching to the empty datasource the cached items will become nil as there are no items in the section.
    4. When switching to a datasource with items after this, the cached items correctly updates initially but then somewhere along the chain it invalidates the cached items returning them to the nil state. I am not sure what is causing this at the moment as the blueprint layout correctly sets this and super is always called before the cached items have been set.
    5. When layoutAttibutesForItem(at indexPath: IndexPath) is called, as the cached items have been invalidated, an index out of bounds exception is caused.

    implementing a safe check for the index resolves the issues, however I am not sure what's causing the cached items to become nil in the first place.

    override open func layoutAttributesForItem(at indexPath: IndexPath) -> LayoutAttributes? {
        let compare: (LayoutAttributes) -> Bool
        #if os(macOS)
          compare = { indexPath > $0.indexPath! }
        #else
          compare = { indexPath > $0.indexPath }
        #endif
    
        guard cachedItems[safe:indexPath.section] != nil else {
            return nil
        }
    
        let result = binarySearch.findElement(in: cachedItems[indexPath.section],
                                              less: compare,
                                              match: { indexPath == $0.indexPath })
        return result
      }
    
    subscript (safe index: Int) -> Element? {
            return index < count ? self[index] : nil
        }
    

    I will add an example asap and will continue to hunt down what may be causing the cached items to become nil.

    bug 
    opened by christoff-1992 8
  • Recommended approach to dynamic height using UICollectionViewDelegateFlowLayout

    Recommended approach to dynamic height using UICollectionViewDelegateFlowLayout

    Hey just wondering what the recommended approach is to using items per row with dynamic height, do we have to load a dummy cell to calculate the height and return this in the sizeForItemAt?

    Likewise to support self sizing headers, at the moment the headerReferenceSize is been used to set the height. As a result the delegate method for referenceSizeForHeaderInSection is not called. Is this a limitation of the layout?

    bug question 
    opened by christoff-1992 7
  • Horizontal Layout - layout attributes for supplementary items changed without invalidating the layout.

    Horizontal Layout - layout attributes for supplementary items changed without invalidating the layout.

    If headers and footers are been used the horizontal layout will crash when been set.

    2018-12-14 11:33:41.254874+0000 Example-iOS[2682:570726] *** Assertion failure in -[UICollectionViewData validateLayoutInRect:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKitCore/UIKit-3698.93.8/UICollectionViewData.m:459
    2018-12-14 11:33:41.256220+0000 Example-iOS[2682:570726] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'layout attributes for supplementary item at index path (<NSIndexPath: 0x281b59b00> {length = 2, path = 0 - 0}) changed from <UICollectionViewLayoutAttributes: 0x104700dd0> index path: (<NSIndexPath: 0x281b582e0> {length = 2, path = 0 - 0}); element kind: (UICollectionElementKindSectionHeader); frame = (0 0; 375 61);  to <UICollectionViewLayoutAttributes: 0x104704650> index path: (<NSIndexPath: 0x281b59b00> {length = 2, path = 0 - 0}); element kind: (UICollectionElementKindSectionHeader); frame = (0 0; 1835 61);  without invalidating the layout'
    *** First throw call stack:
    (0x1c05fbea0 0x1bf7cda40 0x1c0511c1c 0x1c0fff140 0x1ecfbb2ac 0x1ecfba814 0x1ecfbce30 0x1ecf8f594 0x1ecf8eaa8 0x1ecf8e668 0x102f03db0 0x102ee9c80 0x1edb528b4 0x1edb52ed0 0x102f03b68 0x102f0d0f4 0x102f0d044 0x102f0d154 0x1ed6ba768 0x1ece8a6ec 0x1ece8a61c 0x1ed6ba768 0x1ed1486d0 0x1ed1489f0 0x1ed1479f0 0x1ed6f418c 0x1ed6f53f0 0x1ed6d46ec 0x1ed7a057c 0x1ed7a2f74 0x1ed79ba64 0x1c058c1cc 0x1c058c14c 0x1c058ba30 0x1c05868fc 0x1c05861cc 0x1c27fd584 0x1ed6b9054 0x102ed8288 0x1c0046bb4)
    libc++abi.dylib: terminating with uncaught exception of type NSException
    
    bug 
    opened by christoff-1992 6
  • Implement delegate methods for header/footer reference size

    Implement delegate methods for header/footer reference size

    This implements the delegate methods for header/footer reference sizes so they can be provided just like we do for the items.

    This will allow users to provide dynamic heights for headers and footers if they wish.

    enhancement 
    opened by christoff-1992 5
  • OSX example doesn't compile

    OSX example doesn't compile

    Compile OSX framework is Ok Compile OSX example is ok but problem is link the message error are:

    Undefined symbols for architecture x86_64: "___llvm_profile_runtime", referenced from: ___llvm_profile_runtime_user in BlueprintLayoutAnimator.o ___llvm_profile_runtime_user in BlueprintLayoutAnimation.o ___llvm_profile_runtime_user in TypeAlias.o ___llvm_profile_runtime_user in BlueprintLayoutAnimationType.o (maybe you meant: ___llvm_profile_runtime_user) ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)

    compiled with XCode 10.2.1

    opened by DevulderJeanPaul 5
  • Bug/rogue calls to prepare without invalidating the context

    Bug/rogue calls to prepare without invalidating the context

    Fixes #107 - I don't think we should be having to do this, but occasionally prepare is called without the context been invalidated causing additional calls to things like sizeForItemAt.

    This would normally go unnoticed, but I have been playing around with resizable child containers that have collection views with the custom layouts.

    Occasionally the rogue calls would add more items than needed into the dynamic height cache I had held causing some cells to have the incorrect size.

    opened by christoff-1992 5
  • Improve mosaic blueprint initializer

    Improve mosaic blueprint initializer

    This PR changes the initializer of the Mosaic layout to only include a pattern height instead of an item size. The width of the item is never used so this change is motivated by removing the confusion that it might be used. The new label is called patternHeight.

    Reference: https://github.com/zenangst/Blueprints/issues/43

    enhancement 
    opened by zenangst 5
  • [SUGGESTION] AutoCenter flow

    [SUGGESTION] AutoCenter flow

    Hello πŸ‘‹ , first of all thanks for this project!

    I'd like to know if it would be possible to auto-compute the sectionInset based on the layout (and with self cell size calculation) πŸ˜„ .

    Regards

    opened by RSickenberg 3
  • Update default number of sections

    Update default number of sections

    This should be 0 not 1 as we can't assume a value. It can cause issues if the collection view is using headers and footers, as the collection view attempts to dequeue a header/footer that has yet to be registered. fixes #139

    Blocked - Requires further changes 
    opened by christoff-1992 1
  • Number of sections should default to 0

    Number of sections should default to 0

    The number of sections should default to 0 to stop subsequent calls been made to other delegate methods when there are no items to be displayed.

    https://github.com/zenangst/Blueprints/blob/c3dc5442d3102d933bc439c5c845b277b20034b1/Sources/Shared/Core/BlueprintLayout.swift#L38

    This would cause a crash if headers/footers where been dequeued.

    opened by christoff-1992 1
  • Dynamic heights for headers and footers breaks cell positioning.

    Dynamic heights for headers and footers breaks cell positioning.

    When using dynamic heights for headers and footers the height of the collection view is incorrect. The last item will be overlapped by the footer due to the footers dynamic size not been taken into account. This had been fine in the past and may be related to some of the refactoring between #131 and master.

    bug 
    opened by christoff-1992 0
Releases(0.13.1)
Owner
Christoffer Winterkvist
random hero at @finkoslo by day, cocoa vigilante by night, dad at dawn. my life is awesome. Previously @hyperoslo
Christoffer Winterkvist
Enhanced transitioning between UICollectionView layouts in iOS.

TLLayoutTransitioning Enhanced transitioning between UICollectionView layouts in iOS. ##Overview TLLayoutTransitioning provides a TLLayoutTransition t

SwiftKick Mobile 359 Oct 30, 2022
BouncyLayout is a collection view layout that makes your cells bounce.

BouncyLayout is a collection view layout that makes your cells bounce. Features Pure Swift 5. Works with every UICollectionView. Horizontal and vertic

Robert-Hein Hooijmans 4.2k Jan 3, 2023
A drop-in mosaic collection view layout with a focus on simple customizations.

FMMosaicLayout is a mosiac collection view layout. There are a great number of media-based iOS applications that use UICollectionViewFlowLayout withou

Fluid Media Inc. 591 Dec 14, 2022
A mosaic collection view layout inspired by Lightbox's Algorithm, written in Swift πŸ”Ά

TRMosaicLayout A mosaic collection view layout inspired by Lightbox's Algorithm. This is a swift implementation/extension of @fmitech's FMMosaicLayout

Vincent Le 252 Nov 23, 2022
UICollectionViewSplitLayout makes collection view more responsive.

UICollectionViewSplitLayout makes collection view more responsive. What's this? UICollectionViewSplitLayout is a subclass of UICollectionViewLayout. I

Yahoo! JAPAN 239 Dec 6, 2022
Blueprints - A framework that is meant to make your life easier when working with collection view flow layouts.

Description Blueprints is a collection of flow layouts that is meant to make your life easier when working with collection view flow layouts. It comes

Christoffer Winterkvist 982 Dec 7, 2022
A beautiful set of predefined colors and a set of color methods to make your iOS/OSX development life easier.

Installation Drag the included Colours.h and Colours.m files into your project. They are located in the top-level directory. You can see a demo of how

Ben Gordon 3.1k Dec 28, 2022
Make your logic flow and data flow clean and human readable

Flow What's Flow Flow is an utility/ design pattern that help developers to write simple and readable code. There are two main concerns: Flow of opera

null 18 Jun 17, 2022
This app is a sample app that recognizes specific voice commands such as "make it red", "make it blue", "make it green", and "make it black" and change the background color of the view in the frame.

VoiceOperationSample This app is a sample app that recognizes specific voice commands such as "make it red", "make it blue", "make it green", and "mak

Takuya Aso 3 Dec 3, 2021
GraphQLite is a toolkit to work with GraphQL servers easily. It also provides several other features to make life easier during iOS application development.

What is this? GraphQLite is a toolkit to work with GraphQL servers easily. It also provides several other features to make life easier during iOS appl

Related Code 2.8k Jan 9, 2023
SwiftUI implementation of Conway’s Game of Life β€” also known as β€œLife”.

Life Conway’s Game of Life SwiftUI implementation of Conway’s Game of Life β€” also known simply as β€œLife”. About I’m Martin, an indie dev from Berlin.

Martin Lexow 23 Jan 21, 2022
This package is meant to make http request of an easy way inspiren in the architecture of Moya package

NetworkAgent This package is meant to make http request of an easy way inspiren in the architecture of Moya package. This package is 100% free of depe

Angel Rada 19 Sep 8, 2022
SugarRecord is a persistence wrapper designed to make working with persistence solutions like CoreData in a much easier way.

What is SugarRecord? SugarRecord is a persistence wrapper designed to make working with persistence solutions like CoreData in a much easier way. Than

Modo 2.1k Dec 29, 2022
A small set of utilities to make working with CoreData and Swift a bit easier.

SuperRecord =================== SUPPORTS SWIFT 2.0 from Version >= 1.4 ** SUPPORTS SWIFT 1.2 from Version <= 1.3 Both iOS and WatchOS A Swift CoreData

Michael Armstrong 372 Jul 19, 2022
A bunch of layouts providing light and seamless experiences in your Collection View

Swinflate Description Swinflate aims to encorporate a set of collection view layouts which provide a better and even more fluid experience in collecti

Vlad Iacob 224 Dec 19, 2022
SwiftUI Backports - Introducing a collection of SwiftUI backports to make your iOS development easier

SwiftUI Backports Introducing a collection of SwiftUI backports to make your iOS development easier. Many backports support iOS 13+ but where UIKIt fe

Shaps 530 Dec 28, 2022
A SwiftUI collection view with support for custom layouts, preloading, and more.

ASCollectionView A SwiftUI implementation of UICollectionView & UITableView. Here's some of its useful features: supports preloading and onAppear/onDi

Apptek Studios 1.3k Dec 24, 2022
Custom transition between two collection view layouts

Display Switcher We designed a UI that allows users to switch between list and grid views on the fly and choose the most convenient display type. List

Yalantis 2.3k Dec 14, 2022
Bolts is a collection of low-level libraries designed to make developing mobile apps easier.

Bolts Bolts is a collection of low-level libraries designed to make developing mobile apps easier. Bolts was designed by Parse and Facebook for our ow

null 5.7k Dec 29, 2022
Bolts is a collection of low-level libraries designed to make developing mobile apps easier.

Bolts in Swift Bolts is a collection of low-level libraries designed to make developing mobile apps easier. Bolts was designed by Parse and Facebook f

null 1.3k Nov 11, 2022