├── Pod ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── FMMosaicLayout.h │ └── FMMosaicLayout.m ├── Example ├── Tests │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── Tests.m │ ├── Tests-Prefix.pch │ └── Tests-Info.plist ├── FMMosaicLayout │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── Images.xcassets │ │ ├── back.imageset │ │ │ ├── back.png │ │ │ └── Contents.json │ │ ├── city.imageset │ │ │ ├── city.png │ │ │ └── Contents.json │ │ ├── game.imageset │ │ │ ├── game.png │ │ │ └── Contents.json │ │ ├── birds.imageset │ │ │ ├── birds.png │ │ │ └── Contents.json │ │ ├── bridge.imageset │ │ │ ├── bridge.png │ │ │ └── Contents.json │ │ ├── leaves.imageset │ │ │ ├── leaves.png │ │ │ └── Contents.json │ │ ├── stars.imageset │ │ │ ├── stars.png │ │ │ └── Contents.json │ │ ├── stream.imageset │ │ │ ├── stream.png │ │ │ └── Contents.json │ │ ├── sunset.imageset │ │ │ ├── sunset.png │ │ │ └── Contents.json │ │ ├── waves.imageset │ │ │ ├── waves.png │ │ │ └── Contents.json │ │ ├── balcony.imageset │ │ │ ├── balcony.png │ │ │ └── Contents.json │ │ ├── ceiling.imageset │ │ │ ├── ceiling.png │ │ │ └── Contents.json │ │ ├── sitting.imageset │ │ │ ├── sitting.png │ │ │ └── Contents.json │ │ ├── cityscape.imageset │ │ │ ├── cityscape.png │ │ │ └── Contents.json │ │ ├── mountains.imageset │ │ │ ├── mountains.png │ │ │ └── Contents.json │ │ ├── two-birds.imageset │ │ │ ├── two-birds.png │ │ │ └── Contents.json │ │ ├── mountain-tops.imageset │ │ │ ├── mountain-tops.png │ │ │ └── Contents.json │ │ ├── snowy-mountains.imageset │ │ │ ├── snowy-mountains.png │ │ │ └── Contents.json │ │ ├── LaunchImage.launchimage │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── FMMosaicLayout-Prefix.pch │ ├── FMMosaicLayout-Info.plist │ ├── FMMosaicCollectionViewController.h │ ├── FMAppDelegate.h │ ├── FMFooterView.h │ ├── FMHeaderView.h │ ├── main.m │ ├── FMMosaicCellView.h │ ├── FMFooterView.m │ ├── FMHeaderView.m │ ├── FMAppDelegate.m │ ├── FMMosaicCellView.m │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Example.storyboard │ ├── FMFooterView.xib │ ├── FMHeaderView.xib │ └── FMMosaicCollectionViewController.m ├── FMMosaicLayout.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── FMMosaicLayout-Example.xcscheme │ └── project.pbxproj ├── Podfile ├── Podfile.lock └── FMMosaicLayout.xcworkspace │ └── contents.xcworkspacedata ├── .gitignore ├── .travis.yml ├── FMMosaicLayout.podspec ├── LICENSE └── README.md /Pod/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Pod/Classes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/back.imageset/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/back.imageset/back.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/city.imageset/city.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/city.imageset/city.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/game.imageset/game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/game.imageset/game.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/birds.imageset/birds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/birds.imageset/birds.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/bridge.imageset/bridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/bridge.imageset/bridge.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/leaves.imageset/leaves.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/leaves.imageset/leaves.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/stars.imageset/stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/stars.imageset/stars.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/stream.imageset/stream.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/stream.imageset/stream.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/sunset.imageset/sunset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/sunset.imageset/sunset.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/waves.imageset/waves.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/waves.imageset/waves.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/balcony.imageset/balcony.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/balcony.imageset/balcony.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/ceiling.imageset/ceiling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/ceiling.imageset/ceiling.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/sitting.imageset/sitting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/sitting.imageset/sitting.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/cityscape.imageset/cityscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/cityscape.imageset/cityscape.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/mountains.imageset/mountains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/mountains.imageset/mountains.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/two-birds.imageset/two-birds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/two-birds.imageset/two-birds.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/mountain-tops.imageset/mountain-tops.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/mountain-tops.imageset/mountain-tops.png -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/snowy-mountains.imageset/snowy-mountains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmitech/FMMosaicLayout/HEAD/Example/FMMosaicLayout/Images.xcassets/snowy-mountains.imageset/snowy-mountains.png -------------------------------------------------------------------------------- /Example/Tests/Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMMosaicLayoutTests.m 3 | // FMMosaicLayoutTests 4 | // 5 | // Created by JVillella on 02/10/2015. 6 | // Copyright (c) 2014 JVillella. All rights reserved. 7 | // 8 | 9 | ${TEST_EXAMPLE} 10 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every test case source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | 9 | 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | target 'FMMosaicLayout', :exclusive => true do 4 | pod "FMMosaicLayout", :path => "../" 5 | end 6 | 7 | target 'Tests', :exclusive => true do 8 | pod "FMMosaicLayout", :path => "../" 9 | end 10 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FMMosaicLayout (0.1.1) 3 | 4 | DEPENDENCIES: 5 | - FMMosaicLayout (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | FMMosaicLayout: 9 | :path: ../ 10 | 11 | SPEC CHECKSUMS: 12 | FMMosaicLayout: 54c5e40fa93cdfc1f245bea9d59ce6faa27fbfea 13 | 14 | COCOAPODS: 0.36.0.rc.1 15 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/back.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "back.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/city.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "city.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/game.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "game.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMMosaicLayout-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/birds.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "birds.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/bridge.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "bridge.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/leaves.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "leaves.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/stars.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "stars.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/stream.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "stream.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/sunset.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "sunset.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/waves.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "waves.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/balcony.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "balcony.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/ceiling.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "ceiling.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/cityscape.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "cityscape.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/mountains.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "mountains.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/sitting.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "sitting.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/two-birds.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "two-birds.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/mountain-tops.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "mountain-tops.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/snowy-mountains.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "snowy-mountains.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac 2 | .DS_Store 3 | 4 | # Xcode 5 | # 6 | build/ 7 | *.pbxuser 8 | !default.pbxuser 9 | *.mode1v3 10 | !default.mode1v3 11 | *.mode2v3 12 | !default.mode2v3 13 | *.perspectivev3 14 | !default.perspectivev3 15 | xcuserdata 16 | *.xccheckout 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | *.xcuserstate 22 | 23 | # CocoaPods 24 | # 25 | # We recommend against adding the Pods directory to your .gitignore. However 26 | # you should judge for yourself, the pros and cons are mentioned at: 27 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 28 | # 29 | Pods/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * http://www.objc.io/issue-6/travis-ci.html 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | language: objective-c 6 | # cache: cocoapods 7 | # podfile: Example/Podfile 8 | # before_install: 9 | # - gem install cocoapods # Since Travis is not always on latest version 10 | # - pod install --project-directory=Example 11 | install: 12 | - gem install xcpretty --no-rdoc --no-ri --no-document --quiet 13 | script: 14 | - set -o pipefail && xcodebuild test -workspace Example/FMMosaicLayout.xcworkspace -scheme FMMosaicLayout-Example -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO | xcpretty -c 15 | - pod lib lint --quick 16 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /FMMosaicLayout.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "FMMosaicLayout" 3 | s.version = "0.1.4" 4 | s.summary = "A drop-in mosaic collection view layout with a focus on simple customizations." 5 | s.homepage = "https://github.com/fmitech/FMMosaicLayout" 6 | s.screenshots = ["http://fmitech.github.io/FMMosaicLayout/Screenshots/portrait-1.png", 7 | "http://fmitech.github.io/FMMosaicLayout/Screenshots/portrait-2.png", 8 | "http://fmitech.github.io/FMMosaicLayout/Screenshots/portrait-3.png", 9 | "http://fmitech.github.io/FMMosaicLayout/Screenshots/landscape.png", 10 | "http://fmitech.github.io/FMMosaicLayout/Screenshots/fmmosaiclayout.gif"] 11 | s.license = 'MIT' 12 | s.author = { "JVillella" => "julian.villella@hotmail.com" } 13 | s.source = { :git => "https://github.com/fmitech/FMMosaicLayout.git", :tag => s.version.to_s } 14 | 15 | s.platform = :ios, '7.0' 16 | s.requires_arc = true 17 | 18 | s.source_files = 'Pod/Classes' 19 | end 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Fluid Media. All rights reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "ipad", 6 | "minimum-system-version" : "7.0", 7 | "extent" : "full-screen", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "landscape", 12 | "idiom" : "ipad", 13 | "minimum-system-version" : "7.0", 14 | "extent" : "full-screen", 15 | "scale" : "1x" 16 | }, 17 | { 18 | "orientation" : "landscape", 19 | "idiom" : "ipad", 20 | "minimum-system-version" : "7.0", 21 | "extent" : "full-screen", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "orientation" : "portrait", 26 | "idiom" : "iphone", 27 | "minimum-system-version" : "7.0", 28 | "scale" : "2x" 29 | }, 30 | { 31 | "orientation" : "portrait", 32 | "idiom" : "iphone", 33 | "minimum-system-version" : "7.0", 34 | "subtype" : "retina4", 35 | "scale" : "2x" 36 | }, 37 | { 38 | "orientation" : "portrait", 39 | "idiom" : "ipad", 40 | "minimum-system-version" : "7.0", 41 | "extent" : "full-screen", 42 | "scale" : "1x" 43 | } 44 | ], 45 | "info" : { 46 | "version" : 1, 47 | "author" : "xcode" 48 | } 49 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMMosaicLayout-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.fluidmedia.$(PRODUCT_NAME:rfc1034identifier) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 0.1.4 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 5 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Example 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMMosaicCollectionViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMMosaicCollectionViewController.h 3 | // FMMosaicLayout 4 | // 5 | // Created by Julian Villella on 2015-01-30. 6 | // Copyright (c) 2015 Fluid Media. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | @interface FMMosaicCollectionViewController : UICollectionViewController 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMAppDelegate.h 3 | // FMMosaicLayout 4 | // 5 | // Created by Julian Villella on 2015-01-30. 6 | // Copyright (c) 2015 Fluid Media. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | @interface FMAppDelegate : UIResponder 27 | 28 | @property (strong, nonatomic) UIWindow *window; 29 | 30 | @end 31 | 32 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMFooterView.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMFooterView.h 3 | // FMMosaicLayout 4 | // 5 | // Created by Julian Villella on 2015-04-01. 6 | // Copyright (c) 2015 JVillella. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | @interface FMFooterView : UICollectionReusableView 27 | 28 | + (NSString *)reuseIdentifier; 29 | 30 | @property (weak, nonatomic) IBOutlet UILabel *titleLabel; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMHeaderView.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMHeaderView.h 3 | // FMMosaicLayout 4 | // 5 | // Created by Julian Villella on 2015-04-01. 6 | // Copyright (c) 2015 JVillella. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | @interface FMHeaderView : UICollectionReusableView 27 | 28 | + (NSString *)reuseIdentifier; 29 | 30 | @property (weak, nonatomic) IBOutlet UILabel *titleLabel; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // FMMosaicLayout 4 | // 5 | // Created by Julian Villella on 2015-01-30. 6 | // Copyright (c) 2015 Fluid Media. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | #import "FMAppDelegate.h" 28 | 29 | int main(int argc, char * argv[]) { 30 | @autoreleasepool { 31 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([FMAppDelegate class])); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMMosaicCellView.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMMosaicCellView.h 3 | // FMMosaicLayout 4 | // 5 | // Created by Julian Villella on 2015-01-30. 6 | // Copyright (c) 2015 Fluid Media. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | @interface FMMosaicCellView : UICollectionViewCell 27 | 28 | + (NSString *)reuseIdentifier; 29 | 30 | @property (weak, nonatomic) IBOutlet UILabel *titleLabel; 31 | @property (weak, nonatomic) IBOutlet UIImageView *imageView; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMFooterView.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMFooterView.m 3 | // FMMosaicLayout 4 | // 5 | // Created by Julian Villella on 2015-04-01. 6 | // Copyright (c) 2015 JVillella. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "FMFooterView.h" 27 | 28 | static NSString* const kFMFooterViewReuseIdentifier = @"FMFooterViewReuseIdentifier"; 29 | 30 | @implementation FMFooterView 31 | 32 | + (NSString *)reuseIdentifier { 33 | return kFMFooterViewReuseIdentifier; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMHeaderView.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMHeaderView.m 3 | // FMMosaicLayout 4 | // 5 | // Created by Julian Villella on 2015-04-01. 6 | // Copyright (c) 2015 JVillella. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "FMHeaderView.h" 27 | 28 | static NSString* const kFMHeaderViewReuseIdentifier = @"FMHeaderViewReuseIdentifier"; 29 | 30 | @implementation FMHeaderView 31 | 32 | + (NSString *)reuseIdentifier { 33 | return kFMHeaderViewReuseIdentifier; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMAppDelegate.m 3 | // FMMosaicLayout 4 | // 5 | // Created by Julian Villella on 2015-01-30. 6 | // Copyright (c) 2015 Fluid Media. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "FMAppDelegate.h" 27 | 28 | @implementation FMAppDelegate 29 | 30 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 31 | return YES; 32 | } 33 | 34 | - (void)applicationWillResignActive:(UIApplication *)application {} 35 | 36 | - (void)applicationDidEnterBackground:(UIApplication *)application {} 37 | 38 | - (void)applicationWillEnterForeground:(UIApplication *)application {} 39 | 40 | - (void)applicationDidBecomeActive:(UIApplication *)application {} 41 | 42 | - (void)applicationWillTerminate:(UIApplication *)application {} 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Pod/Classes/FMMosaicLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMMosaicLayout.h 3 | // FMMosaicLayout 4 | // 5 | // Created by Julian Villella on 2015-01-30. 6 | // Copyright (c) 2015 Fluid Media. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | @class FMMosaicLayout; 27 | 28 | typedef NS_ENUM(NSUInteger, FMMosaicCellSize) { 29 | FMMosaicCellSizeSmall, 30 | FMMosaicCellSizeBig 31 | }; 32 | 33 | @protocol FMMosaicLayoutDelegate 34 | 35 | - (NSInteger)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout numberOfColumnsInSection:(NSInteger)section; 36 | 37 | @optional 38 | 39 | - (FMMosaicCellSize)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout mosaicCellSizeForItemAtIndexPath:(NSIndexPath *)indexPath; 40 | - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section; 41 | - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout interitemSpacingForSectionAtIndex:(NSInteger)section; 42 | 43 | // Header/Footer 44 | - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout 45 | heightForHeaderInSection:(NSInteger)section; 46 | - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout 47 | heightForFooterInSection:(NSInteger)section; 48 | - (BOOL)headerShouldOverlayContentInCollectionView:(UICollectionView *)collectionView 49 | layout:(FMMosaicLayout *)collectionViewLayout; 50 | - (BOOL)footerShouldOverlayContentInCollectionView:(UICollectionView *)collectionView 51 | layout:(FMMosaicLayout *)collectionViewLayout; 52 | 53 | @end 54 | 55 | @interface FMMosaicLayout : UICollectionViewLayout 56 | 57 | // Not used, just for backwards compatability 58 | @property (nonatomic, weak) id delegate; 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMMosaicCellView.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMMosaicCellView.m 3 | // FMMosaicLayout 4 | // 5 | // Created by Julian Villella on 2015-01-30. 6 | // Copyright (c) 2015 Fluid Media. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "FMMosaicCellView.h" 27 | 28 | static NSString* const kFMMosaicCellViewReuseIdentifier = @"FMMosaicCellViewReuseIdentifier"; 29 | 30 | @interface FMMosaicCellView () 31 | 32 | @property (weak, nonatomic) IBOutlet UIView *overlayView; 33 | 34 | @end 35 | 36 | @implementation FMMosaicCellView 37 | 38 | + (NSString *)reuseIdentifier { 39 | return kFMMosaicCellViewReuseIdentifier; 40 | } 41 | 42 | - (void)awakeFromNib { 43 | UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongPress:)]; 44 | longPressGesture.minimumPressDuration = 0.0; 45 | longPressGesture.delegate = self; 46 | longPressGesture.cancelsTouchesInView = NO; 47 | [self addGestureRecognizer:longPressGesture]; 48 | } 49 | 50 | - (void)onLongPress:(UILongPressGestureRecognizer *)longPressGestureRecognizer { 51 | if (longPressGestureRecognizer.state == UIGestureRecognizerStateBegan) { 52 | [UIView animateWithDuration:0.2 delay:0.0 usingSpringWithDamping:0.6 initialSpringVelocity:0.8 options:UIViewAnimationOptionCurveEaseOut animations:^{ 53 | self.transform = CGAffineTransformMakeScale(0.9, 0.9); 54 | self.overlayView.alpha = 0.35; 55 | } completion:nil]; 56 | 57 | } else { 58 | [UIView animateWithDuration:0.2 delay:0.0 usingSpringWithDamping:0.6 initialSpringVelocity:0.8 options:UIViewAnimationOptionCurveEaseOut animations:^{ 59 | self.transform = CGAffineTransformIdentity; 60 | self.overlayView.alpha = 0.0; 61 | } completion:nil]; 62 | } 63 | } 64 | 65 | - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { 66 | return YES; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout.xcodeproj/xcshareddata/xcschemes/FMMosaicLayout-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CI Status](http://img.shields.io/travis/JVillella/FMMosaicLayout.svg?style=flat)](https://travis-ci.org/JVillella/FMMosaicLayout) 2 | [![Version](https://img.shields.io/cocoapods/v/FMMosaicLayout.svg?style=flat)](http://cocoadocs.org/docsets/FMMosaicLayout) 3 | [![License](https://img.shields.io/cocoapods/l/FMMosaicLayout.svg?style=flat)](http://cocoadocs.org/docsets/FMMosaicLayout) 4 | [![Platform](https://img.shields.io/cocoapods/p/FMMosaicLayout.svg?style=flat)](http://cocoadocs.org/docsets/FMMosaicLayout) 5 | 6 | FMMosaicLayout is a mosiac collection view layout. There are a great number of media-based iOS applications that use `UICollectionViewFlowLayout` without any modifications. This lends itself to boring presentation, and unengaging interaction. FMMosaicLayout is a step in the right direction. Simply add this pod to your project, set your preferences and it will layout out your collection view cells in pretty mosaics. The algorithm behind this got its inspiration from this [blog post](http://blog.vjeux.com/2012/image/image-layout-algorithm-facebook.html). 7 | 8 | ![Portrait Screenshot](https://fmitech.github.io/FMMosaicLayout/Screenshots/portrait-3-small.png) 9 | 10 | ## Usage 11 | 12 | FMMosaicLayout is very easy to use. Below is all you need to get going. 13 | 14 | ```objective-c 15 | - (void)viewDidLoad { 16 | ... 17 | 18 | FMMosaicLayout *mosaicLayout = [[FMMosaicLayout alloc] init]; 19 | self.collectionView.collectionViewLayout = mosaicLayout; 20 | 21 | ... 22 | } 23 | 24 | #pragma mark 25 | 26 | - (NSInteger)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout 27 | numberOfColumnsInSection:(NSInteger)section { 28 | 29 | return 2; // Or any number of your choosing. 30 | } 31 | ``` 32 | 33 | It's also possible to set the layout via Interface Builder. To see a complete example implementation. Clone the repo, and run `pod install` from the Example directory. Then open up `Example/FMMosaicLayout.xcworkspace`. 34 | 35 | ## Customization 36 | 37 | In addition to the required protocol method `collectionView:layout:numberOfColumnsInSection:`, there are several optional methods you can implement from `FMMosaicLayoutDelegate`. You can see them in action in the example project. 38 | 39 | ##### Mosaic Cell Size 40 | 41 | ```objective-c 42 | - (FMMosaicCellSize)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout 43 | mosaicCellSizeForItemAtIndexPath:(NSIndexPath *)indexPath; 44 | ``` 45 | 46 | This allows you to specify when you want to place a large or small mosaic cell. 47 | 48 | ##### Section Insets 49 | ```objective-c 50 | - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout 51 | insetForSectionAtIndex:(NSInteger)section; 52 | ``` 53 | 54 | Here you can specify a custom `UIEdgeInsets` for each section. 55 | 56 | ##### Interitem Spacing 57 | 58 | ```objective-c 59 | - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout 60 | interitemSpacingForSectionAtIndex:(NSInteger)section; 61 | ``` 62 | 63 | Here you can specify the spacing between cells. 64 | 65 | ##### Header and Footer Support 66 | 67 | Below are the optional methods you can make use of to customize your headers and footers. The first methods are to set the height of your header/footers. 68 | 69 | ```objective-c 70 | - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout 71 | heightForHeaderInSection:(NSInteger)section; 72 | 73 | - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout 74 | heightForFooterInSection:(NSInteger)section; 75 | ``` 76 | 77 | If you want your header and/or to overlay your mosaic cells implement the following methods below in your delegate and have them return `YES`. The default is `NO`. 78 | 79 | ```objective-c 80 | - (BOOL)headerShouldOverlayContentInCollectionView:(UICollectionView *)collectionView 81 | layout:(FMMosaicLayout *)collectionViewLayout; 82 | 83 | - (BOOL)footerShouldOverlayContentInCollectionView:(UICollectionView *)collectionView 84 | layout:(FMMosaicLayout *)collectionViewLayout; 85 | ``` 86 | 87 | ## Installation 88 | 89 | FMMosaicLayout is available through [CocoaPods](http://cocoapods.org). To install 90 | it, simply add the following line to your Podfile: 91 | 92 | ```ruby 93 | pod "FMMosaicLayout" 94 | ``` 95 | 96 | ## License 97 | 98 | FMMosaicLayout is available under the MIT license. See the LICENSE file for more info. 99 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMFooterView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMHeaderView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/Base.lproj/Example.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout/FMMosaicCollectionViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMMosaicCollectionViewController.m 3 | // FMMosaicLayout 4 | // 5 | // Created by Julian Villella on 2015-01-30. 6 | // Copyright (c) 2015 Fluid Media. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "FMMosaicCollectionViewController.h" 27 | #import "FMMosaicCellView.h" 28 | #import "FMMosaicLayout.h" 29 | #import "FMHeaderView.h" 30 | #import "FMFooterView.h" 31 | 32 | static const CGFloat kFMHeaderFooterHeight = 44.0; 33 | static const NSInteger kFMMosaicColumnCount = 2; 34 | 35 | @interface FMMosaicCollectionViewController () 36 | 37 | @property (nonatomic, strong) NSArray *stockImages; 38 | 39 | @end 40 | 41 | @implementation FMMosaicCollectionViewController 42 | 43 | - (void)viewDidLoad { 44 | [super viewDidLoad]; 45 | self.collectionView.backgroundColor = [UIColor blackColor]; 46 | 47 | [self.collectionView registerNib:[UINib nibWithNibName:@"FMHeaderView" bundle:nil] 48 | forSupplementaryViewOfKind:UICollectionElementKindSectionHeader 49 | withReuseIdentifier:[FMHeaderView reuseIdentifier]]; 50 | 51 | [self.collectionView registerNib:[UINib nibWithNibName:@"FMFooterView" bundle:nil] 52 | forSupplementaryViewOfKind:UICollectionElementKindSectionFooter 53 | withReuseIdentifier:[FMFooterView reuseIdentifier]]; 54 | 55 | [self adjustContentInsets]; 56 | } 57 | 58 | - (void)adjustContentInsets { 59 | UIEdgeInsets insets = UIEdgeInsetsMake([UIApplication sharedApplication].statusBarFrame.size.height, 0, 0, 0); 60 | self.collectionView.contentInset = insets; 61 | self.collectionView.scrollIndicatorInsets = insets; 62 | } 63 | 64 | #pragma mark 65 | 66 | - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { 67 | return 3; 68 | } 69 | 70 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 71 | switch (section) { 72 | case 0: return 66; 73 | case 1: return 123; 74 | } 75 | return 31; 76 | } 77 | 78 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 79 | FMMosaicCellView *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[FMMosaicCellView reuseIdentifier] forIndexPath:indexPath]; 80 | 81 | // Configure the cell 82 | cell.titleLabel.text = [NSString stringWithFormat:@"%ld", (long)indexPath.item + 1]; 83 | cell.imageView.image = self.stockImages[indexPath.item % self.stockImages.count]; 84 | 85 | return cell; 86 | } 87 | 88 | - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView 89 | viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { 90 | 91 | UICollectionReusableView *reusableView = nil; 92 | if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { 93 | FMHeaderView *headerView = [self.collectionView dequeueReusableSupplementaryViewOfKind:kind 94 | withReuseIdentifier:[FMHeaderView reuseIdentifier] forIndexPath:indexPath]; 95 | 96 | headerView.titleLabel.text = [NSString stringWithFormat:@"SECTION %ld", (long)indexPath.section + 1]; 97 | reusableView = headerView; 98 | 99 | } else if([kind isEqualToString:UICollectionElementKindSectionFooter]) { 100 | FMFooterView *footerView = [self.collectionView dequeueReusableSupplementaryViewOfKind:kind 101 | withReuseIdentifier:[FMFooterView reuseIdentifier] forIndexPath:indexPath]; 102 | 103 | NSInteger assetCount = [self collectionView:self.collectionView numberOfItemsInSection:indexPath.section]; 104 | footerView.titleLabel.text = assetCount == 1 ? @"1 ASSET" : [NSString stringWithFormat:@"%ld ASSETS", (long)assetCount]; 105 | reusableView = footerView; 106 | } 107 | 108 | return reusableView; 109 | } 110 | 111 | #pragma mark 112 | 113 | - (NSInteger)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout 114 | numberOfColumnsInSection:(NSInteger)section { 115 | return kFMMosaicColumnCount; 116 | } 117 | 118 | - (FMMosaicCellSize)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout 119 | mosaicCellSizeForItemAtIndexPath:(NSIndexPath *)indexPath { 120 | return (indexPath.item % 12 == 0) ? FMMosaicCellSizeBig : FMMosaicCellSizeSmall; 121 | } 122 | 123 | - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout 124 | insetForSectionAtIndex:(NSInteger)section { 125 | return UIEdgeInsetsMake(5.0, 5.0, 5.0, 5.0); 126 | } 127 | 128 | - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout 129 | interitemSpacingForSectionAtIndex:(NSInteger)section { 130 | return 2.0; 131 | } 132 | 133 | - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout 134 | heightForHeaderInSection:(NSInteger)section { 135 | return kFMHeaderFooterHeight; 136 | } 137 | 138 | - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout 139 | heightForFooterInSection:(NSInteger)section { 140 | return kFMHeaderFooterHeight; 141 | } 142 | 143 | - (BOOL)headerShouldOverlayContentInCollectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout { 144 | return YES; 145 | } 146 | 147 | - (BOOL)footerShouldOverlayContentInCollectionView:(UICollectionView *)collectionView layout:(FMMosaicLayout *)collectionViewLayout { 148 | return YES; 149 | } 150 | 151 | #pragma mark - Accessors 152 | 153 | - (NSArray *)stockImages { 154 | if (!_stockImages) { 155 | _stockImages = @[ 156 | [UIImage imageNamed:@"back"], 157 | [UIImage imageNamed:@"balcony"], 158 | [UIImage imageNamed:@"birds"], 159 | [UIImage imageNamed:@"bridge"], 160 | [UIImage imageNamed:@"ceiling"], 161 | [UIImage imageNamed:@"city"], 162 | [UIImage imageNamed:@"cityscape"], 163 | [UIImage imageNamed:@"game"], 164 | [UIImage imageNamed:@"leaves"], 165 | [UIImage imageNamed:@"mountain-tops"], 166 | [UIImage imageNamed:@"mountains"], 167 | [UIImage imageNamed:@"sitting"], 168 | [UIImage imageNamed:@"snowy-mountains"], 169 | [UIImage imageNamed:@"stars"], 170 | [UIImage imageNamed:@"stream"], 171 | [UIImage imageNamed:@"sunset"], 172 | [UIImage imageNamed:@"two-birds"], 173 | [UIImage imageNamed:@"waves"] 174 | ]; 175 | } 176 | return _stockImages; 177 | } 178 | 179 | #pragma mark - Status Bar 180 | 181 | - (UIStatusBarStyle)preferredStatusBarStyle { 182 | return UIStatusBarStyleLightContent; 183 | } 184 | 185 | @end 186 | -------------------------------------------------------------------------------- /Pod/Classes/FMMosaicLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMMosaicLayout.m 3 | // FMMosaicLayout 4 | // 5 | // Created by Julian Villella on 2015-01-30. 6 | // Copyright (c) 2015 Fluid Media. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "FMMosaicLayout.h" 27 | 28 | static const NSInteger kFMDefaultNumberOfColumnsInSection = 2; 29 | static const FMMosaicCellSize kFMDefaultCellSize = FMMosaicCellSizeSmall; 30 | static const FMMosaicCellSize kFMDefaultHeaderFooterHeight = 0.0; 31 | static const BOOL kFMDefaultHeaderShouldOverlayContent = NO; 32 | static const BOOL kFMDefaultFooterShouldOverlayContent = NO; 33 | 34 | @interface FMMosaicLayout () 35 | 36 | /** 37 | * A 2D array holding an array of columns heights for each section 38 | */ 39 | @property (nonatomic, strong) NSMutableArray *columnHeightsPerSection; 40 | 41 | /** 42 | * Array of cached layout attributes for each cell 43 | */ 44 | @property (nonatomic, strong) NSMutableDictionary *cellLayoutAttributes; 45 | 46 | /** 47 | * Array of cached layout attributes for each supplementary view (only headers and footer kinds are currently supported) 48 | */ 49 | @property (nonatomic, strong) NSMutableDictionary *supplementaryLayoutAttributes; 50 | 51 | @end 52 | 53 | @implementation FMMosaicLayout 54 | 55 | - (void)prepareLayout { 56 | [super prepareLayout]; 57 | 58 | [self resetLayoutState]; 59 | 60 | // Calculate layout attritbutes in each section 61 | for (NSInteger sectionIndex = 0; sectionIndex < [self.collectionView numberOfSections]; sectionIndex++) { 62 | 63 | CGFloat interitemSpacing = [self interitemSpacingAtSection:sectionIndex]; 64 | 65 | // Add top section insets 66 | [self growColumnHeightsBy:[self insetForSectionAtIndex:sectionIndex].top section:sectionIndex]; 67 | 68 | // Adds header view 69 | UICollectionViewLayoutAttributes *headerLayoutAttribute = 70 | [self addLayoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader 71 | indexPath:[NSIndexPath indexPathForItem:0 inSection:sectionIndex]]; 72 | 73 | if (![self headerShouldOverlayContent]) { 74 | [self growColumnHeightsBy:headerLayoutAttribute.frame.size.height + interitemSpacing section:sectionIndex]; 75 | } 76 | 77 | // Calculate cell attributes in each section 78 | NSMutableArray *smallMosaicCellIndexPathsBuffer = [[NSMutableArray alloc] initWithCapacity:2]; 79 | for (NSInteger cellIndex = 0; cellIndex < [self.collectionView numberOfItemsInSection:sectionIndex]; cellIndex++) { 80 | 81 | NSIndexPath *cellIndexPath = [NSIndexPath indexPathForItem:cellIndex inSection:sectionIndex]; 82 | FMMosaicCellSize mosaicCellSize = [self mosaicCellSizeForItemAtIndexPath:cellIndexPath]; 83 | NSInteger indexOfShortestColumn = [self indexOfShortestColumnInSection:sectionIndex]; // must be recalculated every time a new cell is added 84 | 85 | if (mosaicCellSize == FMMosaicCellSizeBig) { 86 | // Add big cell to shortest column, calculate layout attributes, and recalculate column height now that it's been added 87 | UICollectionViewLayoutAttributes *layoutAttributes = [self addBigMosaicLayoutAttributesForIndexPath:cellIndexPath inColumn:indexOfShortestColumn]; 88 | CGFloat columnHeight = [self.columnHeightsPerSection[sectionIndex][indexOfShortestColumn] floatValue]; 89 | self.columnHeightsPerSection[sectionIndex][indexOfShortestColumn] = @(columnHeight + layoutAttributes.frame.size.height + interitemSpacing); 90 | 91 | } else if(mosaicCellSize == FMMosaicCellSizeSmall) { 92 | [smallMosaicCellIndexPathsBuffer addObject:cellIndexPath]; 93 | 94 | // Wait until small cell buffer is full (widths add up to one big cell), then add small cells to column heights array and layout attributes 95 | if(smallMosaicCellIndexPathsBuffer.count >= 2) { 96 | UICollectionViewLayoutAttributes *layoutAttributes = [self addSmallMosaicLayoutAttributesForIndexPath:smallMosaicCellIndexPathsBuffer[0] 97 | inColumn:indexOfShortestColumn bufferIndex:0]; 98 | [self addSmallMosaicLayoutAttributesForIndexPath:smallMosaicCellIndexPathsBuffer[1] inColumn:indexOfShortestColumn bufferIndex:1]; 99 | 100 | // Add to small cells to shortest column, and recalculate column height now that they've been added 101 | CGFloat columnHeight = [self.columnHeightsPerSection[sectionIndex][indexOfShortestColumn] floatValue]; 102 | self.columnHeightsPerSection[sectionIndex][indexOfShortestColumn] = @(columnHeight + layoutAttributes.frame.size.height + interitemSpacing); 103 | [smallMosaicCellIndexPathsBuffer removeAllObjects]; 104 | } 105 | } 106 | } 107 | 108 | // Handle remaining cells that didn't fill the buffer 109 | if (smallMosaicCellIndexPathsBuffer.count > 0) { 110 | NSInteger indexOfShortestColumn = [self indexOfShortestColumnInSection:sectionIndex]; 111 | UICollectionViewLayoutAttributes *layoutAttributes = [self addSmallMosaicLayoutAttributesForIndexPath:smallMosaicCellIndexPathsBuffer[0] 112 | inColumn:indexOfShortestColumn bufferIndex:0]; 113 | 114 | // Add to small cells to shortest column, and recalculate column height now that they've been added 115 | CGFloat columnHeight = [self.columnHeightsPerSection[sectionIndex][indexOfShortestColumn] floatValue]; 116 | self.columnHeightsPerSection[sectionIndex][indexOfShortestColumn] = @(columnHeight + layoutAttributes.frame.size.height + interitemSpacing); 117 | [smallMosaicCellIndexPathsBuffer removeAllObjects]; 118 | } 119 | 120 | // Adds footer view 121 | UICollectionViewLayoutAttributes *footerLayoutAttribute = 122 | [self addLayoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter 123 | indexPath:[NSIndexPath indexPathForItem:1 inSection:sectionIndex]]; 124 | 125 | if (![self footerShouldOverlayContent]) { 126 | [self growColumnHeightsBy:footerLayoutAttribute.frame.size.height section:sectionIndex]; 127 | } 128 | 129 | // Add bottom section insets, and remove extra added inset 130 | [self growColumnHeightsBy:[self insetForSectionAtIndex:sectionIndex].bottom section:sectionIndex]; 131 | } 132 | } 133 | 134 | // Calculate and return all layout attributes in a given rect 135 | - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { 136 | NSMutableArray *attributesInRect = [[NSMutableArray alloc] initWithCapacity:self.cellLayoutAttributes.count]; 137 | 138 | // Cells 139 | [self.cellLayoutAttributes enumerateKeysAndObjectsUsingBlock:^(NSIndexPath *indexPath, UICollectionViewLayoutAttributes *attributes, BOOL *stop) { 140 | if(CGRectIntersectsRect(rect, attributes.frame)){ 141 | [attributesInRect addObject:attributes]; 142 | } 143 | }]; 144 | 145 | // Supplementary views 146 | [self.supplementaryLayoutAttributes enumerateKeysAndObjectsUsingBlock:^(NSIndexPath *indexPath, UICollectionViewLayoutAttributes *attributes, BOOL *stop) { 147 | if(CGRectIntersectsRect(rect, attributes.frame)){ 148 | [attributesInRect addObject:attributes]; 149 | } 150 | }]; 151 | 152 | return attributesInRect; 153 | } 154 | 155 | - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { 156 | return [self.cellLayoutAttributes objectForKey:indexPath]; 157 | } 158 | 159 | - (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath { 160 | return [self.supplementaryLayoutAttributes objectForKey:indexPath]; 161 | } 162 | 163 | // Content size is the width of the collection view, and the height of all sections combined 164 | - (CGSize)collectionViewContentSize { 165 | CGFloat width = [self collectionViewContentWidth]; 166 | __block CGFloat height = 0.0; 167 | 168 | [self.columnHeightsPerSection enumerateObjectsUsingBlock:^(NSArray *columnHeights, NSUInteger sectionIndex, BOOL *stop) { 169 | NSInteger indexOfTallestColumn = [self indexOfTallestColumnInSection:sectionIndex]; 170 | height += [columnHeights[indexOfTallestColumn] floatValue]; 171 | }]; 172 | 173 | return CGSizeMake(width, height); 174 | } 175 | 176 | - (CGFloat)collectionViewContentWidth { 177 | return self.collectionView.bounds.size.width; 178 | } 179 | 180 | #pragma mark - Orientation 181 | 182 | - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { 183 | CGRect oldBounds = self.collectionView.bounds; 184 | 185 | // Invalidate if the bounds has changed 186 | if (!CGSizeEqualToSize(oldBounds.size, newBounds.size)) { 187 | [self prepareLayout]; 188 | return YES; 189 | } 190 | return NO; 191 | } 192 | 193 | - (void)resetLayoutState { 194 | [self.columnHeightsPerSection removeAllObjects]; 195 | _columnHeightsPerSection = nil; 196 | 197 | [self.cellLayoutAttributes removeAllObjects]; 198 | _cellLayoutAttributes = nil; 199 | 200 | [self.supplementaryLayoutAttributes removeAllObjects]; 201 | _supplementaryLayoutAttributes = nil; 202 | } 203 | 204 | #pragma mark - Accessors 205 | 206 | - (NSArray *)columnHeightsPerSection { 207 | if (!_columnHeightsPerSection) { 208 | NSInteger sectionCount = [self.collectionView numberOfSections]; 209 | _columnHeightsPerSection = [[NSMutableArray alloc] initWithCapacity:sectionCount]; 210 | 211 | for (NSInteger sectionIndex = 0; sectionIndex < sectionCount; sectionIndex++) { 212 | NSInteger numberOfColumnsInSection = [self numberOfColumnsInSection:sectionIndex]; 213 | NSMutableArray *columnHeights = [[NSMutableArray alloc] initWithCapacity:numberOfColumnsInSection]; 214 | 215 | for (NSInteger columnIndex = 0; columnIndex < numberOfColumnsInSection; columnIndex++) { 216 | [columnHeights addObject:@0]; 217 | } 218 | 219 | [_columnHeightsPerSection addObject:columnHeights]; 220 | } 221 | } 222 | 223 | return _columnHeightsPerSection; 224 | } 225 | 226 | - (NSMutableDictionary *)cellLayoutAttributes { 227 | if (!_cellLayoutAttributes) { 228 | _cellLayoutAttributes = [[NSMutableDictionary alloc] init]; 229 | } 230 | return _cellLayoutAttributes; 231 | } 232 | 233 | - (NSMutableDictionary *)supplementaryLayoutAttributes { 234 | if (!_supplementaryLayoutAttributes) { 235 | _supplementaryLayoutAttributes = [[NSMutableDictionary alloc] init]; 236 | } 237 | return _supplementaryLayoutAttributes; 238 | } 239 | 240 | #pragma mark - Helpers 241 | 242 | #pragma mark Layout Attributes Helpers 243 | 244 | // Calculates layout attributes for a small cell, adds to layout attributes array and returns it 245 | - (UICollectionViewLayoutAttributes *)addSmallMosaicLayoutAttributesForIndexPath:(NSIndexPath *)cellIndexPath 246 | inColumn:(NSInteger)column bufferIndex:(NSInteger)bufferIndex { 247 | UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:cellIndexPath]; 248 | CGRect frame = [self mosaicCellRectWithSize:FMMosaicCellSizeSmall atIndexPath:cellIndexPath inColumn:column]; 249 | 250 | // Account for first or second small mosaic cell 251 | CGFloat interitemSpacing = [self interitemSpacingAtSection:cellIndexPath.section]; 252 | CGFloat cellWidth = [self cellHeightForMosaicSize:FMMosaicCellSizeSmall section:cellIndexPath.section]; 253 | frame.origin.x += (cellWidth + interitemSpacing) * bufferIndex; 254 | layoutAttributes.frame = frame; 255 | 256 | [self.cellLayoutAttributes setObject:layoutAttributes forKey:cellIndexPath]; 257 | 258 | return layoutAttributes; 259 | } 260 | 261 | // Calculates layout attributes for a big cell, adds to layout attributes array and returns it 262 | - (UICollectionViewLayoutAttributes *)addBigMosaicLayoutAttributesForIndexPath:(NSIndexPath *)cellIndexPath inColumn:(NSInteger)column { 263 | UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:cellIndexPath]; 264 | CGRect frame = [self mosaicCellRectWithSize:FMMosaicCellSizeBig atIndexPath:cellIndexPath inColumn:column]; 265 | layoutAttributes.frame = frame; 266 | 267 | [self.cellLayoutAttributes setObject:layoutAttributes forKey:cellIndexPath]; 268 | 269 | return layoutAttributes; 270 | } 271 | 272 | - (CGRect)mosaicCellRectWithSize:(FMMosaicCellSize)mosaicCellSize atIndexPath:(NSIndexPath *)cellIndexPath inColumn:(NSInteger)column { 273 | NSInteger sectionIndex = cellIndexPath.section; 274 | 275 | CGFloat cellHeight = [self cellHeightForMosaicSize:mosaicCellSize section:sectionIndex]; 276 | CGFloat cellWidth = cellHeight; 277 | CGFloat columnHeight = [self.columnHeightsPerSection[sectionIndex][column] floatValue]; 278 | 279 | CGFloat originX = column * [self columnWidthInSection:sectionIndex]; 280 | CGFloat originY = [self verticalOffsetForSection:sectionIndex] + columnHeight; 281 | 282 | // Factor in interitem spacing and insets 283 | UIEdgeInsets sectionInset = [self insetForSectionAtIndex:sectionIndex]; 284 | CGFloat interitemSpacing = [self interitemSpacingAtSection:sectionIndex]; 285 | originX += sectionInset.left; 286 | originX += column * interitemSpacing; 287 | 288 | return CGRectMake(originX, originY, cellWidth, cellHeight); 289 | } 290 | 291 | - (UICollectionViewLayoutAttributes *)addLayoutAttributesForSupplementaryViewOfKind:(NSString *)kind indexPath:(NSIndexPath *)indexPath { 292 | UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:kind withIndexPath:indexPath]; 293 | 294 | UIEdgeInsets sectionInset = [self insetForSectionAtIndex:indexPath.section]; 295 | CGFloat originX = sectionInset.left; 296 | CGFloat originY = [self verticalOffsetForSection:indexPath.section]; 297 | CGFloat width = [self collectionViewContentWidth] - sectionInset.left - sectionInset.right; 298 | CGFloat height = 0.0; 299 | 300 | if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { 301 | height = [self heightForHeaderAtSection:indexPath.section]; 302 | 303 | } else if([kind isEqualToString:UICollectionElementKindSectionFooter]) { 304 | height = [self heightForFooterAtSection:indexPath.section]; 305 | if ([self footerShouldOverlayContent]) { 306 | originY -= height; 307 | } 308 | } 309 | 310 | NSInteger tallestColumnIndex = [self indexOfTallestColumnInSection:indexPath.section]; 311 | CGFloat sectionColumnHeight = [self.columnHeightsPerSection[indexPath.section][tallestColumnIndex] floatValue]; 312 | 313 | layoutAttributes.frame = CGRectMake(originX, sectionColumnHeight + originY, width, height); 314 | layoutAttributes.zIndex = 1; 315 | 316 | [self.supplementaryLayoutAttributes setObject:layoutAttributes forKey:indexPath]; 317 | 318 | return layoutAttributes; 319 | } 320 | 321 | #pragma mark Sizing Helpers 322 | 323 | - (CGFloat)cellHeightForMosaicSize:(FMMosaicCellSize)mosaicCellSize section:(NSInteger)section { 324 | CGFloat bigCellSize = [self columnWidthInSection:section]; 325 | CGFloat interitemSpacing = [self interitemSpacingAtSection:section]; 326 | return mosaicCellSize == FMMosaicCellSizeBig ? bigCellSize : (bigCellSize - interitemSpacing) / 2.0; 327 | } 328 | 329 | // The width of a column refers to the width of one FMMosaicCellSizeBig cell w/o interitem spacing 330 | - (CGFloat)columnWidthInSection:(NSInteger)section { 331 | UIEdgeInsets sectionInset = [self insetForSectionAtIndex:section]; 332 | CGFloat combinedInteritemSpacing = ([self numberOfColumnsInSection:section] - 1) * [self interitemSpacingAtSection:section]; 333 | CGFloat combinedColumnWidth = [self collectionViewContentWidth] - sectionInset.left - sectionInset.right - combinedInteritemSpacing; 334 | 335 | return combinedColumnWidth / [self numberOfColumnsInSection:section]; 336 | } 337 | 338 | // The vertical position where this section begins 339 | - (CGFloat)verticalOffsetForSection:(NSInteger)section { 340 | CGFloat verticalOffset = 0.0; 341 | 342 | // Add up heights of all previous sections to get vertical position of this section 343 | for (NSInteger i = 0; i < section; i++) { 344 | NSInteger indexOfTallestColumn = [self indexOfTallestColumnInSection:i]; 345 | CGFloat sectionHeight = [self.columnHeightsPerSection[i][indexOfTallestColumn] floatValue]; 346 | verticalOffset += sectionHeight; 347 | } 348 | 349 | return verticalOffset; 350 | } 351 | 352 | - (void)growColumnHeightsBy:(CGFloat)increase section:(NSInteger)section { 353 | NSMutableArray *columnHeights = [self.columnHeightsPerSection objectAtIndex:section]; 354 | 355 | for (int i = 0; i < columnHeights.count; i++) { 356 | columnHeights[i] = @([columnHeights[i] floatValue] + increase); 357 | } 358 | } 359 | 360 | #pragma mark Index Helpers 361 | 362 | - (NSInteger)indexOfShortestColumnInSection:(NSInteger)section { 363 | NSArray *columnHeights = [self.columnHeightsPerSection objectAtIndex:section]; 364 | 365 | NSInteger indexOfShortestColumn = 0; 366 | for (int i = 1; i < columnHeights.count; i++) { 367 | if([columnHeights[i] floatValue] < [columnHeights[indexOfShortestColumn] floatValue]) 368 | indexOfShortestColumn = i; 369 | } 370 | 371 | return indexOfShortestColumn; 372 | } 373 | 374 | - (NSInteger)indexOfTallestColumnInSection:(NSInteger)section { 375 | NSArray *columnHeights = [self.columnHeightsPerSection objectAtIndex:section]; 376 | 377 | NSInteger indexOfTallestColumn = 0; 378 | for (int i = 1; i < columnHeights.count; i++) { 379 | if([columnHeights[i] floatValue] > [columnHeights[indexOfTallestColumn] floatValue]) 380 | indexOfTallestColumn = i; 381 | } 382 | 383 | return indexOfTallestColumn; 384 | } 385 | 386 | #pragma mark - Delegate Wrappers 387 | 388 | - (NSInteger)numberOfColumnsInSection:(NSInteger)section { 389 | NSInteger columnCount = kFMDefaultNumberOfColumnsInSection; 390 | if ([self.delegate respondsToSelector:@selector(collectionView:layout:numberOfColumnsInSection:)]) { 391 | columnCount = [self.delegate collectionView:self.collectionView layout:self numberOfColumnsInSection:section]; 392 | } 393 | return columnCount; 394 | } 395 | 396 | - (FMMosaicCellSize)mosaicCellSizeForItemAtIndexPath:(NSIndexPath *)indexPath { 397 | FMMosaicCellSize cellSize = kFMDefaultCellSize; 398 | if ([self.delegate respondsToSelector:@selector(collectionView:layout:mosaicCellSizeForItemAtIndexPath:)]) { 399 | cellSize = [self.delegate collectionView:self.collectionView layout:self mosaicCellSizeForItemAtIndexPath:indexPath]; 400 | } 401 | return cellSize; 402 | } 403 | 404 | - (UIEdgeInsets)insetForSectionAtIndex:(NSInteger)section { 405 | UIEdgeInsets inset = UIEdgeInsetsZero; 406 | if ([self.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) { 407 | inset = [self.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:section]; 408 | } 409 | return inset; 410 | } 411 | 412 | - (CGFloat)interitemSpacingAtSection:(NSInteger)section { 413 | CGFloat interitemSpacing = 0.0; 414 | if ([self.delegate respondsToSelector:@selector(collectionView:layout:interitemSpacingForSectionAtIndex:)]) { 415 | interitemSpacing = [self.delegate collectionView:self.collectionView layout:self interitemSpacingForSectionAtIndex:section]; 416 | } 417 | return interitemSpacing; 418 | } 419 | 420 | - (CGFloat)heightForHeaderAtSection:(NSInteger)section { 421 | CGFloat height = kFMDefaultHeaderFooterHeight; 422 | if ([self.delegate respondsToSelector:@selector(collectionView:layout:heightForHeaderInSection:)]) { 423 | height = [self.delegate collectionView:self.collectionView layout:self heightForHeaderInSection:section]; 424 | } 425 | return height; 426 | } 427 | 428 | - (CGFloat)heightForFooterAtSection:(NSInteger)section { 429 | CGFloat height = kFMDefaultHeaderFooterHeight; 430 | if ([self.delegate respondsToSelector:@selector(collectionView:layout:heightForFooterInSection:)]) { 431 | height = [self.delegate collectionView:self.collectionView layout:self heightForFooterInSection:section]; 432 | } 433 | return height; 434 | } 435 | 436 | - (BOOL)headerShouldOverlayContent { 437 | CGFloat shouldOverlay = kFMDefaultHeaderShouldOverlayContent; 438 | if ([self.delegate respondsToSelector:@selector(headerShouldOverlayContentInCollectionView:layout:)]) { 439 | shouldOverlay = [self.delegate headerShouldOverlayContentInCollectionView:self.collectionView layout:self]; 440 | } 441 | return shouldOverlay; 442 | } 443 | 444 | - (BOOL)footerShouldOverlayContent { 445 | CGFloat shouldOverlay = kFMDefaultFooterShouldOverlayContent; 446 | if ([self.delegate respondsToSelector:@selector(footerShouldOverlayContentInCollectionView:layout:)]) { 447 | shouldOverlay = [self.delegate footerShouldOverlayContentInCollectionView:self.collectionView layout:self]; 448 | } 449 | return shouldOverlay; 450 | } 451 | 452 | // If layout delegate hasn't been provided, resort to collection view's delegate which is likely a UICollectionViewController 453 | - (id)delegate { 454 | return _delegate ? _delegate : (id)self.collectionView.delegate; 455 | } 456 | 457 | @end 458 | -------------------------------------------------------------------------------- /Example/FMMosaicLayout.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 16C68EBB823B4316E125CD70 /* libPods-Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AF23CF08D3EBDE40465A3363 /* libPods-Tests.a */; }; 11 | 4C5D8598233836885FB6D374 /* libPods-FMMosaicLayout.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E88784FB63092BC5C3699361 /* libPods-FMMosaicLayout.a */; }; 12 | 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; 13 | 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; }; 14 | 6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; 15 | 6003F598195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F596195388D20070C39A /* InfoPlist.strings */; }; 16 | 6003F5A9195388D20070C39A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5A8195388D20070C39A /* Images.xcassets */; }; 17 | 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; }; 18 | 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; 19 | 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; 20 | 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; }; 21 | 6003F5BC195388D20070C39A /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5BB195388D20070C39A /* Tests.m */; }; 22 | B952EA111ACC380700A979A6 /* FMFooterView.m in Sources */ = {isa = PBXBuildFile; fileRef = B952EA0F1ACC380700A979A6 /* FMFooterView.m */; }; 23 | B952EA161ACC382600A979A6 /* FMHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = B952EA141ACC382600A979A6 /* FMHeaderView.m */; }; 24 | B96097921AD4342D00EBD79A /* FMFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B96097901AD4342D00EBD79A /* FMFooterView.xib */; }; 25 | B96097931AD4342D00EBD79A /* FMHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B96097911AD4342D00EBD79A /* FMHeaderView.xib */; }; 26 | B986BA221A8A5F6000E4584D /* FMAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B986BA1E1A8A5F6000E4584D /* FMAppDelegate.m */; }; 27 | B986BA231A8A5F6000E4584D /* FMMosaicCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = B986BA1F1A8A5F6000E4584D /* FMMosaicCellView.m */; }; 28 | B986BA241A8A5F6000E4584D /* FMMosaicCollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B986BA201A8A5F6000E4584D /* FMMosaicCollectionViewController.m */; }; 29 | B986BA251A8A5F6000E4584D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B986BA211A8A5F6000E4584D /* main.m */; }; 30 | B986BA2A1A8A5F7D00E4584D /* Example.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B986BA261A8A5F7D00E4584D /* Example.storyboard */; }; 31 | B986BA2B1A8A5F7D00E4584D /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = B986BA281A8A5F7D00E4584D /* LaunchScreen.xib */; }; 32 | /* End PBXBuildFile section */ 33 | 34 | /* Begin PBXContainerItemProxy section */ 35 | 6003F5B3195388D20070C39A /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = 6003F582195388D10070C39A /* Project object */; 38 | proxyType = 1; 39 | remoteGlobalIDString = 6003F589195388D20070C39A; 40 | remoteInfo = FMMosaicLayout; 41 | }; 42 | /* End PBXContainerItemProxy section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 0E432239394A4D76C39CDD75 /* FMMosaicLayout.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = FMMosaicLayout.podspec; path = ../FMMosaicLayout.podspec; sourceTree = ""; }; 46 | 18DE6644CFE566A04570A623 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 47 | 271B5DC9EE27D3AF67E31CC1 /* Pods-Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.release.xcconfig"; sourceTree = ""; }; 48 | 564285136DBFDA264B2EA590 /* Pods-FMMosaicLayout.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FMMosaicLayout.release.xcconfig"; path = "Pods/Target Support Files/Pods-FMMosaicLayout/Pods-FMMosaicLayout.release.xcconfig"; sourceTree = ""; }; 49 | 57344976FD9A706AF9A5C0F6 /* Pods-Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.debug.xcconfig"; sourceTree = ""; }; 50 | 6003F58A195388D20070C39A /* FMMosaicLayout.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FMMosaicLayout.app; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 52 | 6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 53 | 6003F591195388D20070C39A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 54 | 6003F595195388D20070C39A /* FMMosaicLayout-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "FMMosaicLayout-Info.plist"; sourceTree = ""; }; 55 | 6003F597195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 56 | 6003F599195388D20070C39A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 57 | 6003F59B195388D20070C39A /* FMMosaicLayout-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FMMosaicLayout-Prefix.pch"; sourceTree = ""; }; 58 | 6003F59C195388D20070C39A /* FMAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FMAppDelegate.h; sourceTree = ""; }; 59 | 6003F5A8195388D20070C39A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 60 | 6003F5AE195388D20070C39A /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | 6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 62 | 6003F5B7195388D20070C39A /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = ""; }; 63 | 6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 64 | 6003F5BB195388D20070C39A /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = ""; }; 65 | 606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = ""; }; 66 | 7605C3CD52D024CD64BFE751 /* Pods-FMMosaicLayout.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FMMosaicLayout.debug.xcconfig"; path = "Pods/Target Support Files/Pods-FMMosaicLayout/Pods-FMMosaicLayout.debug.xcconfig"; sourceTree = ""; }; 67 | 7CBBF3E3E5CC0B3DEF0EB910 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 68 | AF23CF08D3EBDE40465A3363 /* libPods-Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 69 | B952EA0E1ACC380700A979A6 /* FMFooterView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FMFooterView.h; sourceTree = ""; }; 70 | B952EA0F1ACC380700A979A6 /* FMFooterView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FMFooterView.m; sourceTree = ""; }; 71 | B952EA131ACC382600A979A6 /* FMHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FMHeaderView.h; sourceTree = ""; }; 72 | B952EA141ACC382600A979A6 /* FMHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FMHeaderView.m; sourceTree = ""; }; 73 | B96097901AD4342D00EBD79A /* FMFooterView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FMFooterView.xib; sourceTree = ""; }; 74 | B96097911AD4342D00EBD79A /* FMHeaderView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FMHeaderView.xib; sourceTree = ""; }; 75 | B986BA1E1A8A5F6000E4584D /* FMAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FMAppDelegate.m; sourceTree = ""; }; 76 | B986BA1F1A8A5F6000E4584D /* FMMosaicCellView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FMMosaicCellView.m; sourceTree = ""; }; 77 | B986BA201A8A5F6000E4584D /* FMMosaicCollectionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FMMosaicCollectionViewController.m; sourceTree = ""; }; 78 | B986BA211A8A5F6000E4584D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 79 | B986BA271A8A5F7D00E4584D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Example.storyboard; sourceTree = ""; }; 80 | B986BA291A8A5F7D00E4584D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 81 | B986BA351A8A65AD00E4584D /* FMMosaicCellView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FMMosaicCellView.h; sourceTree = ""; }; 82 | B986BA361A8A65AD00E4584D /* FMMosaicCollectionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FMMosaicCollectionViewController.h; sourceTree = ""; }; 83 | E88784FB63092BC5C3699361 /* libPods-FMMosaicLayout.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FMMosaicLayout.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 84 | /* End PBXFileReference section */ 85 | 86 | /* Begin PBXFrameworksBuildPhase section */ 87 | 6003F587195388D20070C39A /* Frameworks */ = { 88 | isa = PBXFrameworksBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */, 92 | 6003F592195388D20070C39A /* UIKit.framework in Frameworks */, 93 | 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */, 94 | 4C5D8598233836885FB6D374 /* libPods-FMMosaicLayout.a in Frameworks */, 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | 6003F5AB195388D20070C39A /* Frameworks */ = { 99 | isa = PBXFrameworksBuildPhase; 100 | buildActionMask = 2147483647; 101 | files = ( 102 | 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */, 103 | 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */, 104 | 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */, 105 | 16C68EBB823B4316E125CD70 /* libPods-Tests.a in Frameworks */, 106 | ); 107 | runOnlyForDeploymentPostprocessing = 0; 108 | }; 109 | /* End PBXFrameworksBuildPhase section */ 110 | 111 | /* Begin PBXGroup section */ 112 | 3C0722103454B1CA2A6B151F /* Pods */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 7605C3CD52D024CD64BFE751 /* Pods-FMMosaicLayout.debug.xcconfig */, 116 | 564285136DBFDA264B2EA590 /* Pods-FMMosaicLayout.release.xcconfig */, 117 | 57344976FD9A706AF9A5C0F6 /* Pods-Tests.debug.xcconfig */, 118 | 271B5DC9EE27D3AF67E31CC1 /* Pods-Tests.release.xcconfig */, 119 | ); 120 | name = Pods; 121 | sourceTree = ""; 122 | }; 123 | 6003F581195388D10070C39A = { 124 | isa = PBXGroup; 125 | children = ( 126 | 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */, 127 | 6003F593195388D20070C39A /* FMMosaicLayout */, 128 | 6003F5B5195388D20070C39A /* Tests */, 129 | 6003F58C195388D20070C39A /* Frameworks */, 130 | 6003F58B195388D20070C39A /* Products */, 131 | 3C0722103454B1CA2A6B151F /* Pods */, 132 | ); 133 | sourceTree = ""; 134 | }; 135 | 6003F58B195388D20070C39A /* Products */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 6003F58A195388D20070C39A /* FMMosaicLayout.app */, 139 | 6003F5AE195388D20070C39A /* Tests.xctest */, 140 | ); 141 | name = Products; 142 | sourceTree = ""; 143 | }; 144 | 6003F58C195388D20070C39A /* Frameworks */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 6003F58D195388D20070C39A /* Foundation.framework */, 148 | 6003F58F195388D20070C39A /* CoreGraphics.framework */, 149 | 6003F591195388D20070C39A /* UIKit.framework */, 150 | 6003F5AF195388D20070C39A /* XCTest.framework */, 151 | E88784FB63092BC5C3699361 /* libPods-FMMosaicLayout.a */, 152 | AF23CF08D3EBDE40465A3363 /* libPods-Tests.a */, 153 | ); 154 | name = Frameworks; 155 | sourceTree = ""; 156 | }; 157 | 6003F593195388D20070C39A /* FMMosaicLayout */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | B952EA181ACC386B00A979A6 /* Cells */, 161 | B986BA361A8A65AD00E4584D /* FMMosaicCollectionViewController.h */, 162 | B986BA201A8A5F6000E4584D /* FMMosaicCollectionViewController.m */, 163 | B986BA211A8A5F6000E4584D /* main.m */, 164 | 6003F59C195388D20070C39A /* FMAppDelegate.h */, 165 | B986BA1E1A8A5F6000E4584D /* FMAppDelegate.m */, 166 | B986BA261A8A5F7D00E4584D /* Example.storyboard */, 167 | B986BA281A8A5F7D00E4584D /* LaunchScreen.xib */, 168 | 6003F5A8195388D20070C39A /* Images.xcassets */, 169 | 6003F594195388D20070C39A /* Supporting Files */, 170 | ); 171 | path = FMMosaicLayout; 172 | sourceTree = ""; 173 | }; 174 | 6003F594195388D20070C39A /* Supporting Files */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | 6003F595195388D20070C39A /* FMMosaicLayout-Info.plist */, 178 | 6003F596195388D20070C39A /* InfoPlist.strings */, 179 | 6003F599195388D20070C39A /* main.m */, 180 | 6003F59B195388D20070C39A /* FMMosaicLayout-Prefix.pch */, 181 | ); 182 | name = "Supporting Files"; 183 | sourceTree = ""; 184 | }; 185 | 6003F5B5195388D20070C39A /* Tests */ = { 186 | isa = PBXGroup; 187 | children = ( 188 | 6003F5BB195388D20070C39A /* Tests.m */, 189 | 6003F5B6195388D20070C39A /* Supporting Files */, 190 | ); 191 | path = Tests; 192 | sourceTree = ""; 193 | }; 194 | 6003F5B6195388D20070C39A /* Supporting Files */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | 6003F5B7195388D20070C39A /* Tests-Info.plist */, 198 | 6003F5B8195388D20070C39A /* InfoPlist.strings */, 199 | 606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */, 200 | ); 201 | name = "Supporting Files"; 202 | sourceTree = ""; 203 | }; 204 | 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */ = { 205 | isa = PBXGroup; 206 | children = ( 207 | 0E432239394A4D76C39CDD75 /* FMMosaicLayout.podspec */, 208 | 18DE6644CFE566A04570A623 /* README.md */, 209 | 7CBBF3E3E5CC0B3DEF0EB910 /* LICENSE */, 210 | ); 211 | name = "Podspec Metadata"; 212 | sourceTree = ""; 213 | }; 214 | B952EA181ACC386B00A979A6 /* Cells */ = { 215 | isa = PBXGroup; 216 | children = ( 217 | B986BA351A8A65AD00E4584D /* FMMosaicCellView.h */, 218 | B986BA1F1A8A5F6000E4584D /* FMMosaicCellView.m */, 219 | B960978F1AD433FE00EBD79A /* Header */, 220 | B960978E1AD433F600EBD79A /* Footer */, 221 | ); 222 | name = Cells; 223 | sourceTree = ""; 224 | }; 225 | B960978E1AD433F600EBD79A /* Footer */ = { 226 | isa = PBXGroup; 227 | children = ( 228 | B952EA0E1ACC380700A979A6 /* FMFooterView.h */, 229 | B952EA0F1ACC380700A979A6 /* FMFooterView.m */, 230 | B96097901AD4342D00EBD79A /* FMFooterView.xib */, 231 | ); 232 | name = Footer; 233 | sourceTree = ""; 234 | }; 235 | B960978F1AD433FE00EBD79A /* Header */ = { 236 | isa = PBXGroup; 237 | children = ( 238 | B952EA131ACC382600A979A6 /* FMHeaderView.h */, 239 | B952EA141ACC382600A979A6 /* FMHeaderView.m */, 240 | B96097911AD4342D00EBD79A /* FMHeaderView.xib */, 241 | ); 242 | name = Header; 243 | sourceTree = ""; 244 | }; 245 | /* End PBXGroup section */ 246 | 247 | /* Begin PBXNativeTarget section */ 248 | 6003F589195388D20070C39A /* FMMosaicLayout */ = { 249 | isa = PBXNativeTarget; 250 | buildConfigurationList = 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "FMMosaicLayout" */; 251 | buildPhases = ( 252 | 2A55F23405B1A758B2AB5B0E /* Check Pods Manifest.lock */, 253 | 6003F586195388D20070C39A /* Sources */, 254 | 6003F587195388D20070C39A /* Frameworks */, 255 | 6003F588195388D20070C39A /* Resources */, 256 | E99A6DF8EE0F2180DCE32AAA /* Copy Pods Resources */, 257 | ); 258 | buildRules = ( 259 | ); 260 | dependencies = ( 261 | ); 262 | name = FMMosaicLayout; 263 | productName = FMMosaicLayout; 264 | productReference = 6003F58A195388D20070C39A /* FMMosaicLayout.app */; 265 | productType = "com.apple.product-type.application"; 266 | }; 267 | 6003F5AD195388D20070C39A /* Tests */ = { 268 | isa = PBXNativeTarget; 269 | buildConfigurationList = 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "Tests" */; 270 | buildPhases = ( 271 | 7CCD0FB2E453FCB8191D6D11 /* Check Pods Manifest.lock */, 272 | 6003F5AA195388D20070C39A /* Sources */, 273 | 6003F5AB195388D20070C39A /* Frameworks */, 274 | 6003F5AC195388D20070C39A /* Resources */, 275 | 815135504CA12D6B2AF5212F /* Copy Pods Resources */, 276 | ); 277 | buildRules = ( 278 | ); 279 | dependencies = ( 280 | 6003F5B4195388D20070C39A /* PBXTargetDependency */, 281 | ); 282 | name = Tests; 283 | productName = FMMosaicLayoutTests; 284 | productReference = 6003F5AE195388D20070C39A /* Tests.xctest */; 285 | productType = "com.apple.product-type.bundle.unit-test"; 286 | }; 287 | /* End PBXNativeTarget section */ 288 | 289 | /* Begin PBXProject section */ 290 | 6003F582195388D10070C39A /* Project object */ = { 291 | isa = PBXProject; 292 | attributes = { 293 | CLASSPREFIX = FM; 294 | LastUpgradeCheck = 0510; 295 | ORGANIZATIONNAME = JVillella; 296 | TargetAttributes = { 297 | 6003F5AD195388D20070C39A = { 298 | TestTargetID = 6003F589195388D20070C39A; 299 | }; 300 | }; 301 | }; 302 | buildConfigurationList = 6003F585195388D10070C39A /* Build configuration list for PBXProject "FMMosaicLayout" */; 303 | compatibilityVersion = "Xcode 3.2"; 304 | developmentRegion = English; 305 | hasScannedForEncodings = 0; 306 | knownRegions = ( 307 | en, 308 | Base, 309 | ); 310 | mainGroup = 6003F581195388D10070C39A; 311 | productRefGroup = 6003F58B195388D20070C39A /* Products */; 312 | projectDirPath = ""; 313 | projectRoot = ""; 314 | targets = ( 315 | 6003F589195388D20070C39A /* FMMosaicLayout */, 316 | 6003F5AD195388D20070C39A /* Tests */, 317 | ); 318 | }; 319 | /* End PBXProject section */ 320 | 321 | /* Begin PBXResourcesBuildPhase section */ 322 | 6003F588195388D20070C39A /* Resources */ = { 323 | isa = PBXResourcesBuildPhase; 324 | buildActionMask = 2147483647; 325 | files = ( 326 | B986BA2B1A8A5F7D00E4584D /* LaunchScreen.xib in Resources */, 327 | 6003F5A9195388D20070C39A /* Images.xcassets in Resources */, 328 | 6003F598195388D20070C39A /* InfoPlist.strings in Resources */, 329 | B96097921AD4342D00EBD79A /* FMFooterView.xib in Resources */, 330 | B986BA2A1A8A5F7D00E4584D /* Example.storyboard in Resources */, 331 | B96097931AD4342D00EBD79A /* FMHeaderView.xib in Resources */, 332 | ); 333 | runOnlyForDeploymentPostprocessing = 0; 334 | }; 335 | 6003F5AC195388D20070C39A /* Resources */ = { 336 | isa = PBXResourcesBuildPhase; 337 | buildActionMask = 2147483647; 338 | files = ( 339 | 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */, 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | /* End PBXResourcesBuildPhase section */ 344 | 345 | /* Begin PBXShellScriptBuildPhase section */ 346 | 2A55F23405B1A758B2AB5B0E /* Check Pods Manifest.lock */ = { 347 | isa = PBXShellScriptBuildPhase; 348 | buildActionMask = 2147483647; 349 | files = ( 350 | ); 351 | inputPaths = ( 352 | ); 353 | name = "Check Pods Manifest.lock"; 354 | outputPaths = ( 355 | ); 356 | runOnlyForDeploymentPostprocessing = 0; 357 | shellPath = /bin/sh; 358 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 359 | showEnvVarsInLog = 0; 360 | }; 361 | 7CCD0FB2E453FCB8191D6D11 /* Check Pods Manifest.lock */ = { 362 | isa = PBXShellScriptBuildPhase; 363 | buildActionMask = 2147483647; 364 | files = ( 365 | ); 366 | inputPaths = ( 367 | ); 368 | name = "Check Pods Manifest.lock"; 369 | outputPaths = ( 370 | ); 371 | runOnlyForDeploymentPostprocessing = 0; 372 | shellPath = /bin/sh; 373 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 374 | showEnvVarsInLog = 0; 375 | }; 376 | 815135504CA12D6B2AF5212F /* Copy Pods Resources */ = { 377 | isa = PBXShellScriptBuildPhase; 378 | buildActionMask = 2147483647; 379 | files = ( 380 | ); 381 | inputPaths = ( 382 | ); 383 | name = "Copy Pods Resources"; 384 | outputPaths = ( 385 | ); 386 | runOnlyForDeploymentPostprocessing = 0; 387 | shellPath = /bin/sh; 388 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-resources.sh\"\n"; 389 | showEnvVarsInLog = 0; 390 | }; 391 | E99A6DF8EE0F2180DCE32AAA /* Copy Pods Resources */ = { 392 | isa = PBXShellScriptBuildPhase; 393 | buildActionMask = 2147483647; 394 | files = ( 395 | ); 396 | inputPaths = ( 397 | ); 398 | name = "Copy Pods Resources"; 399 | outputPaths = ( 400 | ); 401 | runOnlyForDeploymentPostprocessing = 0; 402 | shellPath = /bin/sh; 403 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-FMMosaicLayout/Pods-FMMosaicLayout-resources.sh\"\n"; 404 | showEnvVarsInLog = 0; 405 | }; 406 | /* End PBXShellScriptBuildPhase section */ 407 | 408 | /* Begin PBXSourcesBuildPhase section */ 409 | 6003F586195388D20070C39A /* Sources */ = { 410 | isa = PBXSourcesBuildPhase; 411 | buildActionMask = 2147483647; 412 | files = ( 413 | B986BA221A8A5F6000E4584D /* FMAppDelegate.m in Sources */, 414 | B952EA111ACC380700A979A6 /* FMFooterView.m in Sources */, 415 | B986BA231A8A5F6000E4584D /* FMMosaicCellView.m in Sources */, 416 | B986BA241A8A5F6000E4584D /* FMMosaicCollectionViewController.m in Sources */, 417 | B952EA161ACC382600A979A6 /* FMHeaderView.m in Sources */, 418 | B986BA251A8A5F6000E4584D /* main.m in Sources */, 419 | ); 420 | runOnlyForDeploymentPostprocessing = 0; 421 | }; 422 | 6003F5AA195388D20070C39A /* Sources */ = { 423 | isa = PBXSourcesBuildPhase; 424 | buildActionMask = 2147483647; 425 | files = ( 426 | 6003F5BC195388D20070C39A /* Tests.m in Sources */, 427 | ); 428 | runOnlyForDeploymentPostprocessing = 0; 429 | }; 430 | /* End PBXSourcesBuildPhase section */ 431 | 432 | /* Begin PBXTargetDependency section */ 433 | 6003F5B4195388D20070C39A /* PBXTargetDependency */ = { 434 | isa = PBXTargetDependency; 435 | target = 6003F589195388D20070C39A /* FMMosaicLayout */; 436 | targetProxy = 6003F5B3195388D20070C39A /* PBXContainerItemProxy */; 437 | }; 438 | /* End PBXTargetDependency section */ 439 | 440 | /* Begin PBXVariantGroup section */ 441 | 6003F596195388D20070C39A /* InfoPlist.strings */ = { 442 | isa = PBXVariantGroup; 443 | children = ( 444 | 6003F597195388D20070C39A /* en */, 445 | ); 446 | name = InfoPlist.strings; 447 | sourceTree = ""; 448 | }; 449 | 6003F5B8195388D20070C39A /* InfoPlist.strings */ = { 450 | isa = PBXVariantGroup; 451 | children = ( 452 | 6003F5B9195388D20070C39A /* en */, 453 | ); 454 | name = InfoPlist.strings; 455 | sourceTree = ""; 456 | }; 457 | B986BA261A8A5F7D00E4584D /* Example.storyboard */ = { 458 | isa = PBXVariantGroup; 459 | children = ( 460 | B986BA271A8A5F7D00E4584D /* Base */, 461 | ); 462 | name = Example.storyboard; 463 | sourceTree = ""; 464 | }; 465 | B986BA281A8A5F7D00E4584D /* LaunchScreen.xib */ = { 466 | isa = PBXVariantGroup; 467 | children = ( 468 | B986BA291A8A5F7D00E4584D /* Base */, 469 | ); 470 | name = LaunchScreen.xib; 471 | sourceTree = ""; 472 | }; 473 | /* End PBXVariantGroup section */ 474 | 475 | /* Begin XCBuildConfiguration section */ 476 | 6003F5BD195388D20070C39A /* Debug */ = { 477 | isa = XCBuildConfiguration; 478 | buildSettings = { 479 | ALWAYS_SEARCH_USER_PATHS = NO; 480 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 481 | CLANG_CXX_LIBRARY = "libc++"; 482 | CLANG_ENABLE_MODULES = YES; 483 | CLANG_ENABLE_OBJC_ARC = YES; 484 | CLANG_WARN_BOOL_CONVERSION = YES; 485 | CLANG_WARN_CONSTANT_CONVERSION = YES; 486 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 487 | CLANG_WARN_EMPTY_BODY = YES; 488 | CLANG_WARN_ENUM_CONVERSION = YES; 489 | CLANG_WARN_INT_CONVERSION = YES; 490 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 491 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 492 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 493 | COPY_PHASE_STRIP = NO; 494 | GCC_C_LANGUAGE_STANDARD = gnu99; 495 | GCC_DYNAMIC_NO_PIC = NO; 496 | GCC_OPTIMIZATION_LEVEL = 0; 497 | GCC_PREPROCESSOR_DEFINITIONS = ( 498 | "DEBUG=1", 499 | "$(inherited)", 500 | ); 501 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 502 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 503 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 504 | GCC_WARN_UNDECLARED_SELECTOR = YES; 505 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 506 | GCC_WARN_UNUSED_FUNCTION = YES; 507 | GCC_WARN_UNUSED_VARIABLE = YES; 508 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 509 | ONLY_ACTIVE_ARCH = YES; 510 | SDKROOT = iphoneos; 511 | TARGETED_DEVICE_FAMILY = "1,2"; 512 | }; 513 | name = Debug; 514 | }; 515 | 6003F5BE195388D20070C39A /* Release */ = { 516 | isa = XCBuildConfiguration; 517 | buildSettings = { 518 | ALWAYS_SEARCH_USER_PATHS = NO; 519 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 520 | CLANG_CXX_LIBRARY = "libc++"; 521 | CLANG_ENABLE_MODULES = YES; 522 | CLANG_ENABLE_OBJC_ARC = YES; 523 | CLANG_WARN_BOOL_CONVERSION = YES; 524 | CLANG_WARN_CONSTANT_CONVERSION = YES; 525 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 526 | CLANG_WARN_EMPTY_BODY = YES; 527 | CLANG_WARN_ENUM_CONVERSION = YES; 528 | CLANG_WARN_INT_CONVERSION = YES; 529 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 530 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 531 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 532 | COPY_PHASE_STRIP = YES; 533 | ENABLE_NS_ASSERTIONS = NO; 534 | GCC_C_LANGUAGE_STANDARD = gnu99; 535 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 536 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 537 | GCC_WARN_UNDECLARED_SELECTOR = YES; 538 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 539 | GCC_WARN_UNUSED_FUNCTION = YES; 540 | GCC_WARN_UNUSED_VARIABLE = YES; 541 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 542 | SDKROOT = iphoneos; 543 | TARGETED_DEVICE_FAMILY = "1,2"; 544 | VALIDATE_PRODUCT = YES; 545 | }; 546 | name = Release; 547 | }; 548 | 6003F5C0195388D20070C39A /* Debug */ = { 549 | isa = XCBuildConfiguration; 550 | baseConfigurationReference = 7605C3CD52D024CD64BFE751 /* Pods-FMMosaicLayout.debug.xcconfig */; 551 | buildSettings = { 552 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 553 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 554 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 555 | GCC_PREFIX_HEADER = "FMMosaicLayout/FMMosaicLayout-Prefix.pch"; 556 | INFOPLIST_FILE = "FMMosaicLayout/FMMosaicLayout-Info.plist"; 557 | IPHONEOS_DEPLOYMENT_TARGET = 8.2; 558 | PRODUCT_NAME = "$(TARGET_NAME)"; 559 | WRAPPER_EXTENSION = app; 560 | }; 561 | name = Debug; 562 | }; 563 | 6003F5C1195388D20070C39A /* Release */ = { 564 | isa = XCBuildConfiguration; 565 | baseConfigurationReference = 564285136DBFDA264B2EA590 /* Pods-FMMosaicLayout.release.xcconfig */; 566 | buildSettings = { 567 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 568 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 569 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 570 | GCC_PREFIX_HEADER = "FMMosaicLayout/FMMosaicLayout-Prefix.pch"; 571 | INFOPLIST_FILE = "FMMosaicLayout/FMMosaicLayout-Info.plist"; 572 | IPHONEOS_DEPLOYMENT_TARGET = 8.2; 573 | PRODUCT_NAME = "$(TARGET_NAME)"; 574 | WRAPPER_EXTENSION = app; 575 | }; 576 | name = Release; 577 | }; 578 | 6003F5C3195388D20070C39A /* Debug */ = { 579 | isa = XCBuildConfiguration; 580 | baseConfigurationReference = 57344976FD9A706AF9A5C0F6 /* Pods-Tests.debug.xcconfig */; 581 | buildSettings = { 582 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/FMMosaicLayout.app/FMMosaicLayout"; 583 | FRAMEWORK_SEARCH_PATHS = ( 584 | "$(SDKROOT)/Developer/Library/Frameworks", 585 | "$(inherited)", 586 | "$(DEVELOPER_FRAMEWORKS_DIR)", 587 | ); 588 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 589 | GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; 590 | GCC_PREPROCESSOR_DEFINITIONS = ( 591 | "DEBUG=1", 592 | "$(inherited)", 593 | ); 594 | INFOPLIST_FILE = "Tests/Tests-Info.plist"; 595 | PRODUCT_NAME = "$(TARGET_NAME)"; 596 | TEST_HOST = "$(BUNDLE_LOADER)"; 597 | WRAPPER_EXTENSION = xctest; 598 | }; 599 | name = Debug; 600 | }; 601 | 6003F5C4195388D20070C39A /* Release */ = { 602 | isa = XCBuildConfiguration; 603 | baseConfigurationReference = 271B5DC9EE27D3AF67E31CC1 /* Pods-Tests.release.xcconfig */; 604 | buildSettings = { 605 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/FMMosaicLayout.app/FMMosaicLayout"; 606 | FRAMEWORK_SEARCH_PATHS = ( 607 | "$(SDKROOT)/Developer/Library/Frameworks", 608 | "$(inherited)", 609 | "$(DEVELOPER_FRAMEWORKS_DIR)", 610 | ); 611 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 612 | GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; 613 | INFOPLIST_FILE = "Tests/Tests-Info.plist"; 614 | PRODUCT_NAME = "$(TARGET_NAME)"; 615 | TEST_HOST = "$(BUNDLE_LOADER)"; 616 | WRAPPER_EXTENSION = xctest; 617 | }; 618 | name = Release; 619 | }; 620 | /* End XCBuildConfiguration section */ 621 | 622 | /* Begin XCConfigurationList section */ 623 | 6003F585195388D10070C39A /* Build configuration list for PBXProject "FMMosaicLayout" */ = { 624 | isa = XCConfigurationList; 625 | buildConfigurations = ( 626 | 6003F5BD195388D20070C39A /* Debug */, 627 | 6003F5BE195388D20070C39A /* Release */, 628 | ); 629 | defaultConfigurationIsVisible = 0; 630 | defaultConfigurationName = Release; 631 | }; 632 | 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "FMMosaicLayout" */ = { 633 | isa = XCConfigurationList; 634 | buildConfigurations = ( 635 | 6003F5C0195388D20070C39A /* Debug */, 636 | 6003F5C1195388D20070C39A /* Release */, 637 | ); 638 | defaultConfigurationIsVisible = 0; 639 | defaultConfigurationName = Release; 640 | }; 641 | 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "Tests" */ = { 642 | isa = XCConfigurationList; 643 | buildConfigurations = ( 644 | 6003F5C3195388D20070C39A /* Debug */, 645 | 6003F5C4195388D20070C39A /* Release */, 646 | ); 647 | defaultConfigurationIsVisible = 0; 648 | defaultConfigurationName = Release; 649 | }; 650 | /* End XCConfigurationList section */ 651 | }; 652 | rootObject = 6003F582195388D10070C39A /* Project object */; 653 | } 654 | --------------------------------------------------------------------------------