├── .swift-version
├── Package.swift
├── ReadmeAssets
├── Screenplay.gif
├── Screenshot.png
├── CardLayoutActions.png
├── CardLayoutOptions.png
└── CollectionView_LayoutClass.png
├── HFCardCollectionViewLayoutExample
├── HFCardCollectionViewLayoutExample
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── Icons
│ │ │ ├── Contents.json
│ │ │ ├── Icon1.imageset
│ │ │ │ ├── Icon1.pdf
│ │ │ │ └── Contents.json
│ │ │ ├── Icon2.imageset
│ │ │ │ ├── Icon2.pdf
│ │ │ │ └── Contents.json
│ │ │ ├── Icon3.imageset
│ │ │ │ ├── Icon3.pdf
│ │ │ │ └── Contents.json
│ │ │ ├── Icon4.imageset
│ │ │ │ ├── Icon4.pdf
│ │ │ │ └── Contents.json
│ │ │ ├── Icon5.imageset
│ │ │ │ ├── Icon5.pdf
│ │ │ │ └── Contents.json
│ │ │ └── Icon6.imageset
│ │ │ │ ├── Icon6.pdf
│ │ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Info.plist
│ ├── Base.lproj
│ │ └── LaunchScreen.storyboard
│ ├── AppDelegate.swift
│ ├── ExampleCollectionViewCell.swift
│ ├── ExampleViewController.swift
│ └── MenuTableViewController.swift
├── Podfile
├── Pods
│ ├── Target Support Files
│ │ ├── HFCardCollectionViewLayout
│ │ │ ├── HFCardCollectionViewLayout.modulemap
│ │ │ ├── HFCardCollectionViewLayout-dummy.m
│ │ │ ├── HFCardCollectionViewLayout-prefix.pch
│ │ │ ├── HFCardCollectionViewLayout-umbrella.h
│ │ │ ├── HFCardCollectionViewLayout.xcconfig
│ │ │ └── Info.plist
│ │ └── Pods-HFCardCollectionViewLayoutExample
│ │ │ ├── Pods-HFCardCollectionViewLayoutExample.modulemap
│ │ │ ├── Pods-HFCardCollectionViewLayoutExample-dummy.m
│ │ │ ├── Pods-HFCardCollectionViewLayoutExample-umbrella.h
│ │ │ ├── Pods-HFCardCollectionViewLayoutExample.debug.xcconfig
│ │ │ ├── Pods-HFCardCollectionViewLayoutExample.release.xcconfig
│ │ │ ├── Info.plist
│ │ │ ├── Pods-HFCardCollectionViewLayoutExample-acknowledgements.markdown
│ │ │ ├── Pods-HFCardCollectionViewLayoutExample-acknowledgements.plist
│ │ │ ├── Pods-HFCardCollectionViewLayoutExample-frameworks.sh
│ │ │ └── Pods-HFCardCollectionViewLayoutExample-resources.sh
│ ├── Manifest.lock
│ ├── Local Podspecs
│ │ └── HFCardCollectionViewLayout.podspec.json
│ └── Pods.xcodeproj
│ │ └── project.pbxproj
├── HFCardCollectionViewLayoutExample.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── project.pbxproj
├── HFCardCollectionViewLayoutExample.xcworkspace
│ └── contents.xcworkspacedata
└── Podfile.lock
├── HFCardCollectionViewLayout.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcshareddata
│ └── xcschemes
│ │ └── HFCardCollectionViewLayout.xcscheme
└── project.pbxproj
├── HFCardCollectionViewLayout.podspec
├── HFCardCollectionViewLayout
├── HFCardCollectionViewLayout.h
└── Info.plist
├── LICENSE
├── .gitignore
├── CHANGELOG.md
├── Source
├── HFCardCollectionViewLayoutDelegate.swift
├── HFCardCollectionView.swift
├── HFCardCollectionViewCell.swift
└── HFCardCollectionViewLayout.swift
└── README.md
/.swift-version:
--------------------------------------------------------------------------------
1 | 3.0
2 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | import PackageDescription
2 |
3 | let package = Package(
4 | name: "HFCardCollectionViewLayout"
5 | )
--------------------------------------------------------------------------------
/ReadmeAssets/Screenplay.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hfrahmann/HFCardCollectionViewLayout/HEAD/ReadmeAssets/Screenplay.gif
--------------------------------------------------------------------------------
/ReadmeAssets/Screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hfrahmann/HFCardCollectionViewLayout/HEAD/ReadmeAssets/Screenshot.png
--------------------------------------------------------------------------------
/ReadmeAssets/CardLayoutActions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hfrahmann/HFCardCollectionViewLayout/HEAD/ReadmeAssets/CardLayoutActions.png
--------------------------------------------------------------------------------
/ReadmeAssets/CardLayoutOptions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hfrahmann/HFCardCollectionViewLayout/HEAD/ReadmeAssets/CardLayoutOptions.png
--------------------------------------------------------------------------------
/ReadmeAssets/CollectionView_LayoutClass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hfrahmann/HFCardCollectionViewLayout/HEAD/ReadmeAssets/CollectionView_LayoutClass.png
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line if you're using Swift
2 | use_frameworks!
3 |
4 | target 'HFCardCollectionViewLayoutExample' do
5 | platform :ios, '10.0'
6 | pod 'HFCardCollectionViewLayout', :path => '../'
7 | end
8 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayout.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/HFCardCollectionViewLayout/HFCardCollectionViewLayout.modulemap:
--------------------------------------------------------------------------------
1 | framework module HFCardCollectionViewLayout {
2 | umbrella header "HFCardCollectionViewLayout-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/HFCardCollectionViewLayout/HFCardCollectionViewLayout-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_HFCardCollectionViewLayout : NSObject
3 | @end
4 | @implementation PodsDummy_HFCardCollectionViewLayout
5 | @end
6 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon1.imageset/Icon1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hfrahmann/HFCardCollectionViewLayout/HEAD/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon1.imageset/Icon1.pdf
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon2.imageset/Icon2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hfrahmann/HFCardCollectionViewLayout/HEAD/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon2.imageset/Icon2.pdf
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon3.imageset/Icon3.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hfrahmann/HFCardCollectionViewLayout/HEAD/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon3.imageset/Icon3.pdf
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon4.imageset/Icon4.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hfrahmann/HFCardCollectionViewLayout/HEAD/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon4.imageset/Icon4.pdf
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon5.imageset/Icon5.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hfrahmann/HFCardCollectionViewLayout/HEAD/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon5.imageset/Icon5.pdf
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon6.imageset/Icon6.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hfrahmann/HFCardCollectionViewLayout/HEAD/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon6.imageset/Icon6.pdf
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_HFCardCollectionViewLayoutExample {
2 | umbrella header "Pods-HFCardCollectionViewLayoutExample-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_HFCardCollectionViewLayoutExample : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_HFCardCollectionViewLayoutExample
5 | @end
6 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/HFCardCollectionViewLayout/HFCardCollectionViewLayout-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Icon1.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template",
14 | "preserves-vector-representation" : true
15 | }
16 | }
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Icon2.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template",
14 | "preserves-vector-representation" : true
15 | }
16 | }
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Icon3.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template",
14 | "preserves-vector-representation" : true
15 | }
16 | }
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Icon4.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template",
14 | "preserves-vector-representation" : true
15 | }
16 | }
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Icon5.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template",
14 | "preserves-vector-representation" : true
15 | }
16 | }
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/Icons/Icon6.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Icon6.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template",
14 | "preserves-vector-representation" : true
15 | }
16 | }
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - HFCardCollectionViewLayout (0.2.2)
3 |
4 | DEPENDENCIES:
5 | - HFCardCollectionViewLayout (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | HFCardCollectionViewLayout:
9 | :path: ../
10 |
11 | SPEC CHECKSUMS:
12 | HFCardCollectionViewLayout: 70073318095967f5fa407147df68dd4696c7aedc
13 |
14 | PODFILE CHECKSUM: 234325b1b12e2e74244c12d2d31fa748e550f0f2
15 |
16 | COCOAPODS: 1.2.0.beta.1
17 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - HFCardCollectionViewLayout (0.2.2)
3 |
4 | DEPENDENCIES:
5 | - HFCardCollectionViewLayout (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | HFCardCollectionViewLayout:
9 | :path: ../
10 |
11 | SPEC CHECKSUMS:
12 | HFCardCollectionViewLayout: 70073318095967f5fa407147df68dd4696c7aedc
13 |
14 | PODFILE CHECKSUM: 234325b1b12e2e74244c12d2d31fa748e550f0f2
15 |
16 | COCOAPODS: 1.2.0.beta.1
17 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/HFCardCollectionViewLayout/HFCardCollectionViewLayout-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double HFCardCollectionViewLayoutVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char HFCardCollectionViewLayoutVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_HFCardCollectionViewLayoutExampleVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_HFCardCollectionViewLayoutExampleVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayout.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'HFCardCollectionViewLayout'
3 | s.version = '0.4.2'
4 | s.summary = 'The HFCardCollectionViewLayout provides a card stack layout not quite similar like the apps Reminder and Wallet.'
5 | s.license = 'MIT'
6 | s.homepage = 'https://github.com/hfrahmann/HFCardCollectionViewLayout'
7 | s.ios.deployment_target = '9.0'
8 | s.author = {
9 | 'Hendrik Frahmann' => 'contact@hendrik-frahmann.de'
10 | }
11 | s.source = {
12 | :git => 'https://github.com/hfrahmann/HFCardCollectionViewLayout.git',
13 | :tag => '0.4.2'
14 | }
15 | s.source_files = 'Source/*'
16 | end
17 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/HFCardCollectionViewLayout/HFCardCollectionViewLayout.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/HFCardCollectionViewLayout
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
4 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
5 | PODS_BUILD_DIR = $BUILD_DIR
6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
10 | SKIP_INSTALL = YES
11 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Local Podspecs/HFCardCollectionViewLayout.podspec.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "HFCardCollectionViewLayout",
3 | "version": "0.2.2",
4 | "summary": "The HFCardCollectionViewLayout provides a card stack layout not quite similar like the apps Reminder and Wallet.",
5 | "license": "MIT",
6 | "homepage": "https://github.com/hfrahmann/HFCardCollectionViewLayout",
7 | "platforms": {
8 | "ios": "9.0"
9 | },
10 | "authors": {
11 | "Hendrik Frahmann": "contact@hendrik-frahmann.de"
12 | },
13 | "source": {
14 | "git": "https://github.com/hfrahmann/HFCardCollectionViewLayout.git",
15 | "tag": "0.2.2"
16 | },
17 | "source_files": "Source/*"
18 | }
19 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayout/HFCardCollectionViewLayout.h:
--------------------------------------------------------------------------------
1 | //
2 | // HFCardCollectionViewLayout.h
3 | // HFCardCollectionViewLayout
4 | //
5 | // Created by David Collado on 23/2/17.
6 | // Copyright © 2017 hendrik-frahmann. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for HFCardCollectionViewLayout.
12 | FOUNDATION_EXPORT double HFCardCollectionViewLayoutVersionNumber;
13 |
14 | //! Project version string for HFCardCollectionViewLayout.
15 | FOUNDATION_EXPORT const unsigned char HFCardCollectionViewLayoutVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/HFCardCollectionViewLayout"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/HFCardCollectionViewLayout/HFCardCollectionViewLayout.framework/Headers"
6 | OTHER_LDFLAGS = $(inherited) -framework "HFCardCollectionViewLayout"
7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
8 | PODS_BUILD_DIR = $BUILD_DIR
9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_ROOT = ${SRCROOT}/Pods
11 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/HFCardCollectionViewLayout"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/HFCardCollectionViewLayout/HFCardCollectionViewLayout.framework/Headers"
6 | OTHER_LDFLAGS = $(inherited) -framework "HFCardCollectionViewLayout"
7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
8 | PODS_BUILD_DIR = $BUILD_DIR
9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_ROOT = ${SRCROOT}/Pods
11 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayout/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/HFCardCollectionViewLayout/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 0.2.2
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Hendrik Frahmann
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## HFCardCollectionViewLayout
5 |
6 | MIT License
7 |
8 | Copyright (c) 2016 Hendrik Frahmann
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 |
17 | The above copyright notice and this permission notice shall be included in all
18 | copies or substantial portions of the Software.
19 |
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | SOFTWARE.
27 |
28 | Generated by CocoaPods - https://cocoapods.org
29 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | # Xcode
4 | #
5 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
6 |
7 | ## Build generated
8 | build/
9 | DerivedData/
10 |
11 | ## Various settings
12 | *.pbxuser
13 | !default.pbxuser
14 | *.mode1v3
15 | !default.mode1v3
16 | *.mode2v3
17 | !default.mode2v3
18 | *.perspectivev3
19 | !default.perspectivev3
20 | xcuserdata/
21 |
22 | ## Other
23 | *.moved-aside
24 | *.xcuserstate
25 |
26 | ## Obj-C/Swift specific
27 | *.hmap
28 | *.ipa
29 | *.dSYM.zip
30 | *.dSYM
31 |
32 | ## Playgrounds
33 | timeline.xctimeline
34 | playground.xcworkspace
35 |
36 | # Swift Package Manager
37 | #
38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
39 | # Packages/
40 | .build/
41 |
42 | # CocoaPods
43 | #
44 | # We recommend against adding the Pods directory to your .gitignore. However
45 | # you should judge for yourself, the pros and cons are mentioned at:
46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
47 | #
48 | # Pods/
49 |
50 | # Carthage
51 | #
52 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
53 | # Carthage/Checkouts
54 |
55 | Carthage/Build
56 |
57 | # fastlane
58 | #
59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
60 | # screenshots whenever they are needed.
61 | # For more information about the recommended setup visit:
62 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
63 |
64 | fastlane/report.xml
65 | fastlane/Preview.html
66 | fastlane/screenshots
67 | fastlane/test_output
68 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 |
4 | ## 0.4.2
5 |
6 | - Created HFCardCollectionView class with a helper method
7 |
8 |
9 | ## 0.4.1
10 |
11 | - Fixed UIPanGestureRecognizer misbehaviour
12 | - Added another delete animation
13 |
14 |
15 | ## 0.3.3
16 |
17 | - Added Carthage support (from bitomule)
18 |
19 |
20 | ## 0.3.2
21 |
22 | - Added 'collapse all cards' option
23 | - Fixed a bug of a wrong scale while moving a card.
24 |
25 |
26 | ## 0.3.1
27 |
28 | - Improved shadow of the card cell
29 |
30 |
31 | ## 0.3
32 |
33 | - Added options 'bottomStackedCardsMinimumScale' and 'bottomStackedCardsMaximumScale'
34 | - Added some documentation
35 |
36 |
37 | ## 0.2.2
38 |
39 | - Renamed 'selected' to 'revealed'
40 |
41 |
42 | ## 0.2.1
43 |
44 | - Added option 'scrollStopCardsAtTop'
45 |
46 |
47 | ## 0.2
48 |
49 | - Added the UICollectionViewCell and UICollectionView extension (again)
50 |
51 |
52 | ## 0.1.5
53 |
54 | - Made the HFCardCollectionViewCell and HFCardCollectionViewLayout open instead of public
55 | - Improved the HFCardCollectionViewDelegate
56 | - Package.swift added
57 | - Reordered the source files
58 |
59 |
60 | ## 0.1.4
61 |
62 | - Bugfix for setting the background color or HFCardCollectionViewCell
63 | - Extends the HFCardCollectionViewDelegate
64 | - Removed the HFCardCollectionViewCellDelegate
65 |
66 |
67 | ## 0.1.3
68 |
69 | - HFCardCollectionViewDelegate now inherits from UICollectionViewDelegate
70 |
71 |
72 | ## 0.1.2
73 |
74 | - Renamed option bottomShouldScaleStackedCards to bottomStackedCardsShouldScale
75 | - Improving of the calculation for the moving cell
76 |
77 |
78 | ## 0.1.1
79 |
80 | - Bugfix at scrollShouldSnapCardHead and maximumCardHeight
81 |
82 |
83 | ## 0.1
84 |
85 | - First release
86 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Base.lproj/LaunchScreen.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 |
28 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // HFCardCollectionViewLayoutExample
4 | //
5 | // Created by Hendrik Frahmann on 02.11.16.
6 | // Copyright © 2016 Hendrik Frahmann. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | MIT License
18 |
19 | Copyright (c) 2016 Hendrik Frahmann
20 |
21 | Permission is hereby granted, free of charge, to any person obtaining a copy
22 | of this software and associated documentation files (the "Software"), to deal
23 | in the Software without restriction, including without limitation the rights
24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25 | copies of the Software, and to permit persons to whom the Software is
26 | furnished to do so, subject to the following conditions:
27 |
28 | The above copyright notice and this permission notice shall be included in all
29 | copies or substantial portions of the Software.
30 |
31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37 | SOFTWARE.
38 |
39 | License
40 | MIT
41 | Title
42 | HFCardCollectionViewLayout
43 | Type
44 | PSGroupSpecifier
45 |
46 |
47 | FooterText
48 | Generated by CocoaPods - https://cocoapods.org
49 | Title
50 |
51 | Type
52 | PSGroupSpecifier
53 |
54 |
55 | StringsTable
56 | Acknowledgements
57 | Title
58 | Acknowledgements
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Source/HFCardCollectionViewLayoutDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HFCardCollectionViewLayoutDelegate.swift
3 | // Pods
4 | //
5 | // Created by Hendrik Frahmann on 17.11.16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | /// Extended delegate.
12 | @objc public protocol HFCardCollectionViewLayoutDelegate : UICollectionViewDelegate {
13 |
14 | /// Asks if the card at the specific index can be revealed.
15 | /// - Parameter collectionViewLayout: The current HFCardCollectionViewLayout.
16 | /// - Parameter canRevealCardAtIndex: Index of the card.
17 | @objc optional func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, canRevealCardAtIndex index: Int) -> Bool
18 |
19 | /// Asks if the card at the specific index can be Unrevealed.
20 | /// - Parameter collectionViewLayout: The current HFCardCollectionViewLayout.
21 | /// - Parameter canUnrevealCardAtIndex: Index of the card.
22 | @objc optional func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, canUnrevealCardAtIndex index: Int) -> Bool
23 |
24 | /// Feedback when the card at the given index will be revealed.
25 | /// - Parameter collectionViewLayout: The current HFCardCollectionViewLayout.
26 | /// - Parameter didRevealedCardAtIndex: Index of the card.
27 | @objc optional func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, willRevealCardAtIndex index: Int)
28 |
29 | /// Feedback when the card at the given index was revealed.
30 | /// - Parameter collectionViewLayout: The current HFCardCollectionViewLayout.
31 | /// - Parameter didRevealedCardAtIndex: Index of the card.
32 | @objc optional func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, didRevealCardAtIndex index: Int)
33 |
34 | /// Feedback when the card at the given index will be Unrevealed.
35 | /// - Parameter collectionViewLayout: The current HFCardCollectionViewLayout.
36 | /// - Parameter didUnrevealedCardAtIndex: Index of the card.
37 | @objc optional func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, willUnrevealCardAtIndex index: Int)
38 |
39 | /// Feedback when the card at the given index was Unrevealed.
40 | /// - Parameter collectionViewLayout: The current HFCardCollectionViewLayout.
41 | /// - Parameter didUnrevealedCardAtIndex: Index of the card.
42 | @objc optional func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, didUnrevealCardAtIndex index: Int)
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/Source/HFCardCollectionView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HFCardCollectionView.swift
3 | // Pods
4 | //
5 | // Created by Hendrik Frahmann on 02.04.17.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | class HFCardCollectionView: UICollectionView {
12 |
13 | override open func insertItems(at indexPaths: [IndexPath]) {
14 | if let collectionViewLayout = self.collectionViewLayout as? HFCardCollectionViewLayout {
15 | collectionViewLayout.willInsert(indexPaths: indexPaths)
16 | }
17 | super.insertItems(at: indexPaths)
18 | }
19 |
20 | override open func deleteItems(at indexPaths: [IndexPath]) {
21 | if let collectionViewLayout = self.collectionViewLayout as? HFCardCollectionViewLayout {
22 | collectionViewLayout.willDelete(indexPaths: indexPaths)
23 | }
24 | super.deleteItems(at: indexPaths)
25 | }
26 |
27 | /// Overwritten to prevent default behaviour of 'installsStandardGestureForInteractiveMovement = true'.
28 | ///
29 | /// - Parameter gestureRecognizer: An object whose class descends from the UIGestureRecognizer class. This parameter must not be nil.
30 | override open func addGestureRecognizer(_ gestureRecognizer: UIGestureRecognizer) {
31 | if let collectionViewLayout = self.collectionViewLayout as? HFCardCollectionViewLayout {
32 | let gestureClassName = String(describing: type(of: gestureRecognizer))
33 | let gestureString = String(describing: gestureRecognizer)
34 | // Prevent default behaviour of 'installsStandardGestureForInteractiveMovement = true' and install a custom reorder gesture recognizer.
35 | if(gestureClassName == "UILongPressGestureRecognizer" && gestureString.range(of: "action=_handleReorderingGesture") != nil) {
36 | collectionViewLayout.installMoveCardsGestureRecognizer()
37 | return
38 | }
39 | }
40 | super.addGestureRecognizer(gestureRecognizer)
41 | }
42 |
43 |
44 | /// Overwritten to ignore the contentOffset change when scrolling is disabled.
45 | ///
46 | /// - Parameter contentOffset: A point (expressed in points) that is offset from the content view’s origin.
47 | /// - Parameter animated: true to animate the transition at a constant velocity to the new offset, false to make the transition immediate.
48 | override open func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {
49 | if self.collectionViewLayout is HFCardCollectionViewLayout {
50 | if(self.isScrollEnabled == true) {
51 | super.setContentOffset(contentOffset, animated: animated)
52 | }
53 | } else {
54 | super.setContentOffset(contentOffset, animated: animated)
55 | }
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/ExampleCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleCollectionViewCell.swift
3 | // HFCardCollectionViewLayoutExample
4 | //
5 | // Created by Hendrik Frahmann on 02.11.16.
6 | // Copyright © 2016 Hendrik Frahmann. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import QuartzCore
11 | import HFCardCollectionViewLayout
12 |
13 | class ExampleCollectionViewCell: HFCardCollectionViewCell {
14 |
15 | var cardCollectionViewLayout: HFCardCollectionViewLayout?
16 |
17 | @IBOutlet var buttonFlip: UIButton?
18 | @IBOutlet var tableView: UITableView?
19 | @IBOutlet var labelText: UILabel?
20 | @IBOutlet var imageIcon: UIImageView?
21 |
22 | @IBOutlet var backView: UIView?
23 | @IBOutlet var buttonFlipBack: UIButton?
24 |
25 | override func awakeFromNib() {
26 | super.awakeFromNib()
27 | self.buttonFlip?.isHidden = true
28 | self.tableView?.scrollsToTop = false
29 |
30 | self.tableView?.register(UITableViewCell.self, forCellReuseIdentifier: "TableCell")
31 | self.tableView?.dataSource = self
32 | self.tableView?.delegate = self
33 | self.tableView?.allowsSelectionDuringEditing = false
34 | self.tableView?.reloadData()
35 | }
36 |
37 | func cardIsRevealed(_ isRevealed: Bool) {
38 | self.buttonFlip?.isHidden = !isRevealed
39 | self.tableView?.scrollsToTop = isRevealed
40 | }
41 |
42 | @IBAction func buttonFlipAction() {
43 | if let backView = self.backView {
44 | // Same Corner radius like the contentview of the HFCardCollectionViewCell
45 | backView.layer.cornerRadius = self.cornerRadius
46 | backView.layer.masksToBounds = true
47 |
48 | self.cardCollectionViewLayout?.flipRevealedCard(toView: backView)
49 | }
50 | }
51 |
52 |
53 | }
54 |
55 | extension ExampleCollectionViewCell : UITableViewDelegate, UITableViewDataSource {
56 |
57 | func numberOfSections(in tableView: UITableView) -> Int {
58 | return 1
59 | }
60 |
61 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
62 | return 20
63 | }
64 |
65 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
66 | let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell")
67 | cell?.textLabel?.text = "Table Cell #\(indexPath.row)"
68 | cell?.textLabel?.textColor = .white
69 | cell?.backgroundColor = .clear
70 | cell?.selectionStyle = .none
71 | return cell!
72 | }
73 |
74 | func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
75 | return true
76 | }
77 |
78 | func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
79 | // nothing
80 | }
81 |
82 | func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
83 | let anAction = UITableViewRowAction(style: .default, title: "An Action")
84 | {
85 | (action, indexPath) -> Void in
86 | // code for action
87 | }
88 | return [anAction]
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayout.xcodeproj/xcshareddata/xcschemes/HFCardCollectionViewLayout.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
75 |
76 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/Source/HFCardCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HFCardCollectionViewCell.swift
3 | // HFCardCollectionViewLayout
4 | //
5 | // Created by Hendrik Frahmann on 02.11.16.
6 | // Copyright © 2016 Hendrik Frahmann. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import QuartzCore
11 |
12 | /// An UICollectionViewCell for the HFCardCollectionViewLayout.
13 | ///
14 | /// This Cell has no dependency on the HFCardCollectionViewLayout.
15 | /// So you can create your own UICollectionViewCell without extending from this class.
16 | open class HFCardCollectionViewCell: UICollectionViewCell {
17 |
18 | @IBInspectable open var cornerRadius: CGFloat = 10
19 |
20 | private var firstBackgroundColor: UIColor?
21 |
22 | // MARK: Overrides
23 |
24 | /// Overwritten to setup the view
25 | open override func awakeFromNib() {
26 | super.awakeFromNib()
27 |
28 | self.setupLayer(self)
29 |
30 | self.contentView.layer.masksToBounds = true
31 | self.contentView.layer.cornerRadius = self.cornerRadius
32 | self.contentView.clipsToBounds = true
33 | self.contentView.backgroundColor = self.firstBackgroundColor
34 | }
35 |
36 | /// Important for updating the Z index and setting the flag 'isUserInteractionEnabled'
37 | ///
38 | /// - Parameter layoutAttributes: The new layout attributes
39 | override open func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
40 | super.apply(layoutAttributes)
41 | if let cardLayoutAttributes = layoutAttributes as? HFCardCollectionViewLayoutAttributes {
42 | self.layer.zPosition = CGFloat(cardLayoutAttributes.zIndex)
43 | self.contentView.isUserInteractionEnabled = cardLayoutAttributes.isRevealed
44 | } else {
45 | self.contentView.isUserInteractionEnabled = true
46 | }
47 | }
48 |
49 | /// Overwritten to pass the backgroundColor to contentView and keep the cell itself transparent.
50 | override open var backgroundColor: UIColor? {
51 | set {
52 | if(self.firstBackgroundColor == nil) {
53 | self.firstBackgroundColor = newValue
54 | }
55 | super.backgroundColor = .clear
56 | self.contentView.backgroundColor = newValue
57 | }
58 | get {
59 | return self.contentView.backgroundColor
60 | }
61 | }
62 |
63 | /// Overwritten to update the shadowPath.
64 | override open var bounds: CGRect {
65 | didSet {
66 | let shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.cornerRadius).cgPath
67 | self.layer.shadowPath = shadowPath
68 | }
69 | }
70 |
71 | /// Overwritten to create a better snapshot.
72 | ///
73 | /// The HFCardCollectionViewLayout will create a snapshot of this cell as the moving card view.
74 | /// This Function will recreate the shadows to the snapshotView.
75 | override open func snapshotView(afterScreenUpdates afterUpdates: Bool) -> UIView? {
76 | let snapshotView = UIView(frame: self.frame)
77 | if let snapshotOfContentView = self.contentView.snapshotView(afterScreenUpdates: afterUpdates) {
78 | snapshotView.addSubview(snapshotOfContentView)
79 | }
80 | self.setupLayer(snapshotView)
81 | return snapshotView
82 | }
83 |
84 | // MARK: Private Functions
85 |
86 | private func setupLayer(_ forView: UIView) {
87 | // Shadow can have performance issues on older devices
88 | let shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.cornerRadius).cgPath
89 | forView.layer.shadowPath = shadowPath
90 | forView.layer.masksToBounds = false
91 | forView.layer.shadowColor = UIColor(white: 0.0, alpha: 1.0).cgColor
92 | forView.layer.shadowRadius = 2
93 | forView.layer.shadowOpacity = 0.35
94 | forView.layer.shadowOffset = CGSize(width: 0, height: 0)
95 | forView.layer.rasterizationScale = UIScreen.main.scale
96 | forView.layer.shouldRasterize = true
97 | forView.clipsToBounds = false
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
6 |
7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
8 |
9 | install_framework()
10 | {
11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
12 | local source="${BUILT_PRODUCTS_DIR}/$1"
13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
15 | elif [ -r "$1" ]; then
16 | local source="$1"
17 | fi
18 |
19 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
20 |
21 | if [ -L "${source}" ]; then
22 | echo "Symlinked..."
23 | source="$(readlink "${source}")"
24 | fi
25 |
26 | # use filter instead of exclude so missing patterns dont' throw errors
27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
29 |
30 | local basename
31 | basename="$(basename -s .framework "$1")"
32 | binary="${destination}/${basename}.framework/${basename}"
33 | if ! [ -r "$binary" ]; then
34 | binary="${destination}/${basename}"
35 | fi
36 |
37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
39 | strip_invalid_archs "$binary"
40 | fi
41 |
42 | # Resign the code if required by the build settings to avoid unstable apps
43 | code_sign_if_enabled "${destination}/$(basename "$1")"
44 |
45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
47 | local swift_runtime_libs
48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
49 | for lib in $swift_runtime_libs; do
50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
52 | code_sign_if_enabled "${destination}/${lib}"
53 | done
54 | fi
55 | }
56 |
57 | # Signs a framework with the provided identity
58 | code_sign_if_enabled() {
59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
60 | # Use the current code_sign_identitiy
61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
62 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1""
63 |
64 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
65 | code_sign_cmd="$code_sign_cmd &"
66 | fi
67 | echo "$code_sign_cmd"
68 | eval "$code_sign_cmd"
69 | fi
70 | }
71 |
72 | # Strip invalid architectures
73 | strip_invalid_archs() {
74 | binary="$1"
75 | # Get architectures for current file
76 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
77 | stripped=""
78 | for arch in $archs; do
79 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
80 | # Strip non-valid architectures in-place
81 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1
82 | stripped="$stripped $arch"
83 | fi
84 | done
85 | if [[ "$stripped" ]]; then
86 | echo "Stripped $binary of architectures:$stripped"
87 | fi
88 | }
89 |
90 |
91 | if [[ "$CONFIGURATION" == "Debug" ]]; then
92 | install_framework "$BUILT_PRODUCTS_DIR/HFCardCollectionViewLayout/HFCardCollectionViewLayout.framework"
93 | fi
94 | if [[ "$CONFIGURATION" == "Release" ]]; then
95 | install_framework "$BUILT_PRODUCTS_DIR/HFCardCollectionViewLayout/HFCardCollectionViewLayout.framework"
96 | fi
97 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
98 | wait
99 | fi
100 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
5 |
6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
7 | > "$RESOURCES_TO_COPY"
8 |
9 | XCASSET_FILES=()
10 |
11 | case "${TARGETED_DEVICE_FAMILY}" in
12 | 1,2)
13 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
14 | ;;
15 | 1)
16 | TARGET_DEVICE_ARGS="--target-device iphone"
17 | ;;
18 | 2)
19 | TARGET_DEVICE_ARGS="--target-device ipad"
20 | ;;
21 | 3)
22 | TARGET_DEVICE_ARGS="--target-device tv"
23 | ;;
24 | *)
25 | TARGET_DEVICE_ARGS="--target-device mac"
26 | ;;
27 | esac
28 |
29 | install_resource()
30 | {
31 | if [[ "$1" = /* ]] ; then
32 | RESOURCE_PATH="$1"
33 | else
34 | RESOURCE_PATH="${PODS_ROOT}/$1"
35 | fi
36 | if [[ ! -e "$RESOURCE_PATH" ]] ; then
37 | cat << EOM
38 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
39 | EOM
40 | exit 1
41 | fi
42 | case $RESOURCE_PATH in
43 | *.storyboard)
44 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
45 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
46 | ;;
47 | *.xib)
48 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
49 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
50 | ;;
51 | *.framework)
52 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
53 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
54 | echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
55 | rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
56 | ;;
57 | *.xcdatamodel)
58 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\""
59 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
60 | ;;
61 | *.xcdatamodeld)
62 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\""
63 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
64 | ;;
65 | *.xcmappingmodel)
66 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\""
67 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
68 | ;;
69 | *.xcassets)
70 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
71 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
72 | ;;
73 | *)
74 | echo "$RESOURCE_PATH"
75 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
76 | ;;
77 | esac
78 | }
79 |
80 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
81 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
82 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
83 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
84 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
85 | fi
86 | rm -f "$RESOURCES_TO_COPY"
87 |
88 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
89 | then
90 | # Find all other xcassets (this unfortunately includes those of path pods and other targets).
91 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
92 | while read line; do
93 | if [[ $line != "${PODS_ROOT}*" ]]; then
94 | XCASSET_FILES+=("$line")
95 | fi
96 | done <<<"$OTHER_XCASSETS"
97 |
98 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
99 | fi
100 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/ExampleViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleViewController.swift
3 | // HFCardCollectionViewLayoutExample
4 | //
5 | // Created by Hendrik Frahmann on 28.10.16.
6 | // Copyright © 2016 Hendrik Frahmann. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import HFCardCollectionViewLayout
11 |
12 | struct CardInfo {
13 | var color: UIColor
14 | var icon: UIImage
15 | }
16 |
17 | class ExampleViewController : UICollectionViewController, HFCardCollectionViewLayoutDelegate {
18 |
19 | var cardCollectionViewLayout: HFCardCollectionViewLayout?
20 |
21 | @IBOutlet var backgroundView: UIView?
22 | @IBOutlet var backgroundNavigationBar: UINavigationBar?
23 |
24 | var cardLayoutOptions: CardLayoutSetupOptions?
25 | var shouldSetupBackgroundView = false
26 |
27 | var cardArray: [CardInfo] = []
28 |
29 | override func viewDidLoad() {
30 | self.setupExample()
31 | super.viewDidLoad()
32 | }
33 |
34 | // MARK: CollectionView
35 |
36 | func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, willRevealCardAtIndex index: Int) {
37 | if let cell = self.collectionView?.cellForItem(at: IndexPath(item: index, section: 0)) as? ExampleCollectionViewCell {
38 | cell.cardCollectionViewLayout = self.cardCollectionViewLayout
39 | cell.cardIsRevealed(true)
40 | }
41 | }
42 |
43 | func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, willUnrevealCardAtIndex index: Int) {
44 | if let cell = self.collectionView?.cellForItem(at: IndexPath(item: index, section: 0)) as? ExampleCollectionViewCell {
45 | cell.cardCollectionViewLayout = self.cardCollectionViewLayout
46 | cell.cardIsRevealed(false)
47 | }
48 | }
49 |
50 | override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
51 | return self.cardArray.count
52 | }
53 |
54 | override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
55 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CardCell", for: indexPath) as! ExampleCollectionViewCell
56 | cell.backgroundColor = self.cardArray[indexPath.item].color
57 | cell.imageIcon?.image = self.cardArray[indexPath.item].icon
58 | return cell
59 | }
60 |
61 | override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
62 | self.cardCollectionViewLayout?.revealCardAt(index: indexPath.item)
63 | }
64 |
65 | override func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
66 | let tempItem = self.cardArray[sourceIndexPath.item]
67 | self.cardArray.remove(at: sourceIndexPath.item)
68 | self.cardArray.insert(tempItem, at: destinationIndexPath.item)
69 | }
70 |
71 | // MARK: Actions
72 |
73 | @IBAction func goBackAction() {
74 | _ = self.navigationController?.popViewController(animated: true)
75 | }
76 |
77 | @IBAction func addCardAction() {
78 | let index = 0
79 | let newItem = createCardInfo()
80 | self.cardArray.insert(newItem, at: index)
81 | self.collectionView?.insertItems(at: [IndexPath(item: index, section: 0)])
82 |
83 | if(self.cardArray.count == 1) {
84 | self.cardCollectionViewLayout?.revealCardAt(index: index)
85 | }
86 | }
87 |
88 | @IBAction func deleteCardAtIndex0orSelected() {
89 | var index = 0
90 | if(self.cardCollectionViewLayout!.revealedIndex >= 0) {
91 | index = self.cardCollectionViewLayout!.revealedIndex
92 | }
93 | self.cardCollectionViewLayout?.flipRevealedCardBack(completion: {
94 | self.cardArray.remove(at: index)
95 | self.collectionView?.deleteItems(at: [IndexPath(item: index, section: 0)])
96 | })
97 | }
98 |
99 | // MARK: Private Functions
100 |
101 | private func setupExample() {
102 | if let cardCollectionViewLayout = self.collectionView?.collectionViewLayout as? HFCardCollectionViewLayout {
103 | self.cardCollectionViewLayout = cardCollectionViewLayout
104 | }
105 | if(self.shouldSetupBackgroundView == true) {
106 | self.setupBackgroundView()
107 | }
108 | if let cardLayoutOptions = self.cardLayoutOptions {
109 | self.cardCollectionViewLayout?.firstMovableIndex = cardLayoutOptions.firstMovableIndex
110 | self.cardCollectionViewLayout?.cardHeadHeight = cardLayoutOptions.cardHeadHeight
111 | self.cardCollectionViewLayout?.cardShouldExpandHeadHeight = cardLayoutOptions.cardShouldExpandHeadHeight
112 | self.cardCollectionViewLayout?.cardShouldStretchAtScrollTop = cardLayoutOptions.cardShouldStretchAtScrollTop
113 | self.cardCollectionViewLayout?.cardMaximumHeight = cardLayoutOptions.cardMaximumHeight
114 | self.cardCollectionViewLayout?.bottomNumberOfStackedCards = cardLayoutOptions.bottomNumberOfStackedCards
115 | self.cardCollectionViewLayout?.bottomStackedCardsShouldScale = cardLayoutOptions.bottomStackedCardsShouldScale
116 | self.cardCollectionViewLayout?.bottomCardLookoutMargin = cardLayoutOptions.bottomCardLookoutMargin
117 | self.cardCollectionViewLayout?.spaceAtTopForBackgroundView = cardLayoutOptions.spaceAtTopForBackgroundView
118 | self.cardCollectionViewLayout?.spaceAtTopShouldSnap = cardLayoutOptions.spaceAtTopShouldSnap
119 | self.cardCollectionViewLayout?.spaceAtBottom = cardLayoutOptions.spaceAtBottom
120 | self.cardCollectionViewLayout?.scrollAreaTop = cardLayoutOptions.scrollAreaTop
121 | self.cardCollectionViewLayout?.scrollAreaBottom = cardLayoutOptions.scrollAreaBottom
122 | self.cardCollectionViewLayout?.scrollShouldSnapCardHead = cardLayoutOptions.scrollShouldSnapCardHead
123 | self.cardCollectionViewLayout?.scrollStopCardsAtTop = cardLayoutOptions.scrollStopCardsAtTop
124 | self.cardCollectionViewLayout?.bottomStackedCardsMinimumScale = cardLayoutOptions.bottomStackedCardsMinimumScale
125 | self.cardCollectionViewLayout?.bottomStackedCardsMaximumScale = cardLayoutOptions.bottomStackedCardsMaximumScale
126 |
127 | let count = cardLayoutOptions.numberOfCards
128 |
129 | for index in 0.. CardInfo {
137 | let icons: [UIImage] = [#imageLiteral(resourceName: "Icon1.pdf"), #imageLiteral(resourceName: "Icon2.pdf"), #imageLiteral(resourceName: "Icon3.pdf"), #imageLiteral(resourceName: "Icon4.pdf"), #imageLiteral(resourceName: "Icon5.pdf"), #imageLiteral(resourceName: "Icon6.pdf")]
138 | let icon = icons[Int(arc4random_uniform(6))]
139 | let newItem = CardInfo(color: self.getRandomColor(), icon: icon)
140 | return newItem
141 | }
142 |
143 | private func setupBackgroundView() {
144 | if(self.cardLayoutOptions?.spaceAtTopForBackgroundView == 0) {
145 | self.cardLayoutOptions?.spaceAtTopForBackgroundView = 44 // Height of the NavigationBar in the BackgroundView
146 | }
147 | if let collectionView = self.collectionView {
148 | collectionView.backgroundView = self.backgroundView
149 | self.backgroundNavigationBar?.shadowImage = UIImage()
150 | self.backgroundNavigationBar?.setBackgroundImage(UIImage(), for: .default)
151 | }
152 | }
153 |
154 | private func getRandomColor() -> UIColor{
155 | let randomRed:CGFloat = CGFloat(drand48())
156 | let randomGreen:CGFloat = CGFloat(drand48())
157 | let randomBlue:CGFloat = CGFloat(drand48())
158 | return UIColor(red: randomRed, green: randomGreen, blue: randomBlue, alpha: 1.0)
159 | }
160 | }
161 |
162 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HFCardCollectionViewLayout
2 | The HFCardCollectionViewLayout provides a card stack layout not quite similar like the apps Reminder and Wallet.
3 |
4 | Features:
5 |
6 | - Many options, also within the InterfaceBuilder
7 | - Flip animation to have a backview
8 | - Move/Order the cards
9 | - Simple integration (only set the Layout class in the CollectionView)
10 |
11 | 
12 | 
13 |
14 |
15 | ## Installation
16 |
17 | Install it with Cocoapods, Swift Package Manager, Carthage or just use the files inside the **Source** directory.
18 |
19 |
20 | **Cocoapods:**
21 | ```
22 | pod 'HFCardCollectionViewLayout'
23 | ```
24 |
25 |
26 | **Carthage:**
27 | ```
28 | github "hfrahmann/HFCardCollectionViewLayout"
29 | ```
30 |
31 |
32 | **Swift Package Manager:**
33 | ```
34 | dependencies: [
35 | .Package(url: "https://github.com/hfrahmann/HFCardCollectionViewLayout.git")
36 | ]
37 | ```
38 |
39 |
40 |
41 | ## Implementation
42 |
43 | Just set *HFCardCollectionViewLayout* as the custom layout class in your UICollectionView.
44 |
45 | 
46 |
47 |
48 | There is also a cell class called **HFCardCollectionViewCell** containing rounded corners and a shadow.
49 | But this class has no dependency on the *HFCardCollectionViewLayout*.
50 | It's only there to have a cell that looks like a card.
51 |
52 | **Important: This collectionView layout does support only one section!**
53 |
54 |
55 | ### HFCardCollectionView
56 |
57 | Because of some problems with inserting items while a card is revealed, you have to use the **HFCardCollectionView** instead of the UICollectionView.
58 | Or if you use your own collectionview class, you can copy the lines from the file to your own.
59 |
60 |
61 | ## Delegate
62 |
63 | These are the delegate functions of the **HFCardCollectionViewLayoutDelegate** inherits from *UICollectionViewDelete* so you don't need to connect a further delegate.
64 |
65 | ```swift
66 | /// Asks if the card at the specific index can be revealed.
67 | /// - Parameter collectionViewLayout: The current HFCardCollectionViewLayout.
68 | /// - Parameter canRevealCardAtIndex: Index of the card.
69 | func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, canRevealCardAtIndex index: Int) -> Bool
70 |
71 | /// Asks if the card at the specific index can be unrevealed.
72 | /// - Parameter collectionViewLayout: The current HFCardCollectionViewLayout.
73 | /// - Parameter canUnrevealCardAtIndex: Index of the card.
74 | func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, canUnrevealCardAtIndex index: Int) -> Bool
75 |
76 | /// Feedback when the card at the given index will be revealed.
77 | /// - Parameter collectionViewLayout: The current HFCardCollectionViewLayout.
78 | /// - Parameter didRevealedCardAtIndex: Index of the card.
79 | func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, willRevealCardAtIndex index: Int)
80 |
81 | /// Feedback when the card at the given index was revealed.
82 | /// - Parameter collectionViewLayout: The current HFCardCollectionViewLayout.
83 | /// - Parameter didRevealedCardAtIndex: Index of the card.
84 | func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, didRevealCardAtIndex index: Int)
85 |
86 | /// Feedback when the card at the given index will be unrevealed.
87 | /// - Parameter collectionViewLayout: The current HFCardCollectionViewLayout.
88 | /// - Parameter didUnrevealedCardAtIndex: Index of the card.
89 | func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, willUnrevealCardAtIndex index: Int)
90 |
91 | /// Feedback when the card at the given index was unrevealed.
92 | /// - Parameter collectionViewLayout: The current HFCardCollectionViewLayout.
93 | /// - Parameter didUnrevealedCardAtIndex: Index of the card.
94 | func cardCollectionViewLayout(_ collectionViewLayout: HFCardCollectionViewLayout, didUnrevealCardAtIndex index: Int)
95 | ```
96 |
97 |
98 |
99 | ## Options and Actions
100 |
101 | You also have access to the options and (some) actions at the *HFCardCollectionViewLayout* object in the interface builder.
102 |
103 | 
104 | 
105 |
106 | These are the public variables of *HFCardCollectionViewLayout*.
107 |
108 | ```swift
109 | /////////////// Public Variables
110 |
111 | /// Only cards with index equal or greater than firstMovableIndex can be moved through the collectionView.
112 | @IBInspectable var firstMovableIndex: Int = 0
113 |
114 | /// Specifies the height that is showing the cardhead when the collectionView is showing all cards.
115 | /// The minimum value is 20.
116 | @IBInspectable var cardHeadHeight: CGFloat = 80
117 |
118 | /// When th collectionView is showing all cards but there are not enough cards to fill the full height,
119 | /// the cardHeadHeight will be expanded to equally fill the height.
120 | @IBInspectable var cardShouldExpandHeadHeight: Bool = true
121 |
122 | /// Stretch the cards when scrolling up
123 | @IBInspectable var cardShouldStretchAtScrollTop: Bool = true
124 |
125 | /// Specifies the maximum height of the cards.
126 | /// But the height can be less if the frame size of collectionView is smaller.
127 | @IBInspectable var cardMaximumHeight: CGFloat = 0
128 |
129 | /// Count of bottom stacked cards when a card is revealed.
130 | /// Value must be between 0 and 10
131 | @IBInspectable var bottomNumberOfStackedCards: Int = 5
132 |
133 | /// All bottom stacked cards are scaled to produce the 3D effect.
134 | @IBInspectable var bottomStackedCardsShouldScale: Bool = true
135 |
136 | /// Specifies the margin for the top margin of a bottom stacked card.
137 | /// Value can be between 0 and 20
138 | @IBInspectable var bottomCardLookoutMargin: CGFloat = 10
139 |
140 | /// An additional topspace to show the top of the collectionViews backgroundView.
141 | @IBInspectable var spaceAtTopForBackgroundView: CGFloat = 0
142 |
143 | /// Snaps the scrollView if the contentOffset is on the 'spaceAtTopForBackgroundView'
144 | @IBInspectable var spaceAtTopShouldSnap: Bool = true
145 |
146 | /// Additional space at the bottom to expand the contentsize of the collectionView.
147 | @IBInspectable var spaceAtBottom: CGFloat = 0
148 |
149 | /// Area the top where to autoscroll while moving a card.
150 | @IBInspectable var scrollAreaTop: CGFloat = 120
151 |
152 | /// Area ot the bottom where to autoscroll while moving a card.
153 | @IBInspectable var scrollAreaBottom: CGFloat = 120
154 |
155 | /// The scrollView should snap the cardhead to the top.
156 | @IBInspectable var scrollShouldSnapCardHead: Bool = false
157 |
158 | /// Cards are stopping at top while scrolling.
159 | @IBInspectable var scrollStopCardsAtTop: Bool = true
160 |
161 | /// All cards are collapsed at bottom.
162 | @IBInspectable var collapseAllCards: Bool = false
163 |
164 | /// Contains the revealed index.
165 | /// ReadOnly.
166 | private(set) var revealedIndex: Int = -1
167 | ```
168 |
169 | Interface builder actions
170 | ```swift
171 | /////////////// InterfaceBuilder Actions
172 |
173 |
174 | /// Action for the InterfaceBuilder to flip back the revealed card.
175 | @IBAction func flipBackRevealedCardAction()
176 |
177 | /// Action for the InterfaceBuilder to unreveal the revealed card.
178 | @IBAction func unrevealRevealedCardAction()
179 |
180 | /// Action to collapse all cards.
181 | @IBAction func collapseAllCardsAction()
182 | ```
183 |
184 | Public functions
185 | ```swift
186 | /////////////// Public Functions
187 |
188 |
189 | /// Reveal a card at the given index.
190 | ///
191 | /// - Parameter index: The index of the card.
192 | /// - Parameter completion: An optional completion block. Will be executed the animation is finished.
193 | public func revealCardAt(index: Int, completion: (() -> Void)? = nil)
194 |
195 | /// Unreveal the revealed card
196 | ///
197 | /// - Parameter completion: An optional completion block. Will be executed the animation is finished.
198 | public func unrevealCard(completion: (() -> Void)? = nil)
199 |
200 |
201 | /// Flips the revealed card to the given view.
202 | /// The frame for the view will be the same as the cell
203 | ///
204 | /// - Parameter toView: The view for the backview of te card.
205 | /// - Parameter completion: An optional completion block. Will be executed the animation is finished.
206 | public func flipRevealedCard(toView: UIView, completion: (() -> Void)? = nil)
207 |
208 |
209 | /// Flips the flipped card back to the frontview.
210 | ///
211 | /// - Parameter completion: An optional completion block. Will be executed the animation is finished.
212 | public func flipRevealedCardBack(completion: (() -> Void)? = nil)
213 | ```
214 |
215 |
216 | ## License
217 |
218 | MIT License
219 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample/MenuTableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MenuTableViewController.swift
3 | // HFCardCollectionViewLayoutExample
4 | //
5 | // Created by Hendrik Frahmann on 31.10.16.
6 | // Copyright © 2016 Hendrik Frahmann. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | struct CardLayoutSetupOptions {
12 | var firstMovableIndex: Int = 0
13 | var cardHeadHeight: CGFloat = 80
14 | var cardShouldExpandHeadHeight: Bool = true
15 | var cardShouldStretchAtScrollTop: Bool = true
16 | var cardMaximumHeight: CGFloat = 0
17 | var bottomNumberOfStackedCards: Int = 5
18 | var bottomStackedCardsShouldScale: Bool = true
19 | var bottomCardLookoutMargin: CGFloat = 10
20 | var bottomStackedCardsMaximumScale: CGFloat = 1.0
21 | var bottomStackedCardsMinimumScale: CGFloat = 0.94
22 | var spaceAtTopForBackgroundView: CGFloat = 0
23 | var spaceAtTopShouldSnap: Bool = true
24 | var spaceAtBottom: CGFloat = 0
25 | var scrollAreaTop: CGFloat = 120
26 | var scrollAreaBottom: CGFloat = 120
27 | var scrollShouldSnapCardHead: Bool = false
28 | var scrollStopCardsAtTop: Bool = true
29 |
30 | var numberOfCards: Int = 15
31 | }
32 |
33 | class MenuTableViewController: UITableViewController {
34 |
35 | var hideNavigationBar = false
36 | var hideToolBar = false
37 |
38 | var defaults = CardLayoutSetupOptions()
39 | var numberFormatter = NumberFormatter()
40 |
41 | @IBOutlet var textfieldNumberOfCards: UITextField?
42 | @IBOutlet var textfieldFirstMovableIndex: UITextField?
43 | @IBOutlet var textfieldCardHeadHeight: UITextField?
44 | @IBOutlet var switchCardShouldExpandHeadHeight: UISwitch?
45 | @IBOutlet var switchCardShouldStretchAtScrollTop: UISwitch?
46 | @IBOutlet var textfieldCardMaximumHeight: UITextField?
47 | @IBOutlet var textfieldBottomNumberOfStackedCards: UITextField?
48 | @IBOutlet var switchBottomStackedCardsShouldScale: UISwitch?
49 | @IBOutlet var textfieldBottomCardLookoutMargin: UITextField?
50 | @IBOutlet var textfieldSpaceAtTopForBackgroundView: UITextField?
51 | @IBOutlet var textfieldBottomStackedCardsMinimumScale: UITextField?
52 | @IBOutlet var textfieldBottomStackedCardsMaximumScale: UITextField?
53 | @IBOutlet var switchSpaceAtTopShouldSnap: UISwitch?
54 | @IBOutlet var textfieldSpaceAtBottom: UITextField?
55 | @IBOutlet var textfieldScrollAreaTop: UITextField?
56 | @IBOutlet var textfieldScrollAreaBottom: UITextField?
57 | @IBOutlet var switchScrollShouldSnapCardHead: UISwitch?
58 | @IBOutlet var switchScrollStopCardsAtTop: UISwitch?
59 |
60 | override func viewDidLoad() {
61 | self.numberFormatter.locale = Locale(identifier: "en_US")
62 | super.viewDidLoad()
63 | }
64 |
65 | override func viewWillAppear(_ animated: Bool) {
66 | super.viewWillAppear(animated)
67 | self.navigationController?.isNavigationBarHidden = false
68 | self.navigationController?.isToolbarHidden = true
69 | }
70 |
71 | override func viewWillDisappear(_ animated: Bool) {
72 | super.viewWillDisappear(animated)
73 | UIApplication.shared.keyWindow?.endEditing(true)
74 | self.navigationController?.isNavigationBarHidden = self.hideNavigationBar
75 | self.navigationController?.isToolbarHidden = self.hideToolBar
76 | }
77 |
78 | // MARK: Actions
79 |
80 | @IBAction func resetAction() {
81 | self.textfieldNumberOfCards?.text = String(self.defaults.numberOfCards)
82 | self.textfieldFirstMovableIndex?.text = String(self.defaults.firstMovableIndex)
83 | self.textfieldCardHeadHeight?.text = self.stringFromFloat(self.defaults.cardHeadHeight)
84 | self.switchCardShouldExpandHeadHeight?.isOn = self.defaults.cardShouldExpandHeadHeight
85 | self.switchCardShouldStretchAtScrollTop?.isOn = self.defaults.cardShouldStretchAtScrollTop
86 | self.textfieldCardMaximumHeight?.text = self.stringFromFloat(self.defaults.cardMaximumHeight)
87 | self.textfieldBottomNumberOfStackedCards?.text = String(self.defaults.bottomNumberOfStackedCards)
88 | self.switchBottomStackedCardsShouldScale?.isOn = self.defaults.bottomStackedCardsShouldScale
89 | self.textfieldBottomCardLookoutMargin?.text = self.stringFromFloat(self.defaults.bottomCardLookoutMargin)
90 | self.textfieldSpaceAtTopForBackgroundView?.text = self.stringFromFloat(self.defaults.spaceAtTopForBackgroundView)
91 | self.switchSpaceAtTopShouldSnap?.isOn = self.defaults.spaceAtTopShouldSnap
92 | self.textfieldSpaceAtBottom?.text = self.stringFromFloat(self.defaults.spaceAtBottom)
93 | self.textfieldScrollAreaTop?.text = self.stringFromFloat(self.defaults.scrollAreaTop)
94 | self.textfieldScrollAreaBottom?.text = self.stringFromFloat(self.defaults.scrollAreaBottom)
95 | self.switchScrollShouldSnapCardHead?.isOn = self.defaults.scrollShouldSnapCardHead
96 | self.switchScrollStopCardsAtTop?.isOn = self.defaults.scrollStopCardsAtTop
97 | self.textfieldBottomStackedCardsMinimumScale?.text = self.stringFromFloat(self.defaults.bottomStackedCardsMinimumScale)
98 | self.textfieldBottomStackedCardsMaximumScale?.text = self.stringFromFloat(self.defaults.bottomStackedCardsMaximumScale)
99 | }
100 |
101 | // MARK: Navigation
102 |
103 | // In a storyboard-based application, you will often want to do a little preparation before navigation
104 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
105 | if let controller = segue.destination as? ExampleViewController {
106 |
107 | var layoutOptions = CardLayoutSetupOptions()
108 | layoutOptions.numberOfCards = self.getIntFromTextfield(self.textfieldNumberOfCards!)
109 | layoutOptions.firstMovableIndex = self.getIntFromTextfield(self.textfieldFirstMovableIndex!)
110 | layoutOptions.cardHeadHeight = self.getFloatFromTextfield(self.textfieldCardHeadHeight!)
111 | layoutOptions.cardShouldExpandHeadHeight = self.switchCardShouldExpandHeadHeight!.isOn
112 | layoutOptions.cardShouldStretchAtScrollTop = self.switchCardShouldStretchAtScrollTop!.isOn
113 | layoutOptions.cardMaximumHeight = self.getFloatFromTextfield(self.textfieldCardMaximumHeight!)
114 | layoutOptions.bottomNumberOfStackedCards = self.getIntFromTextfield(self.textfieldBottomNumberOfStackedCards!)
115 | layoutOptions.bottomStackedCardsShouldScale = self.switchBottomStackedCardsShouldScale!.isOn
116 | layoutOptions.bottomCardLookoutMargin = self.getFloatFromTextfield(self.textfieldBottomCardLookoutMargin!)
117 | layoutOptions.spaceAtTopForBackgroundView = self.getFloatFromTextfield(self.textfieldSpaceAtTopForBackgroundView!)
118 | layoutOptions.spaceAtTopShouldSnap = self.switchSpaceAtTopShouldSnap!.isOn
119 | layoutOptions.spaceAtBottom = self.getFloatFromTextfield(self.textfieldSpaceAtBottom!)
120 | layoutOptions.scrollAreaTop = self.getFloatFromTextfield(self.textfieldScrollAreaTop!)
121 | layoutOptions.scrollAreaBottom = self.getFloatFromTextfield(self.textfieldScrollAreaBottom!)
122 | layoutOptions.scrollShouldSnapCardHead = self.switchScrollShouldSnapCardHead!.isOn
123 | layoutOptions.scrollStopCardsAtTop = self.switchScrollStopCardsAtTop!.isOn
124 | layoutOptions.bottomStackedCardsMinimumScale = self.getFloatFromTextfield(self.textfieldBottomStackedCardsMinimumScale!)
125 | layoutOptions.bottomStackedCardsMaximumScale = self.getFloatFromTextfield(self.textfieldBottomStackedCardsMaximumScale!)
126 |
127 | controller.cardLayoutOptions = layoutOptions
128 |
129 | if(segue.identifier == "AsRootController") {
130 | self.hideNavigationBar = true
131 | self.hideToolBar = true
132 | controller.shouldSetupBackgroundView = true
133 | }
134 | if(segue.identifier == "WithinNavigationController") {
135 | self.hideNavigationBar = false
136 | self.hideToolBar = true
137 | }
138 | if(segue.identifier == "WithNavigationAndToolbar") {
139 | self.hideNavigationBar = false
140 | self.hideToolBar = false
141 | }
142 | }
143 | }
144 |
145 | // MARK: Private functions
146 |
147 | private func getIntFromTextfield(_ textfield: UITextField) -> Int {
148 | if let n = self.numberFormatter.number(from: (textfield.text)!) {
149 | return n.intValue
150 | }
151 | return 0
152 | }
153 |
154 | private func getFloatFromTextfield(_ textfield: UITextField) -> CGFloat {
155 | if let n = self.numberFormatter.number(from: (textfield.text)!) {
156 | return CGFloat(truncating: n)
157 | }
158 | return 0
159 | }
160 |
161 | private func stringFromFloat(_ float: CGFloat) -> String {
162 | return String(Int(float))
163 | }
164 |
165 | }
166 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayout.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 416D2D671E5F113600D8A570 /* HFCardCollectionViewLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 416D2D651E5F113600D8A570 /* HFCardCollectionViewLayout.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 416D2D711E5F117500D8A570 /* HFCardCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 416D2D6D1E5F117500D8A570 /* HFCardCollectionViewCell.swift */; };
12 | 416D2D721E5F117500D8A570 /* HFCardCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 416D2D6E1E5F117500D8A570 /* HFCardCollectionViewLayout.swift */; };
13 | 416D2D731E5F117500D8A570 /* HFCardCollectionViewLayoutDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 416D2D6F1E5F117500D8A570 /* HFCardCollectionViewLayoutDelegate.swift */; };
14 | 416D2D741E5F117500D8A570 /* UICollectionViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 416D2D701E5F117500D8A570 /* UICollectionViewExtensions.swift */; };
15 | /* End PBXBuildFile section */
16 |
17 | /* Begin PBXFileReference section */
18 | 416D2D621E5F113600D8A570 /* HFCardCollectionViewLayout.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = HFCardCollectionViewLayout.framework; sourceTree = BUILT_PRODUCTS_DIR; };
19 | 416D2D651E5F113600D8A570 /* HFCardCollectionViewLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HFCardCollectionViewLayout.h; sourceTree = ""; };
20 | 416D2D661E5F113600D8A570 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
21 | 416D2D6D1E5F117500D8A570 /* HFCardCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HFCardCollectionViewCell.swift; path = Source/HFCardCollectionViewCell.swift; sourceTree = SOURCE_ROOT; };
22 | 416D2D6E1E5F117500D8A570 /* HFCardCollectionViewLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HFCardCollectionViewLayout.swift; path = Source/HFCardCollectionViewLayout.swift; sourceTree = SOURCE_ROOT; };
23 | 416D2D6F1E5F117500D8A570 /* HFCardCollectionViewLayoutDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HFCardCollectionViewLayoutDelegate.swift; path = Source/HFCardCollectionViewLayoutDelegate.swift; sourceTree = SOURCE_ROOT; };
24 | 416D2D701E5F117500D8A570 /* UICollectionViewExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UICollectionViewExtensions.swift; path = Source/UICollectionViewExtensions.swift; sourceTree = SOURCE_ROOT; };
25 | /* End PBXFileReference section */
26 |
27 | /* Begin PBXFrameworksBuildPhase section */
28 | 416D2D5E1E5F113600D8A570 /* Frameworks */ = {
29 | isa = PBXFrameworksBuildPhase;
30 | buildActionMask = 2147483647;
31 | files = (
32 | );
33 | runOnlyForDeploymentPostprocessing = 0;
34 | };
35 | /* End PBXFrameworksBuildPhase section */
36 |
37 | /* Begin PBXGroup section */
38 | 416D2D581E5F113600D8A570 = {
39 | isa = PBXGroup;
40 | children = (
41 | 416D2D641E5F113600D8A570 /* HFCardCollectionViewLayout */,
42 | 416D2D631E5F113600D8A570 /* Products */,
43 | );
44 | sourceTree = "";
45 | };
46 | 416D2D631E5F113600D8A570 /* Products */ = {
47 | isa = PBXGroup;
48 | children = (
49 | 416D2D621E5F113600D8A570 /* HFCardCollectionViewLayout.framework */,
50 | );
51 | name = Products;
52 | sourceTree = "";
53 | };
54 | 416D2D641E5F113600D8A570 /* HFCardCollectionViewLayout */ = {
55 | isa = PBXGroup;
56 | children = (
57 | 416D2D6D1E5F117500D8A570 /* HFCardCollectionViewCell.swift */,
58 | 416D2D6E1E5F117500D8A570 /* HFCardCollectionViewLayout.swift */,
59 | 416D2D6F1E5F117500D8A570 /* HFCardCollectionViewLayoutDelegate.swift */,
60 | 416D2D701E5F117500D8A570 /* UICollectionViewExtensions.swift */,
61 | 416D2D651E5F113600D8A570 /* HFCardCollectionViewLayout.h */,
62 | 416D2D661E5F113600D8A570 /* Info.plist */,
63 | );
64 | path = HFCardCollectionViewLayout;
65 | sourceTree = "";
66 | };
67 | /* End PBXGroup section */
68 |
69 | /* Begin PBXHeadersBuildPhase section */
70 | 416D2D5F1E5F113600D8A570 /* Headers */ = {
71 | isa = PBXHeadersBuildPhase;
72 | buildActionMask = 2147483647;
73 | files = (
74 | 416D2D671E5F113600D8A570 /* HFCardCollectionViewLayout.h in Headers */,
75 | );
76 | runOnlyForDeploymentPostprocessing = 0;
77 | };
78 | /* End PBXHeadersBuildPhase section */
79 |
80 | /* Begin PBXNativeTarget section */
81 | 416D2D611E5F113600D8A570 /* HFCardCollectionViewLayout */ = {
82 | isa = PBXNativeTarget;
83 | buildConfigurationList = 416D2D6A1E5F113600D8A570 /* Build configuration list for PBXNativeTarget "HFCardCollectionViewLayout" */;
84 | buildPhases = (
85 | 416D2D5D1E5F113600D8A570 /* Sources */,
86 | 416D2D5E1E5F113600D8A570 /* Frameworks */,
87 | 416D2D5F1E5F113600D8A570 /* Headers */,
88 | 416D2D601E5F113600D8A570 /* Resources */,
89 | );
90 | buildRules = (
91 | );
92 | dependencies = (
93 | );
94 | name = HFCardCollectionViewLayout;
95 | productName = HFCardCollectionViewLayout;
96 | productReference = 416D2D621E5F113600D8A570 /* HFCardCollectionViewLayout.framework */;
97 | productType = "com.apple.product-type.framework";
98 | };
99 | /* End PBXNativeTarget section */
100 |
101 | /* Begin PBXProject section */
102 | 416D2D591E5F113600D8A570 /* Project object */ = {
103 | isa = PBXProject;
104 | attributes = {
105 | LastUpgradeCheck = 0820;
106 | ORGANIZATIONNAME = "hendrik-frahmann";
107 | TargetAttributes = {
108 | 416D2D611E5F113600D8A570 = {
109 | CreatedOnToolsVersion = 8.2.1;
110 | LastSwiftMigration = 0820;
111 | ProvisioningStyle = Automatic;
112 | };
113 | };
114 | };
115 | buildConfigurationList = 416D2D5C1E5F113600D8A570 /* Build configuration list for PBXProject "HFCardCollectionViewLayout" */;
116 | compatibilityVersion = "Xcode 3.2";
117 | developmentRegion = English;
118 | hasScannedForEncodings = 0;
119 | knownRegions = (
120 | en,
121 | );
122 | mainGroup = 416D2D581E5F113600D8A570;
123 | productRefGroup = 416D2D631E5F113600D8A570 /* Products */;
124 | projectDirPath = "";
125 | projectRoot = "";
126 | targets = (
127 | 416D2D611E5F113600D8A570 /* HFCardCollectionViewLayout */,
128 | );
129 | };
130 | /* End PBXProject section */
131 |
132 | /* Begin PBXResourcesBuildPhase section */
133 | 416D2D601E5F113600D8A570 /* Resources */ = {
134 | isa = PBXResourcesBuildPhase;
135 | buildActionMask = 2147483647;
136 | files = (
137 | );
138 | runOnlyForDeploymentPostprocessing = 0;
139 | };
140 | /* End PBXResourcesBuildPhase section */
141 |
142 | /* Begin PBXSourcesBuildPhase section */
143 | 416D2D5D1E5F113600D8A570 /* Sources */ = {
144 | isa = PBXSourcesBuildPhase;
145 | buildActionMask = 2147483647;
146 | files = (
147 | 416D2D741E5F117500D8A570 /* UICollectionViewExtensions.swift in Sources */,
148 | 416D2D721E5F117500D8A570 /* HFCardCollectionViewLayout.swift in Sources */,
149 | 416D2D711E5F117500D8A570 /* HFCardCollectionViewCell.swift in Sources */,
150 | 416D2D731E5F117500D8A570 /* HFCardCollectionViewLayoutDelegate.swift in Sources */,
151 | );
152 | runOnlyForDeploymentPostprocessing = 0;
153 | };
154 | /* End PBXSourcesBuildPhase section */
155 |
156 | /* Begin XCBuildConfiguration section */
157 | 416D2D681E5F113600D8A570 /* Debug */ = {
158 | isa = XCBuildConfiguration;
159 | buildSettings = {
160 | ALWAYS_SEARCH_USER_PATHS = NO;
161 | CLANG_ANALYZER_NONNULL = YES;
162 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
163 | CLANG_CXX_LIBRARY = "libc++";
164 | CLANG_ENABLE_MODULES = YES;
165 | CLANG_ENABLE_OBJC_ARC = YES;
166 | CLANG_WARN_BOOL_CONVERSION = YES;
167 | CLANG_WARN_CONSTANT_CONVERSION = YES;
168 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
169 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
170 | CLANG_WARN_EMPTY_BODY = YES;
171 | CLANG_WARN_ENUM_CONVERSION = YES;
172 | CLANG_WARN_INFINITE_RECURSION = YES;
173 | CLANG_WARN_INT_CONVERSION = YES;
174 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
175 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
176 | CLANG_WARN_UNREACHABLE_CODE = YES;
177 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
178 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
179 | COPY_PHASE_STRIP = NO;
180 | CURRENT_PROJECT_VERSION = 1;
181 | DEBUG_INFORMATION_FORMAT = dwarf;
182 | ENABLE_STRICT_OBJC_MSGSEND = YES;
183 | ENABLE_TESTABILITY = YES;
184 | GCC_C_LANGUAGE_STANDARD = gnu99;
185 | GCC_DYNAMIC_NO_PIC = NO;
186 | GCC_NO_COMMON_BLOCKS = YES;
187 | GCC_OPTIMIZATION_LEVEL = 0;
188 | GCC_PREPROCESSOR_DEFINITIONS = (
189 | "DEBUG=1",
190 | "$(inherited)",
191 | );
192 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
193 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
194 | GCC_WARN_UNDECLARED_SELECTOR = YES;
195 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
196 | GCC_WARN_UNUSED_FUNCTION = YES;
197 | GCC_WARN_UNUSED_VARIABLE = YES;
198 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
199 | MTL_ENABLE_DEBUG_INFO = YES;
200 | ONLY_ACTIVE_ARCH = YES;
201 | SDKROOT = iphoneos;
202 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
203 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
204 | TARGETED_DEVICE_FAMILY = "1,2";
205 | VERSIONING_SYSTEM = "apple-generic";
206 | VERSION_INFO_PREFIX = "";
207 | };
208 | name = Debug;
209 | };
210 | 416D2D691E5F113600D8A570 /* Release */ = {
211 | isa = XCBuildConfiguration;
212 | buildSettings = {
213 | ALWAYS_SEARCH_USER_PATHS = NO;
214 | CLANG_ANALYZER_NONNULL = YES;
215 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
216 | CLANG_CXX_LIBRARY = "libc++";
217 | CLANG_ENABLE_MODULES = YES;
218 | CLANG_ENABLE_OBJC_ARC = YES;
219 | CLANG_WARN_BOOL_CONVERSION = YES;
220 | CLANG_WARN_CONSTANT_CONVERSION = YES;
221 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
222 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
223 | CLANG_WARN_EMPTY_BODY = YES;
224 | CLANG_WARN_ENUM_CONVERSION = YES;
225 | CLANG_WARN_INFINITE_RECURSION = YES;
226 | CLANG_WARN_INT_CONVERSION = YES;
227 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
228 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
229 | CLANG_WARN_UNREACHABLE_CODE = YES;
230 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
231 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
232 | COPY_PHASE_STRIP = NO;
233 | CURRENT_PROJECT_VERSION = 1;
234 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
235 | ENABLE_NS_ASSERTIONS = NO;
236 | ENABLE_STRICT_OBJC_MSGSEND = YES;
237 | GCC_C_LANGUAGE_STANDARD = gnu99;
238 | GCC_NO_COMMON_BLOCKS = YES;
239 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
240 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
241 | GCC_WARN_UNDECLARED_SELECTOR = YES;
242 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
243 | GCC_WARN_UNUSED_FUNCTION = YES;
244 | GCC_WARN_UNUSED_VARIABLE = YES;
245 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
246 | MTL_ENABLE_DEBUG_INFO = NO;
247 | SDKROOT = iphoneos;
248 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
249 | TARGETED_DEVICE_FAMILY = "1,2";
250 | VALIDATE_PRODUCT = YES;
251 | VERSIONING_SYSTEM = "apple-generic";
252 | VERSION_INFO_PREFIX = "";
253 | };
254 | name = Release;
255 | };
256 | 416D2D6B1E5F113600D8A570 /* Debug */ = {
257 | isa = XCBuildConfiguration;
258 | buildSettings = {
259 | CLANG_ENABLE_MODULES = YES;
260 | CODE_SIGN_IDENTITY = "";
261 | DEFINES_MODULE = YES;
262 | DYLIB_COMPATIBILITY_VERSION = 1;
263 | DYLIB_CURRENT_VERSION = 1;
264 | DYLIB_INSTALL_NAME_BASE = "@rpath";
265 | INFOPLIST_FILE = HFCardCollectionViewLayout/Info.plist;
266 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
267 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
268 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
269 | PRODUCT_BUNDLE_IDENTIFIER = "com.hendrik-frahmann.HFCardCollectionViewLayout";
270 | PRODUCT_NAME = "$(TARGET_NAME)";
271 | SKIP_INSTALL = YES;
272 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
273 | SWIFT_VERSION = 3.0;
274 | };
275 | name = Debug;
276 | };
277 | 416D2D6C1E5F113600D8A570 /* Release */ = {
278 | isa = XCBuildConfiguration;
279 | buildSettings = {
280 | CLANG_ENABLE_MODULES = YES;
281 | CODE_SIGN_IDENTITY = "";
282 | DEFINES_MODULE = YES;
283 | DYLIB_COMPATIBILITY_VERSION = 1;
284 | DYLIB_CURRENT_VERSION = 1;
285 | DYLIB_INSTALL_NAME_BASE = "@rpath";
286 | INFOPLIST_FILE = HFCardCollectionViewLayout/Info.plist;
287 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
288 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
289 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
290 | PRODUCT_BUNDLE_IDENTIFIER = "com.hendrik-frahmann.HFCardCollectionViewLayout";
291 | PRODUCT_NAME = "$(TARGET_NAME)";
292 | SKIP_INSTALL = YES;
293 | SWIFT_VERSION = 3.0;
294 | };
295 | name = Release;
296 | };
297 | /* End XCBuildConfiguration section */
298 |
299 | /* Begin XCConfigurationList section */
300 | 416D2D5C1E5F113600D8A570 /* Build configuration list for PBXProject "HFCardCollectionViewLayout" */ = {
301 | isa = XCConfigurationList;
302 | buildConfigurations = (
303 | 416D2D681E5F113600D8A570 /* Debug */,
304 | 416D2D691E5F113600D8A570 /* Release */,
305 | );
306 | defaultConfigurationIsVisible = 0;
307 | defaultConfigurationName = Release;
308 | };
309 | 416D2D6A1E5F113600D8A570 /* Build configuration list for PBXNativeTarget "HFCardCollectionViewLayout" */ = {
310 | isa = XCConfigurationList;
311 | buildConfigurations = (
312 | 416D2D6B1E5F113600D8A570 /* Debug */,
313 | 416D2D6C1E5F113600D8A570 /* Release */,
314 | );
315 | defaultConfigurationIsVisible = 0;
316 | defaultConfigurationName = Release;
317 | };
318 | /* End XCConfigurationList section */
319 | };
320 | rootObject = 416D2D591E5F113600D8A570 /* Project object */;
321 | }
322 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/HFCardCollectionViewLayoutExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 12520E240E28F70E5C9233D1 /* Pods_HFCardCollectionViewLayoutExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BC84C6ADD77ADD52C0B6EEB /* Pods_HFCardCollectionViewLayoutExample.framework */; };
11 | B1472D191DCA7CDD007464CA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1472D181DCA7CDD007464CA /* QuartzCore.framework */; };
12 | B1472D1B1DCA8BBE007464CA /* ExampleCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1472D1A1DCA8BBE007464CA /* ExampleCollectionViewCell.swift */; };
13 | EEBBC63A1DC9E19E00BBC1EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBBC6391DC9E19E00BBC1EE /* AppDelegate.swift */; };
14 | EEBBC63C1DC9E19E00BBC1EE /* ExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBBC63B1DC9E19E00BBC1EE /* ExampleViewController.swift */; };
15 | EEBBC63F1DC9E19E00BBC1EE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EEBBC63D1DC9E19E00BBC1EE /* Main.storyboard */; };
16 | EEBBC6411DC9E19E00BBC1EE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EEBBC6401DC9E19E00BBC1EE /* Assets.xcassets */; };
17 | EEBBC6441DC9E19F00BBC1EE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EEBBC6421DC9E19F00BBC1EE /* LaunchScreen.storyboard */; };
18 | EEBBC64F1DC9E23700BBC1EE /* MenuTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBBC64E1DC9E23700BBC1EE /* MenuTableViewController.swift */; };
19 | /* End PBXBuildFile section */
20 |
21 | /* Begin PBXFileReference section */
22 | 20F29DBCFC8ECCD0C7119C69 /* Pods-HFCardCollectionViewLayoutExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HFCardCollectionViewLayoutExample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample.debug.xcconfig"; sourceTree = ""; };
23 | 896D468DC417110E7A811BB6 /* Pods-HFCardCollectionViewLayoutExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HFCardCollectionViewLayoutExample.release.xcconfig"; path = "Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample.release.xcconfig"; sourceTree = ""; };
24 | 8BC84C6ADD77ADD52C0B6EEB /* Pods_HFCardCollectionViewLayoutExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_HFCardCollectionViewLayoutExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
25 | B1472D181DCA7CDD007464CA /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
26 | B1472D1A1DCA8BBE007464CA /* ExampleCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleCollectionViewCell.swift; sourceTree = ""; };
27 | EEBBC6361DC9E19E00BBC1EE /* HFCardCollectionViewLayoutExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HFCardCollectionViewLayoutExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
28 | EEBBC6391DC9E19E00BBC1EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
29 | EEBBC63B1DC9E19E00BBC1EE /* ExampleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleViewController.swift; sourceTree = ""; };
30 | EEBBC63E1DC9E19E00BBC1EE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
31 | EEBBC6401DC9E19E00BBC1EE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
32 | EEBBC6431DC9E19F00BBC1EE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
33 | EEBBC6451DC9E19F00BBC1EE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
34 | EEBBC64E1DC9E23700BBC1EE /* MenuTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuTableViewController.swift; sourceTree = ""; };
35 | /* End PBXFileReference section */
36 |
37 | /* Begin PBXFrameworksBuildPhase section */
38 | EEBBC6331DC9E19E00BBC1EE /* Frameworks */ = {
39 | isa = PBXFrameworksBuildPhase;
40 | buildActionMask = 2147483647;
41 | files = (
42 | B1472D191DCA7CDD007464CA /* QuartzCore.framework in Frameworks */,
43 | 12520E240E28F70E5C9233D1 /* Pods_HFCardCollectionViewLayoutExample.framework in Frameworks */,
44 | );
45 | runOnlyForDeploymentPostprocessing = 0;
46 | };
47 | /* End PBXFrameworksBuildPhase section */
48 |
49 | /* Begin PBXGroup section */
50 | A138CA03463F1B14B9C087DE /* Pods */ = {
51 | isa = PBXGroup;
52 | children = (
53 | 20F29DBCFC8ECCD0C7119C69 /* Pods-HFCardCollectionViewLayoutExample.debug.xcconfig */,
54 | 896D468DC417110E7A811BB6 /* Pods-HFCardCollectionViewLayoutExample.release.xcconfig */,
55 | );
56 | name = Pods;
57 | sourceTree = "";
58 | };
59 | B1472D171DCA7CDD007464CA /* Frameworks */ = {
60 | isa = PBXGroup;
61 | children = (
62 | B1472D181DCA7CDD007464CA /* QuartzCore.framework */,
63 | 8BC84C6ADD77ADD52C0B6EEB /* Pods_HFCardCollectionViewLayoutExample.framework */,
64 | );
65 | name = Frameworks;
66 | sourceTree = "";
67 | };
68 | EEBBC62D1DC9E19E00BBC1EE = {
69 | isa = PBXGroup;
70 | children = (
71 | EEBBC6381DC9E19E00BBC1EE /* HFCardCollectionViewLayoutExample */,
72 | EEBBC6371DC9E19E00BBC1EE /* Products */,
73 | B1472D171DCA7CDD007464CA /* Frameworks */,
74 | A138CA03463F1B14B9C087DE /* Pods */,
75 | );
76 | sourceTree = "";
77 | };
78 | EEBBC6371DC9E19E00BBC1EE /* Products */ = {
79 | isa = PBXGroup;
80 | children = (
81 | EEBBC6361DC9E19E00BBC1EE /* HFCardCollectionViewLayoutExample.app */,
82 | );
83 | name = Products;
84 | sourceTree = "";
85 | };
86 | EEBBC6381DC9E19E00BBC1EE /* HFCardCollectionViewLayoutExample */ = {
87 | isa = PBXGroup;
88 | children = (
89 | EEBBC6391DC9E19E00BBC1EE /* AppDelegate.swift */,
90 | EEBBC64E1DC9E23700BBC1EE /* MenuTableViewController.swift */,
91 | EEBBC63B1DC9E19E00BBC1EE /* ExampleViewController.swift */,
92 | B1472D1A1DCA8BBE007464CA /* ExampleCollectionViewCell.swift */,
93 | EEBBC63D1DC9E19E00BBC1EE /* Main.storyboard */,
94 | EEBBC6401DC9E19E00BBC1EE /* Assets.xcassets */,
95 | EEBBC6421DC9E19F00BBC1EE /* LaunchScreen.storyboard */,
96 | EEBBC6451DC9E19F00BBC1EE /* Info.plist */,
97 | );
98 | path = HFCardCollectionViewLayoutExample;
99 | sourceTree = "";
100 | };
101 | /* End PBXGroup section */
102 |
103 | /* Begin PBXNativeTarget section */
104 | EEBBC6351DC9E19E00BBC1EE /* HFCardCollectionViewLayoutExample */ = {
105 | isa = PBXNativeTarget;
106 | buildConfigurationList = EEBBC6481DC9E19F00BBC1EE /* Build configuration list for PBXNativeTarget "HFCardCollectionViewLayoutExample" */;
107 | buildPhases = (
108 | DF784A192065786A9B3017F5 /* [CP] Check Pods Manifest.lock */,
109 | EEBBC6321DC9E19E00BBC1EE /* Sources */,
110 | EEBBC6331DC9E19E00BBC1EE /* Frameworks */,
111 | EEBBC6341DC9E19E00BBC1EE /* Resources */,
112 | 906D250FBF2D46B24EB39BA1 /* [CP] Embed Pods Frameworks */,
113 | 9616E71599BA57C3E0C8514A /* [CP] Copy Pods Resources */,
114 | );
115 | buildRules = (
116 | );
117 | dependencies = (
118 | );
119 | name = HFCardCollectionViewLayoutExample;
120 | productName = HFCardCollectionViewLayoutExample;
121 | productReference = EEBBC6361DC9E19E00BBC1EE /* HFCardCollectionViewLayoutExample.app */;
122 | productType = "com.apple.product-type.application";
123 | };
124 | /* End PBXNativeTarget section */
125 |
126 | /* Begin PBXProject section */
127 | EEBBC62E1DC9E19E00BBC1EE /* Project object */ = {
128 | isa = PBXProject;
129 | attributes = {
130 | LastSwiftUpdateCheck = 0810;
131 | LastUpgradeCheck = 0920;
132 | ORGANIZATIONNAME = "Hendrik Frahmann";
133 | TargetAttributes = {
134 | EEBBC6351DC9E19E00BBC1EE = {
135 | CreatedOnToolsVersion = 8.1;
136 | DevelopmentTeam = TKESRF7W2Y;
137 | LastSwiftMigration = 0920;
138 | ProvisioningStyle = Automatic;
139 | };
140 | };
141 | };
142 | buildConfigurationList = EEBBC6311DC9E19E00BBC1EE /* Build configuration list for PBXProject "HFCardCollectionViewLayoutExample" */;
143 | compatibilityVersion = "Xcode 3.2";
144 | developmentRegion = English;
145 | hasScannedForEncodings = 0;
146 | knownRegions = (
147 | en,
148 | Base,
149 | );
150 | mainGroup = EEBBC62D1DC9E19E00BBC1EE;
151 | productRefGroup = EEBBC6371DC9E19E00BBC1EE /* Products */;
152 | projectDirPath = "";
153 | projectRoot = "";
154 | targets = (
155 | EEBBC6351DC9E19E00BBC1EE /* HFCardCollectionViewLayoutExample */,
156 | );
157 | };
158 | /* End PBXProject section */
159 |
160 | /* Begin PBXResourcesBuildPhase section */
161 | EEBBC6341DC9E19E00BBC1EE /* Resources */ = {
162 | isa = PBXResourcesBuildPhase;
163 | buildActionMask = 2147483647;
164 | files = (
165 | EEBBC6441DC9E19F00BBC1EE /* LaunchScreen.storyboard in Resources */,
166 | EEBBC6411DC9E19E00BBC1EE /* Assets.xcassets in Resources */,
167 | EEBBC63F1DC9E19E00BBC1EE /* Main.storyboard in Resources */,
168 | );
169 | runOnlyForDeploymentPostprocessing = 0;
170 | };
171 | /* End PBXResourcesBuildPhase section */
172 |
173 | /* Begin PBXShellScriptBuildPhase section */
174 | 906D250FBF2D46B24EB39BA1 /* [CP] Embed Pods Frameworks */ = {
175 | isa = PBXShellScriptBuildPhase;
176 | buildActionMask = 2147483647;
177 | files = (
178 | );
179 | inputPaths = (
180 | );
181 | name = "[CP] Embed Pods Frameworks";
182 | outputPaths = (
183 | );
184 | runOnlyForDeploymentPostprocessing = 0;
185 | shellPath = /bin/sh;
186 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample-frameworks.sh\"\n";
187 | showEnvVarsInLog = 0;
188 | };
189 | 9616E71599BA57C3E0C8514A /* [CP] Copy Pods Resources */ = {
190 | isa = PBXShellScriptBuildPhase;
191 | buildActionMask = 2147483647;
192 | files = (
193 | );
194 | inputPaths = (
195 | );
196 | name = "[CP] Copy Pods Resources";
197 | outputPaths = (
198 | );
199 | runOnlyForDeploymentPostprocessing = 0;
200 | shellPath = /bin/sh;
201 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample-resources.sh\"\n";
202 | showEnvVarsInLog = 0;
203 | };
204 | DF784A192065786A9B3017F5 /* [CP] Check Pods Manifest.lock */ = {
205 | isa = PBXShellScriptBuildPhase;
206 | buildActionMask = 2147483647;
207 | files = (
208 | );
209 | inputPaths = (
210 | );
211 | name = "[CP] Check Pods Manifest.lock";
212 | outputPaths = (
213 | );
214 | runOnlyForDeploymentPostprocessing = 0;
215 | shellPath = /bin/sh;
216 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
217 | showEnvVarsInLog = 0;
218 | };
219 | /* End PBXShellScriptBuildPhase section */
220 |
221 | /* Begin PBXSourcesBuildPhase section */
222 | EEBBC6321DC9E19E00BBC1EE /* Sources */ = {
223 | isa = PBXSourcesBuildPhase;
224 | buildActionMask = 2147483647;
225 | files = (
226 | EEBBC64F1DC9E23700BBC1EE /* MenuTableViewController.swift in Sources */,
227 | B1472D1B1DCA8BBE007464CA /* ExampleCollectionViewCell.swift in Sources */,
228 | EEBBC63C1DC9E19E00BBC1EE /* ExampleViewController.swift in Sources */,
229 | EEBBC63A1DC9E19E00BBC1EE /* AppDelegate.swift in Sources */,
230 | );
231 | runOnlyForDeploymentPostprocessing = 0;
232 | };
233 | /* End PBXSourcesBuildPhase section */
234 |
235 | /* Begin PBXVariantGroup section */
236 | EEBBC63D1DC9E19E00BBC1EE /* Main.storyboard */ = {
237 | isa = PBXVariantGroup;
238 | children = (
239 | EEBBC63E1DC9E19E00BBC1EE /* Base */,
240 | );
241 | name = Main.storyboard;
242 | sourceTree = "";
243 | };
244 | EEBBC6421DC9E19F00BBC1EE /* LaunchScreen.storyboard */ = {
245 | isa = PBXVariantGroup;
246 | children = (
247 | EEBBC6431DC9E19F00BBC1EE /* Base */,
248 | );
249 | name = LaunchScreen.storyboard;
250 | sourceTree = "";
251 | };
252 | /* End PBXVariantGroup section */
253 |
254 | /* Begin XCBuildConfiguration section */
255 | EEBBC6461DC9E19F00BBC1EE /* Debug */ = {
256 | isa = XCBuildConfiguration;
257 | buildSettings = {
258 | ALWAYS_SEARCH_USER_PATHS = NO;
259 | CLANG_ANALYZER_NONNULL = YES;
260 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
261 | CLANG_CXX_LIBRARY = "libc++";
262 | CLANG_ENABLE_MODULES = YES;
263 | CLANG_ENABLE_OBJC_ARC = YES;
264 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
265 | CLANG_WARN_BOOL_CONVERSION = YES;
266 | CLANG_WARN_COMMA = YES;
267 | CLANG_WARN_CONSTANT_CONVERSION = YES;
268 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
269 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
270 | CLANG_WARN_EMPTY_BODY = YES;
271 | CLANG_WARN_ENUM_CONVERSION = YES;
272 | CLANG_WARN_INFINITE_RECURSION = YES;
273 | CLANG_WARN_INT_CONVERSION = YES;
274 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
275 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
276 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
277 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
278 | CLANG_WARN_STRICT_PROTOTYPES = YES;
279 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
280 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
281 | CLANG_WARN_UNREACHABLE_CODE = YES;
282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
283 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
284 | COPY_PHASE_STRIP = NO;
285 | DEBUG_INFORMATION_FORMAT = dwarf;
286 | ENABLE_STRICT_OBJC_MSGSEND = YES;
287 | ENABLE_TESTABILITY = YES;
288 | GCC_C_LANGUAGE_STANDARD = gnu99;
289 | GCC_DYNAMIC_NO_PIC = NO;
290 | GCC_NO_COMMON_BLOCKS = YES;
291 | GCC_OPTIMIZATION_LEVEL = 0;
292 | GCC_PREPROCESSOR_DEFINITIONS = (
293 | "DEBUG=1",
294 | "$(inherited)",
295 | );
296 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
297 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
298 | GCC_WARN_UNDECLARED_SELECTOR = YES;
299 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
300 | GCC_WARN_UNUSED_FUNCTION = YES;
301 | GCC_WARN_UNUSED_VARIABLE = YES;
302 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
303 | MTL_ENABLE_DEBUG_INFO = YES;
304 | ONLY_ACTIVE_ARCH = YES;
305 | SDKROOT = iphoneos;
306 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
307 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
308 | TARGETED_DEVICE_FAMILY = "1,2";
309 | };
310 | name = Debug;
311 | };
312 | EEBBC6471DC9E19F00BBC1EE /* Release */ = {
313 | isa = XCBuildConfiguration;
314 | buildSettings = {
315 | ALWAYS_SEARCH_USER_PATHS = NO;
316 | CLANG_ANALYZER_NONNULL = YES;
317 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
318 | CLANG_CXX_LIBRARY = "libc++";
319 | CLANG_ENABLE_MODULES = YES;
320 | CLANG_ENABLE_OBJC_ARC = YES;
321 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
322 | CLANG_WARN_BOOL_CONVERSION = YES;
323 | CLANG_WARN_COMMA = YES;
324 | CLANG_WARN_CONSTANT_CONVERSION = YES;
325 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
326 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
327 | CLANG_WARN_EMPTY_BODY = YES;
328 | CLANG_WARN_ENUM_CONVERSION = YES;
329 | CLANG_WARN_INFINITE_RECURSION = YES;
330 | CLANG_WARN_INT_CONVERSION = YES;
331 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
332 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
333 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
334 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
335 | CLANG_WARN_STRICT_PROTOTYPES = YES;
336 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
337 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
338 | CLANG_WARN_UNREACHABLE_CODE = YES;
339 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
340 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
341 | COPY_PHASE_STRIP = NO;
342 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
343 | ENABLE_NS_ASSERTIONS = NO;
344 | ENABLE_STRICT_OBJC_MSGSEND = YES;
345 | GCC_C_LANGUAGE_STANDARD = gnu99;
346 | GCC_NO_COMMON_BLOCKS = YES;
347 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
348 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
349 | GCC_WARN_UNDECLARED_SELECTOR = YES;
350 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
351 | GCC_WARN_UNUSED_FUNCTION = YES;
352 | GCC_WARN_UNUSED_VARIABLE = YES;
353 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
354 | MTL_ENABLE_DEBUG_INFO = NO;
355 | SDKROOT = iphoneos;
356 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
357 | TARGETED_DEVICE_FAMILY = "1,2";
358 | VALIDATE_PRODUCT = YES;
359 | };
360 | name = Release;
361 | };
362 | EEBBC6491DC9E19F00BBC1EE /* Debug */ = {
363 | isa = XCBuildConfiguration;
364 | baseConfigurationReference = 20F29DBCFC8ECCD0C7119C69 /* Pods-HFCardCollectionViewLayoutExample.debug.xcconfig */;
365 | buildSettings = {
366 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
367 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
368 | CODE_SIGN_STYLE = Automatic;
369 | DEVELOPMENT_TEAM = TKESRF7W2Y;
370 | INFOPLIST_FILE = HFCardCollectionViewLayoutExample/Info.plist;
371 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
372 | PRODUCT_BUNDLE_IDENTIFIER = "de.hendrik-frahmann.HFCardCollectionViewLayoutExample";
373 | PRODUCT_NAME = "$(TARGET_NAME)";
374 | PROVISIONING_PROFILE_SPECIFIER = "";
375 | SWIFT_SWIFT3_OBJC_INFERENCE = On;
376 | SWIFT_VERSION = 4.0;
377 | };
378 | name = Debug;
379 | };
380 | EEBBC64A1DC9E19F00BBC1EE /* Release */ = {
381 | isa = XCBuildConfiguration;
382 | baseConfigurationReference = 896D468DC417110E7A811BB6 /* Pods-HFCardCollectionViewLayoutExample.release.xcconfig */;
383 | buildSettings = {
384 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
385 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
386 | CODE_SIGN_STYLE = Automatic;
387 | DEVELOPMENT_TEAM = TKESRF7W2Y;
388 | INFOPLIST_FILE = HFCardCollectionViewLayoutExample/Info.plist;
389 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
390 | PRODUCT_BUNDLE_IDENTIFIER = "de.hendrik-frahmann.HFCardCollectionViewLayoutExample";
391 | PRODUCT_NAME = "$(TARGET_NAME)";
392 | PROVISIONING_PROFILE_SPECIFIER = "";
393 | SWIFT_SWIFT3_OBJC_INFERENCE = On;
394 | SWIFT_VERSION = 4.0;
395 | };
396 | name = Release;
397 | };
398 | /* End XCBuildConfiguration section */
399 |
400 | /* Begin XCConfigurationList section */
401 | EEBBC6311DC9E19E00BBC1EE /* Build configuration list for PBXProject "HFCardCollectionViewLayoutExample" */ = {
402 | isa = XCConfigurationList;
403 | buildConfigurations = (
404 | EEBBC6461DC9E19F00BBC1EE /* Debug */,
405 | EEBBC6471DC9E19F00BBC1EE /* Release */,
406 | );
407 | defaultConfigurationIsVisible = 0;
408 | defaultConfigurationName = Release;
409 | };
410 | EEBBC6481DC9E19F00BBC1EE /* Build configuration list for PBXNativeTarget "HFCardCollectionViewLayoutExample" */ = {
411 | isa = XCConfigurationList;
412 | buildConfigurations = (
413 | EEBBC6491DC9E19F00BBC1EE /* Debug */,
414 | EEBBC64A1DC9E19F00BBC1EE /* Release */,
415 | );
416 | defaultConfigurationIsVisible = 0;
417 | defaultConfigurationName = Release;
418 | };
419 | /* End XCConfigurationList section */
420 | };
421 | rootObject = EEBBC62E1DC9E19E00BBC1EE /* Project object */;
422 | }
423 |
--------------------------------------------------------------------------------
/HFCardCollectionViewLayoutExample/Pods/Pods.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 072CA10A611A32FF1BD5A97A921B24D9 /* HFCardCollectionViewLayout-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC687B01081814BEFEA88991197B0BC /* HFCardCollectionViewLayout-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 3CE3C81FFEFE5F52C3CC15FB5684F101 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */; };
12 | 790F98919A98AB3E2AE7D5B3FD41A905 /* HFCardCollectionViewLayoutDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A16A63496E99558B4CA6B9D180806AB9 /* HFCardCollectionViewLayoutDelegate.swift */; };
13 | 7A6E27CC77BF07F42DB5DA9DF2990BA6 /* HFCardCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41BF607B2DDA5A8DD7AE50E6E83165C /* HFCardCollectionViewCell.swift */; };
14 | 7F63908EBEA5EE8B1B984B1B5CEB46E1 /* Pods-HFCardCollectionViewLayoutExample-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 046CED6827F8F476ACC86DD5468CF257 /* Pods-HFCardCollectionViewLayoutExample-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
15 | 8EFA7FE72F4E97A43C553E2BC4C123B4 /* HFCardCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C3E00731B0E31D62A8489277EFEEB67 /* HFCardCollectionViewLayout.swift */; };
16 | A5E3B8108717879F1E175A7882970651 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */; };
17 | B1BF26FC1E90FD810077D75E /* HFCardCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1BF26FB1E90FD810077D75E /* HFCardCollectionView.swift */; };
18 | CAB4E8075BB566BEB9DEFC2BB0AE1A44 /* HFCardCollectionViewLayout-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = B42049707F2D0F6158127900CD948320 /* HFCardCollectionViewLayout-dummy.m */; };
19 | F493F895289894F832FE0C88F27A0B15 /* Pods-HFCardCollectionViewLayoutExample-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AAF622BE70472DDFBC8E2489D38DD90 /* Pods-HFCardCollectionViewLayoutExample-dummy.m */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXContainerItemProxy section */
23 | B55B90381C05AD68454AFA5C2682ABA2 /* PBXContainerItemProxy */ = {
24 | isa = PBXContainerItemProxy;
25 | containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
26 | proxyType = 1;
27 | remoteGlobalIDString = E1C2F6043B98ABA5417B87102C667275;
28 | remoteInfo = HFCardCollectionViewLayout;
29 | };
30 | /* End PBXContainerItemProxy section */
31 |
32 | /* Begin PBXFileReference section */
33 | 046CED6827F8F476ACC86DD5468CF257 /* Pods-HFCardCollectionViewLayoutExample-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-HFCardCollectionViewLayoutExample-umbrella.h"; sourceTree = ""; };
34 | 07D657C1C371416A2A0C47DEFBCAEC04 /* Pods-HFCardCollectionViewLayoutExample-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-HFCardCollectionViewLayoutExample-frameworks.sh"; sourceTree = ""; };
35 | 1C3E00731B0E31D62A8489277EFEEB67 /* HFCardCollectionViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = HFCardCollectionViewLayout.swift; sourceTree = ""; };
36 | 2665BF22FA509A9D04D472D47F29BBDB /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
37 | 2871AA1D8F3B5DB60D1FC7F51114E01C /* HFCardCollectionViewLayout.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = HFCardCollectionViewLayout.framework; sourceTree = BUILT_PRODUCTS_DIR; };
38 | 2F0C5D5262152E6CAC8FBF879E31EDCE /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
39 | 3B08DABD74D6D5378A5DDCE853030F53 /* HFCardCollectionViewLayout.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = HFCardCollectionViewLayout.xcconfig; sourceTree = ""; };
40 | 4AAF622BE70472DDFBC8E2489D38DD90 /* Pods-HFCardCollectionViewLayoutExample-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-HFCardCollectionViewLayoutExample-dummy.m"; sourceTree = ""; };
41 | 54312038EC8BFFC3303E3C93C780CEFD /* HFCardCollectionViewLayout-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "HFCardCollectionViewLayout-prefix.pch"; sourceTree = ""; };
42 | 89EB551874C33A437A4B3D8A20764101 /* Pods-HFCardCollectionViewLayoutExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-HFCardCollectionViewLayoutExample.release.xcconfig"; sourceTree = ""; };
43 | 919E129C9C6AEDB0ADC7AD498746062A /* HFCardCollectionViewLayout.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = HFCardCollectionViewLayout.modulemap; sourceTree = ""; };
44 | 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
45 | A16A63496E99558B4CA6B9D180806AB9 /* HFCardCollectionViewLayoutDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = HFCardCollectionViewLayoutDelegate.swift; sourceTree = ""; };
46 | B1258B00B7C713CD4DB0AD7B276F8F50 /* Pods-HFCardCollectionViewLayoutExample-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-HFCardCollectionViewLayoutExample-resources.sh"; sourceTree = ""; };
47 | B1BF26FB1E90FD810077D75E /* HFCardCollectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HFCardCollectionView.swift; sourceTree = ""; };
48 | B42049707F2D0F6158127900CD948320 /* HFCardCollectionViewLayout-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "HFCardCollectionViewLayout-dummy.m"; sourceTree = ""; };
49 | B5F36D8799F60A8D7E92CEC996CF92EB /* Pods-HFCardCollectionViewLayoutExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-HFCardCollectionViewLayoutExample.debug.xcconfig"; sourceTree = ""; };
50 | C67398A2C41620ED4BB8215FBA4D8EFE /* Pods-HFCardCollectionViewLayoutExample-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-HFCardCollectionViewLayoutExample-acknowledgements.markdown"; sourceTree = ""; };
51 | CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
52 | D41BF607B2DDA5A8DD7AE50E6E83165C /* HFCardCollectionViewCell.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = HFCardCollectionViewCell.swift; sourceTree = ""; };
53 | D4DDF1440510E0A645063459BBF342BC /* Pods-HFCardCollectionViewLayoutExample-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-HFCardCollectionViewLayoutExample-acknowledgements.plist"; sourceTree = ""; };
54 | F11EAAD3F1CFFDD7D706ACA402A1C371 /* Pods_HFCardCollectionViewLayoutExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_HFCardCollectionViewLayoutExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
55 | FAC687B01081814BEFEA88991197B0BC /* HFCardCollectionViewLayout-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "HFCardCollectionViewLayout-umbrella.h"; sourceTree = ""; };
56 | FFD465A5DC9B5ACE385F3591BD90A298 /* Pods-HFCardCollectionViewLayoutExample.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = "Pods-HFCardCollectionViewLayoutExample.modulemap"; sourceTree = ""; };
57 | /* End PBXFileReference section */
58 |
59 | /* Begin PBXFrameworksBuildPhase section */
60 | D5F0304732E1A375415908F1B6AC9FEE /* Frameworks */ = {
61 | isa = PBXFrameworksBuildPhase;
62 | buildActionMask = 2147483647;
63 | files = (
64 | 3CE3C81FFEFE5F52C3CC15FB5684F101 /* Foundation.framework in Frameworks */,
65 | );
66 | runOnlyForDeploymentPostprocessing = 0;
67 | };
68 | D8B57CD8DCCF548A95047D16F3B2EC2D /* Frameworks */ = {
69 | isa = PBXFrameworksBuildPhase;
70 | buildActionMask = 2147483647;
71 | files = (
72 | A5E3B8108717879F1E175A7882970651 /* Foundation.framework in Frameworks */,
73 | );
74 | runOnlyForDeploymentPostprocessing = 0;
75 | };
76 | /* End PBXFrameworksBuildPhase section */
77 |
78 | /* Begin PBXGroup section */
79 | 29DCA1BD5EA65F6AABF1763FF25A5265 /* Pods-HFCardCollectionViewLayoutExample */ = {
80 | isa = PBXGroup;
81 | children = (
82 | 2665BF22FA509A9D04D472D47F29BBDB /* Info.plist */,
83 | FFD465A5DC9B5ACE385F3591BD90A298 /* Pods-HFCardCollectionViewLayoutExample.modulemap */,
84 | C67398A2C41620ED4BB8215FBA4D8EFE /* Pods-HFCardCollectionViewLayoutExample-acknowledgements.markdown */,
85 | D4DDF1440510E0A645063459BBF342BC /* Pods-HFCardCollectionViewLayoutExample-acknowledgements.plist */,
86 | 4AAF622BE70472DDFBC8E2489D38DD90 /* Pods-HFCardCollectionViewLayoutExample-dummy.m */,
87 | 07D657C1C371416A2A0C47DEFBCAEC04 /* Pods-HFCardCollectionViewLayoutExample-frameworks.sh */,
88 | B1258B00B7C713CD4DB0AD7B276F8F50 /* Pods-HFCardCollectionViewLayoutExample-resources.sh */,
89 | 046CED6827F8F476ACC86DD5468CF257 /* Pods-HFCardCollectionViewLayoutExample-umbrella.h */,
90 | B5F36D8799F60A8D7E92CEC996CF92EB /* Pods-HFCardCollectionViewLayoutExample.debug.xcconfig */,
91 | 89EB551874C33A437A4B3D8A20764101 /* Pods-HFCardCollectionViewLayoutExample.release.xcconfig */,
92 | );
93 | name = "Pods-HFCardCollectionViewLayoutExample";
94 | path = "Target Support Files/Pods-HFCardCollectionViewLayoutExample";
95 | sourceTree = "";
96 | };
97 | 384F295B9B7C16999BBC2531611857C1 /* Support Files */ = {
98 | isa = PBXGroup;
99 | children = (
100 | 919E129C9C6AEDB0ADC7AD498746062A /* HFCardCollectionViewLayout.modulemap */,
101 | 3B08DABD74D6D5378A5DDCE853030F53 /* HFCardCollectionViewLayout.xcconfig */,
102 | B42049707F2D0F6158127900CD948320 /* HFCardCollectionViewLayout-dummy.m */,
103 | 54312038EC8BFFC3303E3C93C780CEFD /* HFCardCollectionViewLayout-prefix.pch */,
104 | FAC687B01081814BEFEA88991197B0BC /* HFCardCollectionViewLayout-umbrella.h */,
105 | 2F0C5D5262152E6CAC8FBF879E31EDCE /* Info.plist */,
106 | );
107 | name = "Support Files";
108 | path = "HFCardCollectionViewLayoutExample/Pods/Target Support Files/HFCardCollectionViewLayout";
109 | sourceTree = "";
110 | };
111 | 3FF3C2B28A3EE6A89FBA891598AF5508 /* HFCardCollectionViewLayout */ = {
112 | isa = PBXGroup;
113 | children = (
114 | 90DA7C0E383D971F85355B2CDE812ADE /* Source */,
115 | 384F295B9B7C16999BBC2531611857C1 /* Support Files */,
116 | );
117 | name = HFCardCollectionViewLayout;
118 | path = ../..;
119 | sourceTree = "";
120 | };
121 | 4FFE99151BD282E539E9002587D70D0A /* Development Pods */ = {
122 | isa = PBXGroup;
123 | children = (
124 | 3FF3C2B28A3EE6A89FBA891598AF5508 /* HFCardCollectionViewLayout */,
125 | );
126 | name = "Development Pods";
127 | sourceTree = "";
128 | };
129 | 7531C8F8DE19F1AA3C8A7AC97A91DC29 /* iOS */ = {
130 | isa = PBXGroup;
131 | children = (
132 | CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */,
133 | );
134 | name = iOS;
135 | sourceTree = "";
136 | };
137 | 7DB346D0F39D3F0E887471402A8071AB = {
138 | isa = PBXGroup;
139 | children = (
140 | 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */,
141 | 4FFE99151BD282E539E9002587D70D0A /* Development Pods */,
142 | BC3CA7F9E30CC8F7E2DD044DD34432FC /* Frameworks */,
143 | E11057D728DF1A0CA614502392CB04B8 /* Products */,
144 | E1C4EBB06D13D49B160F339B6DDBECA0 /* Targets Support Files */,
145 | );
146 | sourceTree = "";
147 | };
148 | 90DA7C0E383D971F85355B2CDE812ADE /* Source */ = {
149 | isa = PBXGroup;
150 | children = (
151 | D41BF607B2DDA5A8DD7AE50E6E83165C /* HFCardCollectionViewCell.swift */,
152 | 1C3E00731B0E31D62A8489277EFEEB67 /* HFCardCollectionViewLayout.swift */,
153 | A16A63496E99558B4CA6B9D180806AB9 /* HFCardCollectionViewLayoutDelegate.swift */,
154 | B1BF26FB1E90FD810077D75E /* HFCardCollectionView.swift */,
155 | );
156 | path = Source;
157 | sourceTree = "";
158 | };
159 | BC3CA7F9E30CC8F7E2DD044DD34432FC /* Frameworks */ = {
160 | isa = PBXGroup;
161 | children = (
162 | 7531C8F8DE19F1AA3C8A7AC97A91DC29 /* iOS */,
163 | );
164 | name = Frameworks;
165 | sourceTree = "";
166 | };
167 | E11057D728DF1A0CA614502392CB04B8 /* Products */ = {
168 | isa = PBXGroup;
169 | children = (
170 | 2871AA1D8F3B5DB60D1FC7F51114E01C /* HFCardCollectionViewLayout.framework */,
171 | F11EAAD3F1CFFDD7D706ACA402A1C371 /* Pods_HFCardCollectionViewLayoutExample.framework */,
172 | );
173 | name = Products;
174 | sourceTree = "";
175 | };
176 | E1C4EBB06D13D49B160F339B6DDBECA0 /* Targets Support Files */ = {
177 | isa = PBXGroup;
178 | children = (
179 | 29DCA1BD5EA65F6AABF1763FF25A5265 /* Pods-HFCardCollectionViewLayoutExample */,
180 | );
181 | name = "Targets Support Files";
182 | sourceTree = "";
183 | };
184 | /* End PBXGroup section */
185 |
186 | /* Begin PBXHeadersBuildPhase section */
187 | 7E51A2A926EE7949AAE4FD1EA1AC105D /* Headers */ = {
188 | isa = PBXHeadersBuildPhase;
189 | buildActionMask = 2147483647;
190 | files = (
191 | 072CA10A611A32FF1BD5A97A921B24D9 /* HFCardCollectionViewLayout-umbrella.h in Headers */,
192 | );
193 | runOnlyForDeploymentPostprocessing = 0;
194 | };
195 | D61D6C4F7E5AC15BD599A447CA8055CE /* Headers */ = {
196 | isa = PBXHeadersBuildPhase;
197 | buildActionMask = 2147483647;
198 | files = (
199 | 7F63908EBEA5EE8B1B984B1B5CEB46E1 /* Pods-HFCardCollectionViewLayoutExample-umbrella.h in Headers */,
200 | );
201 | runOnlyForDeploymentPostprocessing = 0;
202 | };
203 | /* End PBXHeadersBuildPhase section */
204 |
205 | /* Begin PBXNativeTarget section */
206 | 1D9676DD5B8F6AABC6C66730FC85E322 /* Pods-HFCardCollectionViewLayoutExample */ = {
207 | isa = PBXNativeTarget;
208 | buildConfigurationList = 7B1C1515171E534D7DD08A568F6263CE /* Build configuration list for PBXNativeTarget "Pods-HFCardCollectionViewLayoutExample" */;
209 | buildPhases = (
210 | 047C28A02840759B5C22A4609D896D39 /* Sources */,
211 | D5F0304732E1A375415908F1B6AC9FEE /* Frameworks */,
212 | D61D6C4F7E5AC15BD599A447CA8055CE /* Headers */,
213 | );
214 | buildRules = (
215 | );
216 | dependencies = (
217 | 1CC8B9C75E5A9B2B2A6B1E27AB954823 /* PBXTargetDependency */,
218 | );
219 | name = "Pods-HFCardCollectionViewLayoutExample";
220 | productName = "Pods-HFCardCollectionViewLayoutExample";
221 | productReference = F11EAAD3F1CFFDD7D706ACA402A1C371 /* Pods_HFCardCollectionViewLayoutExample.framework */;
222 | productType = "com.apple.product-type.framework";
223 | };
224 | E1C2F6043B98ABA5417B87102C667275 /* HFCardCollectionViewLayout */ = {
225 | isa = PBXNativeTarget;
226 | buildConfigurationList = C000741956A955D75290C78B8C062923 /* Build configuration list for PBXNativeTarget "HFCardCollectionViewLayout" */;
227 | buildPhases = (
228 | 6FA203D0BBD713600FC1B3832161E89A /* Sources */,
229 | D8B57CD8DCCF548A95047D16F3B2EC2D /* Frameworks */,
230 | 7E51A2A926EE7949AAE4FD1EA1AC105D /* Headers */,
231 | );
232 | buildRules = (
233 | );
234 | dependencies = (
235 | );
236 | name = HFCardCollectionViewLayout;
237 | productName = HFCardCollectionViewLayout;
238 | productReference = 2871AA1D8F3B5DB60D1FC7F51114E01C /* HFCardCollectionViewLayout.framework */;
239 | productType = "com.apple.product-type.framework";
240 | };
241 | /* End PBXNativeTarget section */
242 |
243 | /* Begin PBXProject section */
244 | D41D8CD98F00B204E9800998ECF8427E /* Project object */ = {
245 | isa = PBXProject;
246 | attributes = {
247 | LastSwiftUpdateCheck = 0730;
248 | LastUpgradeCheck = 0920;
249 | TargetAttributes = {
250 | E1C2F6043B98ABA5417B87102C667275 = {
251 | LastSwiftMigration = 0920;
252 | };
253 | };
254 | };
255 | buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */;
256 | compatibilityVersion = "Xcode 3.2";
257 | developmentRegion = English;
258 | hasScannedForEncodings = 0;
259 | knownRegions = (
260 | en,
261 | );
262 | mainGroup = 7DB346D0F39D3F0E887471402A8071AB;
263 | productRefGroup = E11057D728DF1A0CA614502392CB04B8 /* Products */;
264 | projectDirPath = "";
265 | projectRoot = "";
266 | targets = (
267 | E1C2F6043B98ABA5417B87102C667275 /* HFCardCollectionViewLayout */,
268 | 1D9676DD5B8F6AABC6C66730FC85E322 /* Pods-HFCardCollectionViewLayoutExample */,
269 | );
270 | };
271 | /* End PBXProject section */
272 |
273 | /* Begin PBXSourcesBuildPhase section */
274 | 047C28A02840759B5C22A4609D896D39 /* Sources */ = {
275 | isa = PBXSourcesBuildPhase;
276 | buildActionMask = 2147483647;
277 | files = (
278 | F493F895289894F832FE0C88F27A0B15 /* Pods-HFCardCollectionViewLayoutExample-dummy.m in Sources */,
279 | );
280 | runOnlyForDeploymentPostprocessing = 0;
281 | };
282 | 6FA203D0BBD713600FC1B3832161E89A /* Sources */ = {
283 | isa = PBXSourcesBuildPhase;
284 | buildActionMask = 2147483647;
285 | files = (
286 | 7A6E27CC77BF07F42DB5DA9DF2990BA6 /* HFCardCollectionViewCell.swift in Sources */,
287 | CAB4E8075BB566BEB9DEFC2BB0AE1A44 /* HFCardCollectionViewLayout-dummy.m in Sources */,
288 | 8EFA7FE72F4E97A43C553E2BC4C123B4 /* HFCardCollectionViewLayout.swift in Sources */,
289 | 790F98919A98AB3E2AE7D5B3FD41A905 /* HFCardCollectionViewLayoutDelegate.swift in Sources */,
290 | B1BF26FC1E90FD810077D75E /* HFCardCollectionView.swift in Sources */,
291 | );
292 | runOnlyForDeploymentPostprocessing = 0;
293 | };
294 | /* End PBXSourcesBuildPhase section */
295 |
296 | /* Begin PBXTargetDependency section */
297 | 1CC8B9C75E5A9B2B2A6B1E27AB954823 /* PBXTargetDependency */ = {
298 | isa = PBXTargetDependency;
299 | name = HFCardCollectionViewLayout;
300 | target = E1C2F6043B98ABA5417B87102C667275 /* HFCardCollectionViewLayout */;
301 | targetProxy = B55B90381C05AD68454AFA5C2682ABA2 /* PBXContainerItemProxy */;
302 | };
303 | /* End PBXTargetDependency section */
304 |
305 | /* Begin XCBuildConfiguration section */
306 | 12914D756594D15C6F2CA12FE5F89F1B /* Debug */ = {
307 | isa = XCBuildConfiguration;
308 | buildSettings = {
309 | ALWAYS_SEARCH_USER_PATHS = NO;
310 | CLANG_ANALYZER_NONNULL = YES;
311 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
312 | CLANG_CXX_LIBRARY = "libc++";
313 | CLANG_ENABLE_MODULES = YES;
314 | CLANG_ENABLE_OBJC_ARC = YES;
315 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
316 | CLANG_WARN_BOOL_CONVERSION = YES;
317 | CLANG_WARN_COMMA = YES;
318 | CLANG_WARN_CONSTANT_CONVERSION = YES;
319 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES;
320 | CLANG_WARN_EMPTY_BODY = YES;
321 | CLANG_WARN_ENUM_CONVERSION = YES;
322 | CLANG_WARN_INFINITE_RECURSION = YES;
323 | CLANG_WARN_INT_CONVERSION = YES;
324 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
325 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
326 | CLANG_WARN_OBJC_ROOT_CLASS = YES;
327 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
328 | CLANG_WARN_STRICT_PROTOTYPES = YES;
329 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
330 | CLANG_WARN_UNREACHABLE_CODE = YES;
331 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
332 | CODE_SIGNING_REQUIRED = NO;
333 | COPY_PHASE_STRIP = NO;
334 | ENABLE_STRICT_OBJC_MSGSEND = YES;
335 | ENABLE_TESTABILITY = YES;
336 | GCC_C_LANGUAGE_STANDARD = gnu99;
337 | GCC_DYNAMIC_NO_PIC = NO;
338 | GCC_NO_COMMON_BLOCKS = YES;
339 | GCC_OPTIMIZATION_LEVEL = 0;
340 | GCC_PREPROCESSOR_DEFINITIONS = (
341 | "POD_CONFIGURATION_DEBUG=1",
342 | "DEBUG=1",
343 | "$(inherited)",
344 | );
345 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
346 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
347 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
348 | GCC_WARN_UNDECLARED_SELECTOR = YES;
349 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
350 | GCC_WARN_UNUSED_FUNCTION = YES;
351 | GCC_WARN_UNUSED_VARIABLE = YES;
352 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
353 | ONLY_ACTIVE_ARCH = YES;
354 | PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/;
355 | STRIP_INSTALLED_PRODUCT = NO;
356 | SYMROOT = "${SRCROOT}/../build";
357 | };
358 | name = Debug;
359 | };
360 | 59039CA94E93F462878EA27D8A88C6AE /* Release */ = {
361 | isa = XCBuildConfiguration;
362 | baseConfigurationReference = 89EB551874C33A437A4B3D8A20764101 /* Pods-HFCardCollectionViewLayoutExample.release.xcconfig */;
363 | buildSettings = {
364 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
365 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
366 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
367 | CURRENT_PROJECT_VERSION = 1;
368 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
369 | DEFINES_MODULE = YES;
370 | DYLIB_COMPATIBILITY_VERSION = 1;
371 | DYLIB_CURRENT_VERSION = 1;
372 | DYLIB_INSTALL_NAME_BASE = "@rpath";
373 | ENABLE_STRICT_OBJC_MSGSEND = YES;
374 | GCC_NO_COMMON_BLOCKS = YES;
375 | INFOPLIST_FILE = "Target Support Files/Pods-HFCardCollectionViewLayoutExample/Info.plist";
376 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
377 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
378 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
379 | MACH_O_TYPE = staticlib;
380 | MODULEMAP_FILE = "Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample.modulemap";
381 | MTL_ENABLE_DEBUG_INFO = NO;
382 | OTHER_LDFLAGS = "";
383 | OTHER_LIBTOOLFLAGS = "";
384 | PODS_ROOT = "$(SRCROOT)";
385 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
386 | PRODUCT_NAME = Pods_HFCardCollectionViewLayoutExample;
387 | SDKROOT = iphoneos;
388 | SKIP_INSTALL = YES;
389 | TARGETED_DEVICE_FAMILY = "1,2";
390 | VERSIONING_SYSTEM = "apple-generic";
391 | VERSION_INFO_PREFIX = "";
392 | };
393 | name = Release;
394 | };
395 | 7161B9D607CCBE396C693489B0AEB112 /* Release */ = {
396 | isa = XCBuildConfiguration;
397 | baseConfigurationReference = 3B08DABD74D6D5378A5DDCE853030F53 /* HFCardCollectionViewLayout.xcconfig */;
398 | buildSettings = {
399 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
400 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
401 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
402 | CURRENT_PROJECT_VERSION = 1;
403 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
404 | DEFINES_MODULE = YES;
405 | DYLIB_COMPATIBILITY_VERSION = 1;
406 | DYLIB_CURRENT_VERSION = 1;
407 | DYLIB_INSTALL_NAME_BASE = "@rpath";
408 | ENABLE_STRICT_OBJC_MSGSEND = YES;
409 | GCC_NO_COMMON_BLOCKS = YES;
410 | GCC_PREFIX_HEADER = "Target Support Files/HFCardCollectionViewLayout/HFCardCollectionViewLayout-prefix.pch";
411 | INFOPLIST_FILE = "Target Support Files/HFCardCollectionViewLayout/Info.plist";
412 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
413 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
414 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
415 | MODULEMAP_FILE = "Target Support Files/HFCardCollectionViewLayout/HFCardCollectionViewLayout.modulemap";
416 | MTL_ENABLE_DEBUG_INFO = NO;
417 | PRODUCT_NAME = HFCardCollectionViewLayout;
418 | SDKROOT = iphoneos;
419 | SKIP_INSTALL = YES;
420 | SWIFT_SWIFT3_OBJC_INFERENCE = On;
421 | SWIFT_VERSION = 4.0;
422 | TARGETED_DEVICE_FAMILY = "1,2";
423 | VERSIONING_SYSTEM = "apple-generic";
424 | VERSION_INFO_PREFIX = "";
425 | };
426 | name = Release;
427 | };
428 | 92B027B0926C28AD73F595226EFBDF0B /* Debug */ = {
429 | isa = XCBuildConfiguration;
430 | baseConfigurationReference = 3B08DABD74D6D5378A5DDCE853030F53 /* HFCardCollectionViewLayout.xcconfig */;
431 | buildSettings = {
432 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
433 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
434 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
435 | CURRENT_PROJECT_VERSION = 1;
436 | DEBUG_INFORMATION_FORMAT = dwarf;
437 | DEFINES_MODULE = YES;
438 | DYLIB_COMPATIBILITY_VERSION = 1;
439 | DYLIB_CURRENT_VERSION = 1;
440 | DYLIB_INSTALL_NAME_BASE = "@rpath";
441 | ENABLE_STRICT_OBJC_MSGSEND = YES;
442 | GCC_NO_COMMON_BLOCKS = YES;
443 | GCC_PREFIX_HEADER = "Target Support Files/HFCardCollectionViewLayout/HFCardCollectionViewLayout-prefix.pch";
444 | INFOPLIST_FILE = "Target Support Files/HFCardCollectionViewLayout/Info.plist";
445 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
446 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
447 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
448 | MODULEMAP_FILE = "Target Support Files/HFCardCollectionViewLayout/HFCardCollectionViewLayout.modulemap";
449 | MTL_ENABLE_DEBUG_INFO = YES;
450 | PRODUCT_NAME = HFCardCollectionViewLayout;
451 | SDKROOT = iphoneos;
452 | SKIP_INSTALL = YES;
453 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
454 | SWIFT_SWIFT3_OBJC_INFERENCE = On;
455 | SWIFT_VERSION = 4.0;
456 | TARGETED_DEVICE_FAMILY = "1,2";
457 | VERSIONING_SYSTEM = "apple-generic";
458 | VERSION_INFO_PREFIX = "";
459 | };
460 | name = Debug;
461 | };
462 | CAED8D664B647776A9C45FD40CED9B7F /* Debug */ = {
463 | isa = XCBuildConfiguration;
464 | baseConfigurationReference = B5F36D8799F60A8D7E92CEC996CF92EB /* Pods-HFCardCollectionViewLayoutExample.debug.xcconfig */;
465 | buildSettings = {
466 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
467 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
468 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
469 | CURRENT_PROJECT_VERSION = 1;
470 | DEBUG_INFORMATION_FORMAT = dwarf;
471 | DEFINES_MODULE = YES;
472 | DYLIB_COMPATIBILITY_VERSION = 1;
473 | DYLIB_CURRENT_VERSION = 1;
474 | DYLIB_INSTALL_NAME_BASE = "@rpath";
475 | ENABLE_STRICT_OBJC_MSGSEND = YES;
476 | GCC_NO_COMMON_BLOCKS = YES;
477 | INFOPLIST_FILE = "Target Support Files/Pods-HFCardCollectionViewLayoutExample/Info.plist";
478 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
479 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
480 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
481 | MACH_O_TYPE = staticlib;
482 | MODULEMAP_FILE = "Target Support Files/Pods-HFCardCollectionViewLayoutExample/Pods-HFCardCollectionViewLayoutExample.modulemap";
483 | MTL_ENABLE_DEBUG_INFO = YES;
484 | OTHER_LDFLAGS = "";
485 | OTHER_LIBTOOLFLAGS = "";
486 | PODS_ROOT = "$(SRCROOT)";
487 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
488 | PRODUCT_NAME = Pods_HFCardCollectionViewLayoutExample;
489 | SDKROOT = iphoneos;
490 | SKIP_INSTALL = YES;
491 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
492 | TARGETED_DEVICE_FAMILY = "1,2";
493 | VERSIONING_SYSTEM = "apple-generic";
494 | VERSION_INFO_PREFIX = "";
495 | };
496 | name = Debug;
497 | };
498 | E72E7977875C2D251FC62736BBDDC389 /* Release */ = {
499 | isa = XCBuildConfiguration;
500 | buildSettings = {
501 | ALWAYS_SEARCH_USER_PATHS = NO;
502 | CLANG_ANALYZER_NONNULL = YES;
503 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
504 | CLANG_CXX_LIBRARY = "libc++";
505 | CLANG_ENABLE_MODULES = YES;
506 | CLANG_ENABLE_OBJC_ARC = YES;
507 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
508 | CLANG_WARN_BOOL_CONVERSION = YES;
509 | CLANG_WARN_COMMA = YES;
510 | CLANG_WARN_CONSTANT_CONVERSION = YES;
511 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES;
512 | CLANG_WARN_EMPTY_BODY = YES;
513 | CLANG_WARN_ENUM_CONVERSION = YES;
514 | CLANG_WARN_INFINITE_RECURSION = YES;
515 | CLANG_WARN_INT_CONVERSION = YES;
516 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
517 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
518 | CLANG_WARN_OBJC_ROOT_CLASS = YES;
519 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
520 | CLANG_WARN_STRICT_PROTOTYPES = YES;
521 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
522 | CLANG_WARN_UNREACHABLE_CODE = YES;
523 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
524 | CODE_SIGNING_REQUIRED = NO;
525 | COPY_PHASE_STRIP = YES;
526 | ENABLE_NS_ASSERTIONS = NO;
527 | ENABLE_STRICT_OBJC_MSGSEND = YES;
528 | GCC_C_LANGUAGE_STANDARD = gnu99;
529 | GCC_NO_COMMON_BLOCKS = YES;
530 | GCC_PREPROCESSOR_DEFINITIONS = (
531 | "POD_CONFIGURATION_RELEASE=1",
532 | "$(inherited)",
533 | );
534 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
535 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
536 | GCC_WARN_UNDECLARED_SELECTOR = YES;
537 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
538 | GCC_WARN_UNUSED_FUNCTION = YES;
539 | GCC_WARN_UNUSED_VARIABLE = YES;
540 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
541 | PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/;
542 | STRIP_INSTALLED_PRODUCT = NO;
543 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
544 | SYMROOT = "${SRCROOT}/../build";
545 | VALIDATE_PRODUCT = YES;
546 | };
547 | name = Release;
548 | };
549 | /* End XCBuildConfiguration section */
550 |
551 | /* Begin XCConfigurationList section */
552 | 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = {
553 | isa = XCConfigurationList;
554 | buildConfigurations = (
555 | 12914D756594D15C6F2CA12FE5F89F1B /* Debug */,
556 | E72E7977875C2D251FC62736BBDDC389 /* Release */,
557 | );
558 | defaultConfigurationIsVisible = 0;
559 | defaultConfigurationName = Release;
560 | };
561 | 7B1C1515171E534D7DD08A568F6263CE /* Build configuration list for PBXNativeTarget "Pods-HFCardCollectionViewLayoutExample" */ = {
562 | isa = XCConfigurationList;
563 | buildConfigurations = (
564 | CAED8D664B647776A9C45FD40CED9B7F /* Debug */,
565 | 59039CA94E93F462878EA27D8A88C6AE /* Release */,
566 | );
567 | defaultConfigurationIsVisible = 0;
568 | defaultConfigurationName = Release;
569 | };
570 | C000741956A955D75290C78B8C062923 /* Build configuration list for PBXNativeTarget "HFCardCollectionViewLayout" */ = {
571 | isa = XCConfigurationList;
572 | buildConfigurations = (
573 | 92B027B0926C28AD73F595226EFBDF0B /* Debug */,
574 | 7161B9D607CCBE396C693489B0AEB112 /* Release */,
575 | );
576 | defaultConfigurationIsVisible = 0;
577 | defaultConfigurationName = Release;
578 | };
579 | /* End XCConfigurationList section */
580 | };
581 | rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
582 | }
583 |
--------------------------------------------------------------------------------
/Source/HFCardCollectionViewLayout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HFCardCollectionViewLayout.swift
3 | // HFCardCollectionViewLayout
4 | //
5 | // Created by Hendrik Frahmann on 02.11.16.
6 | // Copyright © 2016 Hendrik Frahmann. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /// Layout attributes for the HFCardCollectionViewLayout
12 | open class HFCardCollectionViewLayoutAttributes: UICollectionViewLayoutAttributes {
13 |
14 | /// Specifies if the CardCell is revealed.
15 | public var isRevealed = false
16 |
17 | /// Overwritten to copy also the 'isRevealed' flag.
18 | override open func copy(with zone: NSZone? = nil) -> Any {
19 | let attribute = super.copy(with: zone) as! HFCardCollectionViewLayoutAttributes
20 | attribute.isRevealed = isRevealed
21 | return attribute
22 | }
23 |
24 | }
25 |
26 | /// The HFCardCollectionViewLayout provides a card stack layout not quite similar like the apps Reminder and Wallet.
27 | open class HFCardCollectionViewLayout: UICollectionViewLayout, UIGestureRecognizerDelegate {
28 |
29 | // MARK: Public Variables
30 |
31 | /// Only cards with index equal or greater than firstMovableIndex can be moved through the collectionView.
32 | ///
33 | /// Default: 0
34 | @IBInspectable open var firstMovableIndex: Int = 0
35 |
36 | /// Specifies the height that is showing the cardhead when the collectionView is showing all cards.
37 | ///
38 | /// The minimum value is 20.
39 | ///
40 | /// Default: 80
41 | @IBInspectable open var cardHeadHeight: CGFloat = 80 {
42 | didSet {
43 | if(cardHeadHeight < 20) {
44 | cardHeadHeight = 20
45 | return
46 | }
47 | self.collectionView?.performBatchUpdates({ self.invalidateLayout() }, completion: nil)
48 | }
49 | }
50 |
51 | /// When th collectionView is showing all cards but there are not enough cards to fill the full height,
52 | /// the cardHeadHeight will be expanded to equally fill the height.
53 | ///
54 | /// Default: true
55 | @IBInspectable open var cardShouldExpandHeadHeight: Bool = true {
56 | didSet {
57 | self.collectionView?.performBatchUpdates({ self.invalidateLayout() }, completion: nil)
58 | }
59 | }
60 |
61 | /// Stretch the cards when scrolling up
62 | ///
63 | /// Default: true
64 | @IBInspectable open var cardShouldStretchAtScrollTop: Bool = true {
65 | didSet {
66 | self.collectionView?.performBatchUpdates({ self.invalidateLayout() }, completion: nil)
67 | }
68 | }
69 |
70 | /// Specifies the maximum height of the cards.
71 | ///
72 | /// But the height can be less if the frame size of collectionView is smaller.
73 | ///
74 | /// Default: 0 (no height specified)
75 | @IBInspectable open var cardMaximumHeight: CGFloat = 0 {
76 | didSet {
77 | if(cardMaximumHeight < 0) {
78 | cardMaximumHeight = 0
79 | return
80 | }
81 | self.collectionView?.performBatchUpdates({ self.invalidateLayout() }, completion: nil)
82 | }
83 | }
84 |
85 | /// Count of bottom stacked cards when a card is revealed.
86 | ///
87 | /// Value must be between 0 and 10
88 | ///
89 | /// Default: 5
90 | @IBInspectable open var bottomNumberOfStackedCards: Int = 5 {
91 | didSet {
92 | if(bottomNumberOfStackedCards < 0) {
93 | bottomNumberOfStackedCards = 0
94 | return
95 | }
96 | if(bottomNumberOfStackedCards > 10) {
97 | bottomNumberOfStackedCards = 10
98 | return
99 | }
100 | self.collectionView?.performBatchUpdates({ self.collectionView?.reloadData() }, completion: nil)
101 | }
102 | }
103 |
104 | /// All bottom stacked cards are scaled to produce the 3D effect.
105 | ///
106 | /// Default: true
107 | @IBInspectable open var bottomStackedCardsShouldScale: Bool = true {
108 | didSet {
109 | self.collectionView?.performBatchUpdates({ self.invalidateLayout() }, completion: nil)
110 | }
111 | }
112 |
113 | /// The minimum scale for the bottom cards.
114 | ///
115 | /// Default: 0.94
116 | @IBInspectable open var bottomStackedCardsMinimumScale: CGFloat = 0.94 {
117 | didSet {
118 | if(self.bottomStackedCardsMinimumScale < 0.0) {
119 | self.bottomStackedCardsMinimumScale = 0.0
120 | return
121 | }
122 | self.collectionView?.performBatchUpdates({ self.invalidateLayout() }, completion: nil)
123 | }
124 | }
125 |
126 | /// The maximum scale for the bottom cards.
127 | ///
128 | /// Default: 0.94
129 | @IBInspectable open var bottomStackedCardsMaximumScale: CGFloat = 1.0 {
130 | didSet {
131 | if(self.bottomStackedCardsMaximumScale > 1.0) {
132 | self.bottomStackedCardsMaximumScale = 1.0
133 | return
134 | }
135 | self.collectionView?.performBatchUpdates({ self.invalidateLayout() }, completion: nil)
136 | }
137 | }
138 |
139 | /// Specifies the margin for the top margin of a bottom stacked card.
140 | ///
141 | /// Value can be between 0 and 20
142 | ///
143 | /// Default: 10
144 | @IBInspectable open var bottomCardLookoutMargin: CGFloat = 10 {
145 | didSet {
146 | if(bottomCardLookoutMargin < 0) {
147 | bottomCardLookoutMargin = 0
148 | return
149 | }
150 | if(bottomCardLookoutMargin > 20) {
151 | bottomCardLookoutMargin = 20
152 | return
153 | }
154 | self.collectionView?.performBatchUpdates({ self.invalidateLayout() }, completion: nil)
155 | }
156 | }
157 |
158 | /// An additional topspace to show the top of the collectionViews backgroundView.
159 | ///
160 | /// Default: 0
161 | @IBInspectable open var spaceAtTopForBackgroundView: CGFloat = 0 {
162 | didSet {
163 | if(spaceAtTopForBackgroundView < 0) {
164 | spaceAtTopForBackgroundView = 0
165 | return
166 | }
167 | self.collectionView?.performBatchUpdates({ self.invalidateLayout() }, completion: nil)
168 | }
169 | }
170 |
171 | /// Snaps the scrollView if the contentOffset is on the 'spaceAtTopForBackgroundView'
172 | ///
173 | /// Default: true
174 | @IBInspectable open var spaceAtTopShouldSnap: Bool = true
175 |
176 | /// Additional space at the bottom to expand the contentsize of the collectionView.
177 | ///
178 | /// Default: 0
179 | @IBInspectable open var spaceAtBottom: CGFloat = 0 {
180 | didSet {
181 | self.collectionView?.performBatchUpdates({ self.invalidateLayout() }, completion: nil)
182 | }
183 | }
184 |
185 | /// Area the top where to autoscroll while moving a card.
186 | ///
187 | /// Default 120
188 | @IBInspectable open var scrollAreaTop: CGFloat = 120 {
189 | didSet {
190 | if(scrollAreaTop < 0) {
191 | scrollAreaTop = 0
192 | return
193 | }
194 | }
195 | }
196 |
197 | /// Area ot the bottom where to autoscroll while moving a card.
198 | ///
199 | /// Default 120
200 | @IBInspectable open var scrollAreaBottom: CGFloat = 120 {
201 | didSet {
202 | if(scrollAreaBottom < 0) {
203 | scrollAreaBottom = 0
204 | return
205 | }
206 | }
207 | }
208 |
209 | /// The scrollView should snap the cardhead to the top.
210 | ///
211 | /// Default: false
212 | @IBInspectable open var scrollShouldSnapCardHead: Bool = false
213 |
214 | /// Cards are stopping at top while scrolling.
215 | ///
216 | /// Default: true
217 | @IBInspectable open var scrollStopCardsAtTop: Bool = true {
218 | didSet {
219 | self.collectionView?.performBatchUpdates({ self.invalidateLayout() }, completion: nil)
220 | }
221 | }
222 |
223 | /// All cards are collapsed at bottom.
224 | ///
225 | /// Default: false
226 | @IBInspectable open var collapseAllCards: Bool = false {
227 | didSet {
228 | self.flipRevealedCardBack(completion: {
229 | self.collectionView?.isScrollEnabled = !self.collapseAllCards
230 | var previousRevealedIndex = -1
231 | let collectionViewLayoutDelegate = self.collectionView?.delegate as? HFCardCollectionViewLayoutDelegate
232 | if(self.revealedIndex >= 0) {
233 | previousRevealedIndex = self.revealedIndex
234 | collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, willUnrevealCardAtIndex: self.revealedIndex)
235 | self.revealedIndex = -1
236 | }
237 | self.collectionView?.performBatchUpdates({ self.collectionView?.reloadData() }, completion: {(finished) in
238 | if(previousRevealedIndex >= 0) {
239 |
240 | collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, didUnrevealCardAtIndex: previousRevealedIndex)
241 | }
242 | })
243 | })
244 | }
245 | }
246 |
247 | /// Contains the revealed index.
248 | /// ReadOnly.
249 | private(set) open var revealedIndex: Int = -1
250 |
251 | // MARK: Public Actions
252 |
253 | /// Action for the InterfaceBuilder to flip back the revealed card.
254 | @IBAction open func flipBackRevealedCardAction() {
255 | self.flipRevealedCardBack()
256 | }
257 |
258 | /// Action for the InterfaceBuilder to Unreveal the revealed card.
259 | @IBAction open func unrevealRevealedCardAction() {
260 | self.unrevealCard()
261 | }
262 |
263 | /// Action to collapse all cards.
264 | @IBAction open func collapseAllCardsAction() {
265 | self.collapseAllCards = true
266 | }
267 |
268 | // MARK: Public Functions
269 |
270 | /// Reveal a card at the given index.
271 | ///
272 | /// - Parameter index: The index of the card.
273 | /// - Parameter completion: An optional completion block. Will be executed the animation is finished.
274 | open func revealCardAt(index: Int, completion: (() -> Void)? = nil) {
275 | var index = index
276 | let collectionViewLayoutDelegate = self.collectionView?.delegate as? HFCardCollectionViewLayoutDelegate
277 | let oldRevealedIndex = self.revealedIndex
278 |
279 | if(oldRevealedIndex < 0 && index >= 0 && self.collapseAllCards == true) {
280 | index = oldRevealedIndex
281 | self.collapseAllCards = false
282 | return
283 | }
284 |
285 | if ((self.revealedIndex >= 0 && self.revealedIndex == index) || (self.revealedIndex >= 0 && index < 0)) && self.revealedCardIsFlipped == true {
286 | // do nothing, because the card is flipped
287 | } else if self.revealedIndex >= 0 && index >= 0 {
288 | if(self.collectionViewForceUnreveal == false) {
289 | if(collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, canUnrevealCardAtIndex: self.revealedIndex) == false) {
290 | return
291 | }
292 | }
293 | self.collectionViewForceUnreveal = false
294 | if(self.revealedCardIsFlipped == true) {
295 | self.flipRevealedCardBack(completion: {
296 | self.collectionView?.isScrollEnabled = true
297 | self.deinitializeRevealedCard()
298 | collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, willUnrevealCardAtIndex: self.revealedIndex)
299 | self.revealedIndex = -1
300 | self.collectionView?.performBatchUpdates({ self.collectionView?.reloadData() }, completion: { (finished) in
301 | collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, didUnrevealCardAtIndex: oldRevealedIndex)
302 | completion?()
303 | })
304 | })
305 | } else {
306 | self.collectionView?.isScrollEnabled = true
307 | self.deinitializeRevealedCard()
308 | collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, willUnrevealCardAtIndex: self.revealedIndex)
309 | self.revealedIndex = -1
310 | self.collectionView?.performBatchUpdates({ self.collectionView?.reloadData() }, completion: { (finished) in
311 | collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, didUnrevealCardAtIndex: oldRevealedIndex)
312 | completion?()
313 | })
314 | }
315 | } else {
316 | if(index < 0 && self.revealedIndex >= 0) {
317 | self.deinitializeRevealedCard()
318 | collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, willUnrevealCardAtIndex: self.revealedIndex)
319 | }
320 | if index >= 0 {
321 | self.revealedIndex = index
322 | if(collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, canRevealCardAtIndex: index) == false) {
323 | self.revealedIndex = -1
324 | self.collectionView?.isScrollEnabled = true
325 | self.deinitializeRevealedCard()
326 | return
327 | }
328 | collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, willRevealCardAtIndex: index)
329 | _ = self.initializeRevealedCard()
330 | self.collectionView?.isScrollEnabled = false
331 |
332 | self.collectionView?.performBatchUpdates({ self.collectionView?.reloadData() }, completion: { (finished) in
333 | collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, didRevealCardAtIndex: self.revealedIndex)
334 | completion?()
335 | })
336 | } else if(self.revealedIndex >= 0) {
337 | self.revealedIndex = index
338 | self.collectionView?.isScrollEnabled = false
339 | self.collectionView?.performBatchUpdates({ self.collectionView?.reloadData() }, completion: { (finished) in
340 | collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, didUnrevealCardAtIndex: oldRevealedIndex)
341 | completion?()
342 | })
343 | }
344 | self.revealedIndex = index
345 | }
346 | }
347 |
348 | /// Unreveal the revealed card
349 | ///
350 | /// - Parameter completion: An optional completion block. Will be executed the animation is finished.
351 | open func unrevealCard(completion: (() -> Void)? = nil) {
352 | if(self.revealedIndex == -1) {
353 | completion?()
354 | } else if(self.revealedCardIsFlipped == true) {
355 | self.flipRevealedCardBack(completion: {
356 | self.collectionViewForceUnreveal = true
357 | self.revealCardAt(index: self.revealedIndex, completion: completion)
358 | })
359 | } else {
360 | self.collectionViewForceUnreveal = true
361 | self.revealCardAt(index: self.revealedIndex, completion: completion)
362 | }
363 | }
364 |
365 | /// Flips the revealed card to the given view.
366 | /// The frame for the view will be the same as the cell
367 | ///
368 | /// - Parameter toView: The view for the backview of te card.
369 | /// - Parameter completion: An optional completion block. Will be executed the animation is finished.
370 | open func flipRevealedCard(toView: UIView, completion: (() -> Void)? = nil) {
371 | if(self.revealedCardIsFlipped == true) {
372 | return
373 | }
374 | if let cardCell = self.revealedCardCell, self.revealedIndex >= 0 {
375 | toView.removeFromSuperview()
376 | self.revealedCardFlipView = toView
377 | toView.frame = CGRect(x: 0, y: 0, width: cardCell.frame.width, height: cardCell.frame.height)
378 | toView.isHidden = true
379 | cardCell.addSubview(toView)
380 |
381 | self.revealedCardIsFlipped = true
382 | UIApplication.shared.keyWindow?.endEditing(true)
383 | let originalShouldRasterize = cardCell.layer.shouldRasterize
384 | cardCell.layer.shouldRasterize = false
385 |
386 | UIView.transition(with: cardCell, duration: 0.5, options:[.transitionFlipFromRight], animations: { () -> Void in
387 | cardCell.contentView.isHidden = true
388 | toView.isHidden = false
389 | }, completion: { (Bool) -> Void in
390 | cardCell.layer.shouldRasterize = originalShouldRasterize
391 | completion?()
392 | })
393 | }
394 | }
395 |
396 | /// Flips the flipped card back to the frontview.
397 | ///
398 | /// - Parameter completion: An optional completion block. Will be executed the animation is finished.
399 | open func flipRevealedCardBack(completion: (() -> Void)? = nil) {
400 | if(self.revealedCardIsFlipped == false) {
401 | completion?()
402 | return
403 | }
404 | if let cardCell = self.revealedCardCell {
405 | if let flipView = self.revealedCardFlipView {
406 | let originalShouldRasterize = cardCell.layer.shouldRasterize
407 | UIApplication.shared.keyWindow?.endEditing(true)
408 | cardCell.layer.shouldRasterize = false
409 |
410 | UIView.transition(with: cardCell, duration: 0.5, options:[.transitionFlipFromLeft], animations: { () -> Void in
411 | flipView.isHidden = true
412 | cardCell.contentView.isHidden = false
413 | }, completion: { (Bool) -> Void in
414 | flipView.removeFromSuperview()
415 | cardCell.layer.shouldRasterize = originalShouldRasterize
416 | self.revealedCardFlipView = nil
417 | self.revealedCardIsFlipped = false
418 | completion?()
419 | })
420 | }
421 | }
422 | }
423 |
424 | open func willInsert(indexPaths: [IndexPath]) {
425 | for indexPath in indexPaths {
426 | if(indexPath.section == 0) {
427 | if(indexPath.item <= self.revealedIndex) {
428 | collectionViewTemporaryTop += self.cardHeadHeight
429 | self.revealedIndex += 1
430 | }
431 | }
432 | }
433 | }
434 |
435 | open func willDelete(indexPaths: [IndexPath]) {
436 | let collectionViewLayoutDelegate = self.collectionView?.delegate as? HFCardCollectionViewLayoutDelegate
437 | for indexPath in indexPaths {
438 | if(indexPath.section == 0) {
439 | if(indexPath.item == self.revealedIndex) {
440 | self.revealedIndex = -1
441 | self.collectionView?.isScrollEnabled = true
442 | self.deinitializeRevealedCard()
443 | collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, willUnrevealCardAtIndex: indexPath.item)
444 | //collectionViewLayoutDelegate?.cardCollectionViewLayout?(self, didUnrevealCardAtIndex: indexPath.item)
445 | }
446 | if(indexPath.item <= self.revealedIndex) {
447 | collectionViewTemporaryTop -= self.cardHeadHeight
448 | self.revealedIndex -= 1
449 | }
450 | }
451 | }
452 | }
453 |
454 | ////////////////////////////////////////////////////////////////////////////////////////////////////
455 | ////////// Private //////////
456 | ////////////////////////////////////////////////////////////////////////////////////////////////////
457 |
458 | // MARK: Private Variables
459 |
460 | private var collectionViewIsInitialized = false
461 | private var collectionViewItemCount: Int = 0
462 | private var collectionViewTapGestureRecognizer: UITapGestureRecognizer?
463 | private var collectionViewIgnoreBottomContentOffsetChanges: Bool = false
464 | private var collectionViewLastBottomContentOffset: CGFloat = 0
465 | private var collectionViewForceUnreveal: Bool = false
466 | private var collectionViewDeletedIndexPaths = [IndexPath]()
467 | private var collectionViewTemporaryTop: CGFloat = 0
468 |
469 | private var cardCollectionBoundsSize: CGSize = .zero
470 | private var cardCollectionViewLayoutAttributes:[HFCardCollectionViewLayoutAttributes]!
471 | private var cardCollectionBottomCardsSet: [Int] = []
472 | private var cardCollectionBottomCardsRevealedIndex: CGFloat = 0
473 | private var cardCollectionCellSize: CGSize = .zero
474 |
475 | private var revealedCardCell: UICollectionViewCell?
476 | private var revealedCardPanGestureRecognizer: UIPanGestureRecognizer?
477 | private var revealedCardPanGestureTouchLocationY: CGFloat = 0
478 | private var revealedCardFlipView: UIView?
479 | private var revealedCardIsFlipped: Bool = false
480 |
481 | private var movingCardSelectedIndex: Int = -1
482 | private var movingCardGestureRecognizer: UILongPressGestureRecognizer?
483 | private var movingCardActive: Bool = false
484 | private var movingCardGestureStartLocation: CGPoint = .zero
485 | private var movingCardGestureCurrentLocation: CGPoint = .zero
486 | private var movingCardCenterStart: CGPoint = .zero
487 | private var movingCardSnapshotCell: UIView?
488 | private var movingCardLastTouchedLocation: CGPoint = .zero
489 | private var movingCardLastTouchedIndexPath: IndexPath?
490 | private var movingCardStartIndexPath: IndexPath?
491 |
492 | private var autoscrollDisplayLink: CADisplayLink?
493 | private var autoscrollDirection: HFCardCollectionScrollDirection = .unknown
494 |
495 | // MARK: Private calculated Variable
496 |
497 | private var contentInset: UIEdgeInsets {
498 | get {
499 | if #available(iOS 11, *) {
500 | return self.collectionView!.adjustedContentInset
501 | } else {
502 | return self.collectionView!.contentInset
503 | }
504 | }
505 | }
506 |
507 | private var contentOffsetTop: CGFloat {
508 | get {
509 | return self.collectionView!.contentOffset.y + self.contentInset.top
510 | }
511 | }
512 |
513 | private var bottomCardCount: CGFloat {
514 | return CGFloat(min(self.collectionViewItemCount, min(self.bottomNumberOfStackedCards, self.cardCollectionBottomCardsSet.count)))
515 | }
516 |
517 | private var contentInsetBottom: CGFloat {
518 | if(self.collectionViewIgnoreBottomContentOffsetChanges == true) {
519 | return self.collectionViewLastBottomContentOffset
520 | }
521 | self.collectionViewLastBottomContentOffset = self.contentInset.bottom
522 | return self.contentInset.bottom
523 | }
524 |
525 | private var scalePerCard: CGFloat {
526 | let maximumScale = self.bottomStackedCardsMaximumScale
527 | let minimumScale = (maximumScale < self.bottomStackedCardsMinimumScale) ? maximumScale : self.bottomStackedCardsMinimumScale
528 | return (maximumScale - minimumScale) / CGFloat(self.bottomNumberOfStackedCards)
529 | }
530 |
531 | // MARK: Initialize HFCardCollectionViewLayout
532 |
533 | internal func installMoveCardsGestureRecognizer() {
534 | self.movingCardGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.movingCardGestureHandler))
535 | self.movingCardGestureRecognizer?.minimumPressDuration = 0.49
536 | self.movingCardGestureRecognizer?.delegate = self
537 | self.collectionView?.addGestureRecognizer(self.movingCardGestureRecognizer!)
538 | }
539 |
540 | private func initializeCardCollectionViewLayout() {
541 | self.collectionViewIsInitialized = true
542 |
543 | NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
544 | NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardDidHide(_:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
545 |
546 | self.collectionViewTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.collectionViewTapGestureHandler))
547 | self.collectionViewTapGestureRecognizer?.delegate = self
548 | self.collectionView?.addGestureRecognizer(self.collectionViewTapGestureRecognizer!)
549 | }
550 |
551 | @objc func keyboardWillShow(_ notification: Notification) {
552 | self.collectionViewIgnoreBottomContentOffsetChanges = true
553 | }
554 |
555 | @objc func keyboardDidHide(_ notification: Notification) {
556 | self.collectionViewIgnoreBottomContentOffsetChanges = false
557 | }
558 |
559 | // MARK: UICollectionViewLayout Overrides
560 |
561 | /// The width and height of the collection view’s contents.
562 | override open var collectionViewContentSize: CGSize {
563 | get {
564 | let contentHeight = (self.cardHeadHeight * CGFloat(self.collectionViewItemCount)) + self.spaceAtTopForBackgroundView + self.spaceAtBottom
565 | let contentWidth = self.collectionView!.frame.width - (contentInset.left + contentInset.right)
566 | return CGSize.init(width: contentWidth, height: contentHeight)
567 | }
568 | }
569 |
570 | /// Tells the layout object to update the current layout.
571 | override open func prepare() {
572 | super.prepare()
573 |
574 | self.collectionViewItemCount = self.collectionView!.numberOfItems(inSection: 0)
575 | self.cardCollectionCellSize = self.generateCellSize()
576 |
577 | if(self.collectionViewIsInitialized == false) {
578 | self.initializeCardCollectionViewLayout()
579 | }
580 |
581 | self.cardCollectionViewLayoutAttributes = self.generateCardCollectionViewLayoutAttributes()
582 | }
583 |
584 | /// A layout attributes object containing the information to apply to the item’s cell.
585 | override open func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
586 | return self.cardCollectionViewLayoutAttributes[indexPath.item]
587 | }
588 |
589 | /// An array of UICollectionViewLayoutAttributes objects representing the layout information for the cells and views. The default implementation returns nil.
590 | ///
591 | /// - Parameter rect: The rectangle
592 | override open func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
593 | let attributes = self.cardCollectionViewLayoutAttributes.filter { (layout) -> Bool in
594 | return (layout.frame.intersects(rect))
595 | }
596 | return attributes
597 | }
598 |
599 | /// true if the collection view requires a layout update or false if the layout does not need to change.
600 | ///
601 | /// - Parameter newBounds: The new bounds of the collection view.
602 | override open func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
603 | return true
604 | }
605 |
606 | /// The content offset that you want to use instead.
607 | ///
608 | /// - Parameter proposedContentOffset: The proposed point (in the collection view’s content view) at which to stop scrolling. This is the value at which scrolling would naturally stop if no adjustments were made. The point reflects the upper-left corner of the visible content.
609 | /// - Parameter velocity: The current scrolling velocity along both the horizontal and vertical axes. This value is measured in points per second.
610 | override open func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
611 | let proposedContentOffsetY = proposedContentOffset.y + self.contentInset.top
612 | if(self.spaceAtTopShouldSnap == true && self.spaceAtTopForBackgroundView > 0) {
613 | if(proposedContentOffsetY > 0 && proposedContentOffsetY < self.spaceAtTopForBackgroundView) {
614 | let scrollToTopY = self.spaceAtTopForBackgroundView * 0.5
615 | if(proposedContentOffsetY < scrollToTopY) {
616 | return CGPoint(x: 0, y: 0 - self.contentInset.top)
617 | } else {
618 | return CGPoint(x: 0, y: self.spaceAtTopForBackgroundView - self.contentInset.top)
619 | }
620 | }
621 | }
622 | if(self.scrollShouldSnapCardHead == true && proposedContentOffsetY > self.spaceAtTopForBackgroundView && self.collectionView!.contentSize.height > self.collectionView!.frame.height + self.cardHeadHeight) {
623 | let startIndex = Int((proposedContentOffsetY - self.spaceAtTopForBackgroundView) / self.cardHeadHeight) + 1
624 | let positionToGoUp = self.cardHeadHeight * 0.5
625 | let cardHeadPosition = (proposedContentOffsetY - self.spaceAtTopForBackgroundView).truncatingRemainder(dividingBy: self.cardHeadHeight)
626 | if(cardHeadPosition > positionToGoUp) {
627 | let targetY = (CGFloat(startIndex) * self.cardHeadHeight) + (self.spaceAtTopForBackgroundView - self.contentInset.top)
628 | return CGPoint(x: 0, y: targetY)
629 | } else {
630 | let targetY = (CGFloat(startIndex) * self.cardHeadHeight) - self.cardHeadHeight + (self.spaceAtTopForBackgroundView - self.contentInset.top)
631 | return CGPoint(x: 0, y: targetY)
632 | }
633 | }
634 | return proposedContentOffset
635 | }
636 |
637 | /// This method is called when there is an update with deletes to the collection view.
638 | override open func prepare(forCollectionViewUpdates updateItems: [UICollectionViewUpdateItem]) {
639 | super.prepare(forCollectionViewUpdates: updateItems)
640 |
641 | collectionViewDeletedIndexPaths.removeAll(keepingCapacity: false)
642 |
643 | for update in updateItems {
644 | switch update.updateAction {
645 | case .delete:
646 | collectionViewDeletedIndexPaths.append(update.indexPathBeforeUpdate!)
647 | default:
648 | return
649 | }
650 | }
651 | }
652 |
653 | /// Custom animation for deleting cells.
654 | override open func finalLayoutAttributesForDisappearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
655 | let attrs = super.finalLayoutAttributesForDisappearingItem(at: itemIndexPath)
656 |
657 | if collectionViewDeletedIndexPaths.contains(itemIndexPath) {
658 | if let attrs = attrs {
659 | attrs.alpha = 0.0
660 | attrs.transform3D = CATransform3DScale(attrs.transform3D, 0.001, 0.001, 1)
661 | }
662 | }
663 |
664 | return attrs
665 | }
666 |
667 | /// Remove deleted indexPaths
668 | override open func finalizeCollectionViewUpdates() {
669 | super.finalizeCollectionViewUpdates()
670 | collectionViewDeletedIndexPaths.removeAll(keepingCapacity: false)
671 | }
672 |
673 | // MARK: Private Functions for UICollectionViewLayout
674 |
675 | @objc internal func collectionViewTapGestureHandler() {
676 | if let tapLocation = self.collectionViewTapGestureRecognizer?.location(in: self.collectionView) {
677 | if let indexPath = self.collectionView?.indexPathForItem(at: tapLocation) {
678 | self.collectionView?.delegate?.collectionView?(self.collectionView!, didSelectItemAt: indexPath)
679 | }
680 | }
681 | }
682 |
683 | private func generateCellSize() -> CGSize {
684 | let width = self.collectionView!.frame.width - (self.contentInset.left + self.contentInset.right)
685 | let maxHeight = self.collectionView!.frame.height - (self.bottomCardLookoutMargin * CGFloat(self.bottomNumberOfStackedCards)) - (self.contentInset.top + self.contentInsetBottom) - 2
686 | let height = (self.cardMaximumHeight == 0 || self.cardMaximumHeight > maxHeight) ? maxHeight : self.cardMaximumHeight
687 | let size = CGSize.init(width: width, height: height)
688 | return size
689 | }
690 |
691 | private func generateCardCollectionViewLayoutAttributes() -> [HFCardCollectionViewLayoutAttributes] {
692 | var cardCollectionViewLayoutAttributes: [HFCardCollectionViewLayoutAttributes] = []
693 | var shouldReloadAllItems = false
694 | if(self.cardCollectionViewLayoutAttributes != nil && self.collectionViewItemCount == self.cardCollectionViewLayoutAttributes.count) {
695 | cardCollectionViewLayoutAttributes = self.cardCollectionViewLayoutAttributes
696 | } else {
697 | shouldReloadAllItems = true
698 | }
699 |
700 | var startIndex = Int((self.collectionView!.contentOffset.y + self.contentInset.top - self.spaceAtTopForBackgroundView + collectionViewTemporaryTop) / self.cardHeadHeight) - 10
701 | var endBeforeIndex = Int((self.collectionView!.contentOffset.y + self.collectionView!.frame.size.height + collectionViewTemporaryTop) / self.cardHeadHeight) + 5
702 |
703 | if(startIndex < 0) {
704 | startIndex = 0
705 | }
706 | if(endBeforeIndex > self.collectionViewItemCount) {
707 | endBeforeIndex = self.collectionViewItemCount
708 | }
709 | if(shouldReloadAllItems == true) {
710 | startIndex = 0
711 | endBeforeIndex = self.collectionViewItemCount
712 | }
713 |
714 | self.cardCollectionBottomCardsSet = self.generateBottomIndexes()
715 |
716 | var bottomIndex: CGFloat = 0
717 | for itemIndex in startIndex.. [Int] {
742 | if self.revealedIndex < 0 {
743 | if self.collapseAllCards == false {
744 | return []
745 | } else {
746 | let startIndex: Int = Int((self.contentOffsetTop + collectionViewTemporaryTop) / self.cardHeadHeight)
747 | let endIndex = max(0, startIndex + self.bottomNumberOfStackedCards - 2)
748 | return Array(startIndex...endIndex)
749 | }
750 | }
751 |
752 | let half = Int(self.bottomNumberOfStackedCards / 2)
753 | var minIndex = self.revealedIndex - half
754 | var maxIndex = self.revealedIndex + half
755 |
756 | if minIndex < 0 {
757 | minIndex = 0
758 | maxIndex = self.revealedIndex + half + abs(self.revealedIndex - half)
759 | } else if maxIndex >= self.collectionViewItemCount {
760 | minIndex = (self.collectionViewItemCount - 2 * half) - 1
761 | maxIndex = self.collectionViewItemCount - 1
762 | }
763 |
764 | self.cardCollectionBottomCardsRevealedIndex = 0
765 |
766 | return Array(minIndex...maxIndex).filter({ (value) -> Bool in
767 | if value >= 0 && value != self.revealedIndex {
768 | if(value < self.revealedIndex) {
769 | self.cardCollectionBottomCardsRevealedIndex += 1
770 | }
771 | return true
772 | }
773 | return false
774 | })
775 | }
776 |
777 | private func generateNonRevealedCardsAttribute(_ attribute: HFCardCollectionViewLayoutAttributes) {
778 | let cardHeadHeight = self.calculateCardHeadHeight()
779 |
780 | let startIndex = Int((self.contentOffsetTop + collectionViewTemporaryTop - self.spaceAtTopForBackgroundView) / cardHeadHeight)
781 | let currentIndex = attribute.indexPath.item
782 | if(currentIndex == self.movingCardSelectedIndex) {
783 | attribute.alpha = 0.0
784 | } else {
785 | attribute.alpha = 1.0
786 | }
787 |
788 | let currentFrame = CGRect(x: 0, y: self.spaceAtTopForBackgroundView + cardHeadHeight * CGFloat(currentIndex), width: self.cardCollectionCellSize.width, height: self.cardCollectionCellSize.height)
789 |
790 | if(self.contentOffsetTop >= 0 && self.contentOffsetTop <= self.spaceAtTopForBackgroundView) {
791 | attribute.frame = currentFrame
792 | } else if(self.contentOffsetTop > self.spaceAtTopForBackgroundView) {
793 | attribute.isHidden = (self.scrollStopCardsAtTop == true && currentIndex < startIndex)
794 |
795 | if(self.movingCardSelectedIndex >= 0 && currentIndex + 1 == self.movingCardSelectedIndex) {
796 | attribute.isHidden = false
797 | }
798 | if (self.scrollStopCardsAtTop == true && ((currentIndex != 0 && currentIndex <= startIndex) || (currentIndex == 0 && (self.contentOffsetTop - self.spaceAtTopForBackgroundView) > 0))) {
799 | var newFrame = currentFrame
800 | newFrame.origin.y = self.contentOffsetTop
801 | attribute.frame = newFrame
802 | } else {
803 | attribute.frame = currentFrame
804 | }
805 | if(attribute.isHidden == true && currentIndex < startIndex - 5) {
806 | attribute.frame = currentFrame
807 | attribute.frame.origin.y = self.collectionView!.frame.height * -1.5
808 | }
809 | } else {
810 | if(self.cardShouldStretchAtScrollTop == true) {
811 | let stretchMultiplier: CGFloat = (1 + (CGFloat(currentIndex + 1) * -0.2))
812 | var newFrame = currentFrame
813 | newFrame.origin.y = newFrame.origin.y + CGFloat(self.contentOffsetTop * stretchMultiplier)
814 | attribute.frame = newFrame
815 | } else {
816 | attribute.frame = currentFrame
817 | }
818 | }
819 | attribute.isRevealed = false
820 | }
821 |
822 | private func generateRevealedCardAttribute(_ attribute: HFCardCollectionViewLayoutAttributes) {
823 | attribute.isRevealed = true
824 | if(self.collectionViewItemCount == 1) {
825 | attribute.frame = CGRect.init(x: 0, y: self.contentOffsetTop + self.spaceAtTopForBackgroundView + 0.01 , width: self.cardCollectionCellSize.width, height: self.cardCollectionCellSize.height)
826 | } else {
827 | attribute.frame = CGRect.init(x: 0, y: self.contentOffsetTop + 0.01 , width: self.cardCollectionCellSize.width, height: self.cardCollectionCellSize.height)
828 | }
829 | }
830 |
831 | private func generateBottomCardsAttribute(_ attribute: HFCardCollectionViewLayoutAttributes, bottomIndex:inout CGFloat) {
832 | let index = attribute.indexPath.item
833 | let posY = self.cardHeadHeight * CGFloat(index)
834 | let currentFrame = CGRect(x: self.collectionView!.frame.origin.x, y: posY, width: self.cardCollectionCellSize.width, height: self.cardCollectionCellSize.height)
835 | let maxY = self.collectionView!.contentOffset.y + self.collectionView!.frame.height
836 | let contentFrame = CGRect(x: 0, y: self.collectionView!.contentOffset.y, width: self.collectionView!.frame.width, height: maxY)
837 | if self.cardCollectionBottomCardsSet.contains(index) {
838 | let margin: CGFloat = self.bottomCardLookoutMargin
839 | let baseHeight = (self.collectionView!.frame.height + self.collectionView!.contentOffset.y) - self.contentInsetBottom - (margin * self.bottomCardCount)
840 | let scale: CGFloat = self.calculateCardScale(forIndex: bottomIndex)
841 | let yAddition: CGFloat = (self.cardCollectionCellSize.height - (self.cardCollectionCellSize.height * scale)) / 2
842 | let yPos: CGFloat = baseHeight + (bottomIndex * margin) - yAddition
843 | attribute.frame = CGRect.init(x: 0, y: yPos, width: self.cardCollectionCellSize.width, height: self.cardCollectionCellSize.height)
844 | attribute.transform = CGAffineTransform(scaleX: scale, y: scale)
845 | bottomIndex += 1
846 | } else if contentFrame.intersects(currentFrame) {
847 | attribute.isHidden = true
848 | attribute.alpha = 0.0
849 | attribute.frame = CGRect.init(x: 0, y: maxY, width: self.cardCollectionCellSize.width, height: self.cardCollectionCellSize.height)
850 | }else {
851 | attribute.isHidden = true
852 | attribute.alpha = 0.0
853 | attribute.frame = CGRect(x: 0, y: posY, width: cardCollectionCellSize.width, height: cardCollectionCellSize.height)
854 | }
855 | attribute.isRevealed = false
856 | }
857 |
858 | private func calculateCardScale(forIndex index: CGFloat, scaleBehindCard: Bool = false) -> CGFloat {
859 | if(self.bottomStackedCardsShouldScale == true) {
860 | let scalePerCard = self.scalePerCard
861 | let addedDownScale: CGFloat = (scaleBehindCard == true && index < self.bottomCardCount) ? scalePerCard : 0.0
862 | return min(1.0, self.bottomStackedCardsMaximumScale - (((index + 1 - self.bottomCardCount) * -1) * scalePerCard) - addedDownScale)
863 | }
864 | return 1.0
865 | }
866 |
867 | private func calculateCardHeadHeight() -> CGFloat {
868 | var cardHeadHeight = self.cardHeadHeight
869 | if(self.cardShouldExpandHeadHeight == true) {
870 | cardHeadHeight = max(self.cardHeadHeight, (self.collectionView!.frame.height - (self.contentInset.top + self.contentInsetBottom + self.spaceAtTopForBackgroundView)) / CGFloat(self.collectionViewItemCount))
871 | }
872 | return cardHeadHeight
873 | }
874 |
875 | // MARK: Revealed Card
876 |
877 | private func initializeRevealedCard() -> Bool {
878 | if let cell = self.collectionView?.cellForItem(at: IndexPath(item: self.revealedIndex, section: 0)) {
879 | self.revealedCardCell = cell
880 | self.revealedCardPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.revealedCardPanGestureHandler))
881 | self.revealedCardPanGestureRecognizer?.delegate = self
882 | self.revealedCardCell?.addGestureRecognizer(self.revealedCardPanGestureRecognizer!)
883 | return true
884 | }
885 | return false
886 | }
887 |
888 | private func deinitializeRevealedCard() {
889 | if self.revealedCardCell != nil && self.revealedCardPanGestureRecognizer != nil {
890 | self.revealedCardCell?.removeGestureRecognizer(self.revealedCardPanGestureRecognizer!)
891 | self.revealedCardPanGestureRecognizer = nil
892 | self.revealedCardCell = nil
893 | }
894 | }
895 |
896 | @objc internal func revealedCardPanGestureHandler() {
897 | if self.collectionViewItemCount == 1 || self.revealedCardIsFlipped == true {
898 | return
899 | }
900 | if let revealedCardPanGestureRecognizer = self.revealedCardPanGestureRecognizer, self.revealedCardCell != nil {
901 | let gestureTouchLocation = revealedCardPanGestureRecognizer.location(in: self.collectionView)
902 | let shiftY: CGFloat = (gestureTouchLocation.y - self.revealedCardPanGestureTouchLocationY > 0) ? gestureTouchLocation.y - self.revealedCardPanGestureTouchLocationY : 0
903 |
904 | switch revealedCardPanGestureRecognizer.state {
905 | case .began:
906 | UIApplication.shared.keyWindow?.endEditing(true)
907 | self.revealedCardPanGestureTouchLocationY = gestureTouchLocation.y
908 | case .changed:
909 | let scaleTarget = self.calculateCardScale(forIndex: self.cardCollectionBottomCardsRevealedIndex, scaleBehindCard: true)
910 | let scaleDiff: CGFloat = 1.0 - scaleTarget
911 | let scale: CGFloat = 1.0 - min(((shiftY * scaleDiff) / (self.collectionView!.frame.height / 2)) , scaleDiff)
912 | let transformY = CGAffineTransform.init(translationX: 0, y: shiftY)
913 | let transformScale = CGAffineTransform.init(scaleX: scale, y: scale)
914 | self.revealedCardCell?.transform = transformY.concatenating(transformScale)
915 | default:
916 | let isNeedReload = (shiftY > self.revealedCardCell!.frame.height / 7) ? true : false
917 | let resetY = (isNeedReload) ? self.collectionView!.frame.height : 0
918 | let scale: CGFloat = (isNeedReload) ? self.calculateCardScale(forIndex: self.cardCollectionBottomCardsRevealedIndex, scaleBehindCard: true) : 1.0
919 |
920 | let transformScale = CGAffineTransform.init(scaleX: scale, y: scale)
921 | let transformY = CGAffineTransform.init(translationX: 0, y: resetY * (1.0 + (1.0 - scale)))
922 |
923 | UIView.animate(withDuration: 0.3, animations: {
924 | self.revealedCardCell?.transform = transformY.concatenating(transformScale)
925 | }, completion: { (finished) in
926 | if isNeedReload && finished {
927 | self.revealCardAt(index: self.revealedIndex)
928 | }
929 | })
930 | }
931 | }
932 | }
933 |
934 | // MARK: Moving Card
935 |
936 | @objc internal func movingCardGestureHandler() {
937 | let moveUpOffset: CGFloat = 20
938 |
939 | if let movingCardGestureRecognizer = self.movingCardGestureRecognizer {
940 | switch movingCardGestureRecognizer.state {
941 | case .began:
942 | self.movingCardGestureStartLocation = movingCardGestureRecognizer.location(in: self.collectionView)
943 | if let indexPath = self.collectionView?.indexPathForItem(at: self.movingCardGestureStartLocation) {
944 | self.movingCardActive = true
945 | if(indexPath.item < self.firstMovableIndex) {
946 | self.movingCardActive = false
947 | return
948 | }
949 | if let cell = self.collectionView?.cellForItem(at: indexPath) {
950 | self.movingCardStartIndexPath = indexPath
951 | self.movingCardCenterStart = cell.center
952 | self.movingCardSnapshotCell = cell.snapshotView(afterScreenUpdates: false)
953 | self.movingCardSnapshotCell?.frame = cell.frame
954 | self.movingCardSnapshotCell?.alpha = 1.0
955 | self.movingCardSnapshotCell?.layer.zPosition = cell.layer.zPosition
956 | self.collectionView?.insertSubview(self.movingCardSnapshotCell!, aboveSubview: cell)
957 | cell.alpha = 0.0
958 | self.movingCardSelectedIndex = indexPath.item
959 | UIView.animate(withDuration: 0.2, animations: {
960 | self.movingCardSnapshotCell?.frame.origin.y -= moveUpOffset
961 | })
962 | }
963 | } else {
964 | self.movingCardActive = false
965 | }
966 | case .changed:
967 | if self.movingCardActive == true {
968 | self.movingCardGestureCurrentLocation = movingCardGestureRecognizer.location(in: self.collectionView)
969 | var currentCenter = self.movingCardCenterStart
970 | currentCenter.y += (self.movingCardGestureCurrentLocation.y - self.movingCardGestureStartLocation.y - moveUpOffset)
971 | self.movingCardSnapshotCell?.center = currentCenter
972 | if(self.movingCardGestureCurrentLocation.y > ((self.collectionView!.contentOffset.y + self.collectionView!.frame.height) - self.spaceAtBottom - self.contentInsetBottom - self.scrollAreaBottom)) {
973 | self.setupScrollTimer(direction: .down)
974 | } else if((self.movingCardGestureCurrentLocation.y - self.collectionView!.contentOffset.y) - self.contentInset.top < self.scrollAreaTop) {
975 | self.setupScrollTimer(direction: .up)
976 | } else {
977 | self.invalidateScrollTimer()
978 | }
979 |
980 | var tempIndexPath = self.collectionView?.indexPathForItem(at: self.movingCardGestureCurrentLocation)
981 | if(tempIndexPath == nil) {
982 | tempIndexPath = self.collectionView?.indexPathForItem(at: self.movingCardLastTouchedLocation)
983 | }
984 |
985 | if let currentTouchedIndexPath = tempIndexPath {
986 | self.movingCardLastTouchedLocation = self.movingCardGestureCurrentLocation
987 | if(currentTouchedIndexPath.item < self.firstMovableIndex) {
988 | return
989 | }
990 | if(self.movingCardLastTouchedIndexPath == nil && currentTouchedIndexPath != self.movingCardStartIndexPath!) {
991 | self.movingCardLastTouchedIndexPath = self.movingCardStartIndexPath
992 | }
993 | if(self.self.movingCardLastTouchedIndexPath != nil && self.movingCardLastTouchedIndexPath! != currentTouchedIndexPath) {
994 | let movingCell = self.collectionView?.cellForItem(at: currentTouchedIndexPath)
995 | let movingCellAttr = self.collectionView?.layoutAttributesForItem(at: currentTouchedIndexPath)
996 |
997 | if(movingCell != nil) {
998 | let cardHeadHeight = self.calculateCardHeadHeight()
999 | UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseOut, animations: {
1000 | movingCell?.frame.origin.y -= cardHeadHeight
1001 | }, completion: { (finished) in
1002 | movingCellAttr?.frame.origin.y -= cardHeadHeight
1003 | })
1004 | }
1005 |
1006 | self.movingCardSelectedIndex = currentTouchedIndexPath.item
1007 | self.collectionView?.dataSource?.collectionView?(self.collectionView!, moveItemAt: currentTouchedIndexPath, to: self.movingCardLastTouchedIndexPath!)
1008 | UIView.performWithoutAnimation {
1009 | self.collectionView?.moveItem(at: currentTouchedIndexPath, to: self.movingCardLastTouchedIndexPath!)
1010 | }
1011 |
1012 | self.movingCardLastTouchedIndexPath = currentTouchedIndexPath
1013 | if let belowCell = self.collectionView?.cellForItem(at: currentTouchedIndexPath) {
1014 | self.movingCardSnapshotCell?.removeFromSuperview()
1015 | self.collectionView?.insertSubview(self.movingCardSnapshotCell!, belowSubview: belowCell)
1016 | self.movingCardSnapshotCell?.layer.zPosition = belowCell.layer.zPosition
1017 | } else {
1018 | self.collectionView?.sendSubview(toBack: self.movingCardSnapshotCell!)
1019 | }
1020 | }
1021 | }
1022 | }
1023 | case .ended:
1024 | self.invalidateScrollTimer()
1025 | if self.movingCardActive == true {
1026 | var indexPath = self.movingCardStartIndexPath!
1027 | if(self.movingCardLastTouchedIndexPath != nil) {
1028 | indexPath = self.movingCardLastTouchedIndexPath!
1029 | }
1030 | if let cell = self.collectionView?.cellForItem(at: indexPath) {
1031 | UIView.animate(withDuration: 0.2, animations: {
1032 | self.movingCardSnapshotCell?.frame = cell.frame
1033 | }, completion: { (finished) in
1034 | self.movingCardActive = false
1035 | self.movingCardLastTouchedIndexPath = nil
1036 | self.movingCardSelectedIndex = -1
1037 | self.collectionView?.reloadData()
1038 | self.movingCardSnapshotCell?.removeFromSuperview()
1039 | self.movingCardSnapshotCell = nil
1040 | if(self.movingCardStartIndexPath == indexPath) {
1041 | UIView.animate(withDuration: 0, animations: {
1042 | self.invalidateLayout()
1043 | })
1044 | }
1045 | })
1046 | } else {
1047 | fallthrough
1048 | }
1049 | }
1050 | case .cancelled:
1051 | self.movingCardActive = false
1052 | self.movingCardLastTouchedIndexPath = nil
1053 | self.movingCardSelectedIndex = -1
1054 | self.collectionView?.reloadData()
1055 | self.movingCardSnapshotCell?.removeFromSuperview()
1056 | self.movingCardSnapshotCell = nil
1057 | self.invalidateLayout()
1058 | default:
1059 | break
1060 | }
1061 | }
1062 | }
1063 |
1064 | // MARK: AutoScroll
1065 |
1066 | enum HFCardCollectionScrollDirection : Int {
1067 | case unknown = 0
1068 | case up
1069 | case down
1070 | }
1071 |
1072 | private func setupScrollTimer(direction: HFCardCollectionScrollDirection) {
1073 | if(self.autoscrollDisplayLink != nil && self.autoscrollDisplayLink!.isPaused == false) {
1074 | if(direction == self.autoscrollDirection) {
1075 | return
1076 | }
1077 | }
1078 | self.invalidateScrollTimer()
1079 | self.autoscrollDisplayLink = CADisplayLink(target: self, selector: #selector(self.autoscrollHandler(displayLink:)))
1080 | self.autoscrollDirection = direction
1081 | self.autoscrollDisplayLink?.add(to: .main, forMode: .commonModes)
1082 | }
1083 |
1084 | private func invalidateScrollTimer() {
1085 | if(self.autoscrollDisplayLink != nil && self.autoscrollDisplayLink!.isPaused == false) {
1086 | self.autoscrollDisplayLink?.invalidate()
1087 | }
1088 | self.autoscrollDisplayLink = nil
1089 | }
1090 |
1091 | @objc internal func autoscrollHandler(displayLink: CADisplayLink) {
1092 | let direction = self.autoscrollDirection
1093 | if(direction == .unknown) {
1094 | return
1095 | }
1096 |
1097 | let scrollMultiplier = self.generateScrollSpeedMultiplier()
1098 | let frameSize = self.collectionView!.frame.size
1099 | let contentSize = self.collectionView!.contentSize
1100 | let contentOffset = self.collectionView!.contentOffset
1101 | let contentInset = self.contentInset
1102 | var distance: CGFloat = CGFloat(rint(scrollMultiplier * displayLink.duration))
1103 | var translation = CGPoint.zero
1104 |
1105 | switch(direction) {
1106 | case .up:
1107 | distance = -distance
1108 | let minY: CGFloat = 0.0 - contentInset.top
1109 | if (contentOffset.y + distance) <= minY {
1110 | distance = -contentOffset.y - contentInset.top
1111 | }
1112 | translation = CGPoint(x: 0.0, y: distance)
1113 | case .down:
1114 | let maxY: CGFloat = max(contentSize.height, frameSize.height) - frameSize.height + self.contentInsetBottom
1115 | if (contentOffset.y + distance) >= maxY {
1116 | distance = maxY - contentOffset.y
1117 | }
1118 | translation = CGPoint(x: 0.0, y: distance)
1119 | default:
1120 | break
1121 | }
1122 |
1123 | self.collectionView!.contentOffset = self.cgPointAdd(contentOffset, translation)
1124 | self.movingCardGestureHandler()
1125 | }
1126 |
1127 | private func generateScrollSpeedMultiplier() -> Double {
1128 | var multiplier: Double = 250.0
1129 | if let movingCardGestureRecognizer = self.movingCardGestureRecognizer {
1130 | let touchLocation = movingCardGestureRecognizer.location(in: self.collectionView)
1131 | let maxSpeed: CGFloat = 600
1132 | if(self.autoscrollDirection == .up) {
1133 | let touchPosY = min(max(0, self.scrollAreaTop - (touchLocation.y - self.contentOffsetTop)), self.scrollAreaTop)
1134 | multiplier = Double(maxSpeed * (touchPosY / self.scrollAreaTop))
1135 | } else if(self.autoscrollDirection == .down) {
1136 | let offsetTop = ((self.collectionView!.contentOffset.y + self.collectionView!.frame.height) - self.spaceAtBottom - self.contentInsetBottom - self.scrollAreaBottom)
1137 | let touchPosY = min(max(0, (touchLocation.y - offsetTop)), self.scrollAreaBottom)
1138 | multiplier = Double(maxSpeed * (touchPosY / self.scrollAreaBottom))
1139 | }
1140 | }
1141 | return multiplier
1142 | }
1143 |
1144 | private func cgPointAdd(_ point1: CGPoint, _ point2: CGPoint) -> CGPoint {
1145 | return CGPoint(x: point1.x + point2.x, y: point1.y + point2.y)
1146 | }
1147 |
1148 | // MARK: UIGestureRecognizerDelegate
1149 |
1150 | /// Return true no card is revealed.
1151 | ///
1152 | /// - Parameter gestureRecognizer: The gesture recognizer.
1153 | public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
1154 | if(gestureRecognizer == self.movingCardGestureRecognizer || gestureRecognizer == self.collectionViewTapGestureRecognizer) {
1155 | if(self.revealedIndex >= 0) {
1156 | return false
1157 | }
1158 | }
1159 |
1160 | if(gestureRecognizer == self.revealedCardPanGestureRecognizer) {
1161 | let velocity = self.revealedCardPanGestureRecognizer?.velocity(in: self.revealedCardPanGestureRecognizer?.view)
1162 | let result = fabs(velocity!.y) > fabs(velocity!.x)
1163 | return result
1164 | }
1165 | return true
1166 | }
1167 |
1168 | }
1169 |
--------------------------------------------------------------------------------