Compare commits

..

5 Commits

Author SHA1 Message Date
Arnaud Dorgans c125f52695 fix open var 2018-01-03 11:02:50 +01:00
Arnaud Dorgans 075fb6c75b add exemples & delegate 2018-01-03 10:23:49 +01:00
Arnaud Dorgans 03e9dbd3a4 add CocoaProxy 2017-12-27 23:26:31 +01:00
Arnaud Dorgans 1fbb837941 update 2017-12-25 18:36:20 +01:00
Arnaud Dorgans 5746d5a7c4 Update README.md 2017-12-25 18:30:35 +01:00
18 changed files with 756 additions and 214 deletions
@@ -9,12 +9,15 @@
/* Begin PBXBuildFile section */
5259B95F4E58F763F6C70333 /* Pods_InfiniteLayout_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6830D8B970E919B725A0D5E /* Pods_InfiniteLayout_Example.framework */; };
607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; };
607FACD81AFB9204008FA782 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* ViewController.swift */; };
607FACD81AFB9204008FA782 /* CustomViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* CustomViewController.swift */; };
607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; };
607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; };
607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; };
607FACEC1AFB9204008FA782 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* Tests.swift */; };
D403973F1FEBFA9D006C41D2 /* Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D403973E1FEBFA9D006C41D2 /* Cell.swift */; };
D4162A391FF502A900AC2572 /* CustomLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4162A381FF502A900AC2572 /* CustomLayout.swift */; };
D43362D11FF64B330040C679 /* BaseCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43362CF1FF64B330040C679 /* BaseCollectionViewController.swift */; };
D4B9816E1FFCCC900016C676 /* PickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4B9816D1FFCCC900016C676 /* PickerController.swift */; };
E997A539C8278E7A661C9F91 /* Pods_InfiniteLayout_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C50F79B0DFFDE95D322480B2 /* Pods_InfiniteLayout_Tests.framework */; };
/* End PBXBuildFile section */
@@ -35,7 +38,7 @@
607FACD01AFB9204008FA782 /* InfiniteLayout_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = InfiniteLayout_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
607FACD71AFB9204008FA782 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
607FACD71AFB9204008FA782 /* CustomViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomViewController.swift; sourceTree = "<group>"; };
607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
@@ -46,6 +49,9 @@
AD3D900D0067605DEAFF148B /* Pods-InfiniteLayout_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InfiniteLayout_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-InfiniteLayout_Example/Pods-InfiniteLayout_Example.release.xcconfig"; sourceTree = "<group>"; };
C50F79B0DFFDE95D322480B2 /* Pods_InfiniteLayout_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_InfiniteLayout_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D403973E1FEBFA9D006C41D2 /* Cell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cell.swift; sourceTree = "<group>"; };
D4162A381FF502A900AC2572 /* CustomLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomLayout.swift; sourceTree = "<group>"; };
D43362CF1FF64B330040C679 /* BaseCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCollectionViewController.swift; sourceTree = "<group>"; };
D4B9816D1FFCCC900016C676 /* PickerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickerController.swift; sourceTree = "<group>"; };
EF577FD009F0E2F96F1CECC6 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
F900DDE615FA1056EB58998B /* Pods-InfiniteLayout_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InfiniteLayout_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InfiniteLayout_Tests/Pods-InfiniteLayout_Tests.debug.xcconfig"; sourceTree = "<group>"; };
FD6AC573B93C313B5BDFF3FE /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
@@ -96,8 +102,9 @@
isa = PBXGroup;
children = (
607FACD51AFB9204008FA782 /* AppDelegate.swift */,
607FACD71AFB9204008FA782 /* ViewController.swift */,
D403973E1FEBFA9D006C41D2 /* Cell.swift */,
D43362D31FF64B9E0040C679 /* Base */,
D43362CC1FF64AD30040C679 /* Custom */,
D4B9816C1FFCCC5B0016C676 /* Picker */,
607FACD91AFB9204008FA782 /* Main.storyboard */,
607FACDC1AFB9204008FA782 /* Images.xcassets */,
607FACDE1AFB9204008FA782 /* LaunchScreen.xib */,
@@ -151,6 +158,32 @@
name = Frameworks;
sourceTree = "<group>";
};
D43362CC1FF64AD30040C679 /* Custom */ = {
isa = PBXGroup;
children = (
607FACD71AFB9204008FA782 /* CustomViewController.swift */,
D4162A381FF502A900AC2572 /* CustomLayout.swift */,
);
name = Custom;
sourceTree = "<group>";
};
D43362D31FF64B9E0040C679 /* Base */ = {
isa = PBXGroup;
children = (
D403973E1FEBFA9D006C41D2 /* Cell.swift */,
D43362CF1FF64B330040C679 /* BaseCollectionViewController.swift */,
);
name = Base;
sourceTree = "<group>";
};
D4B9816C1FFCCC5B0016C676 /* Picker */ = {
isa = PBXGroup;
children = (
D4B9816D1FFCCC900016C676 /* PickerController.swift */,
);
name = Picker;
sourceTree = "<group>";
};
E938139B99B9D91C14707C07 /* Pods */ = {
isa = PBXGroup;
children = (
@@ -291,10 +324,12 @@
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-InfiniteLayout_Example/Pods-InfiniteLayout_Example-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/CocoaProxy/CocoaProxy.framework",
"${BUILT_PRODUCTS_DIR}/InfiniteLayout/InfiniteLayout.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CocoaProxy.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/InfiniteLayout.framework",
);
runOnlyForDeploymentPostprocessing = 0;
@@ -375,9 +410,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
607FACD81AFB9204008FA782 /* ViewController.swift in Sources */,
607FACD81AFB9204008FA782 /* CustomViewController.swift in Sources */,
607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */,
D4162A391FF502A900AC2572 /* CustomLayout.swift in Sources */,
D4B9816E1FFCCC900016C676 /* PickerController.swift in Sources */,
D403973F1FEBFA9D006C41D2 /* Cell.swift in Sources */,
D43362D11FF64B330040C679 /* BaseCollectionViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+348 -27
View File
@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="yGQ-hH-2v6">
<device id="retina5_9" orientation="portrait">
<device id="retina3_5" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
@@ -14,68 +16,387 @@
<objects>
<navigationController id="yGQ-hH-2v6" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="IdE-R7-9TG">
<rect key="frame" x="0.0" y="44" width="375" height="44"/>
<rect key="frame" x="0.0" y="20" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="sSL-wr-E9v" kind="relationship" relationship="rootViewController" id="6hU-n3-d5H"/>
<segue destination="pMz-7t-sA5" kind="relationship" relationship="rootViewController" id="AAf-BN-dLc"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="0uD-Xz-jjT" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-988" y="37"/>
<point key="canvasLocation" x="-1644" y="61"/>
</scene>
<!--View Controller-->
<scene sceneID="Tsa-GF-Rqw">
<!--InfiniteLayout-->
<scene sceneID="fMt-PB-wyT">
<objects>
<collectionViewController id="sSL-wr-E9v" customClass="ViewController" customModule="InfiniteLayout_Example" customModuleProvider="target" sceneMemberID="viewController">
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" id="BuB-JB-b15" customClass="InfiniteCollectionView" customModule="InfiniteLayout">
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
<tableViewController id="pMz-7t-sA5" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="YNN-Jo-hL3">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="Tcc-xt-sXE">
<size key="itemSize" width="150" height="100"/>
<sections>
<tableViewSection id="wLh-Qy-wV4">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="VSq-Pr-6ay" style="IBUITableViewCellStyleDefault" id="Ave-Hr-Gmz">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Ave-Hr-Gmz" id="Fri-pG-UG3">
<rect key="frame" x="0.0" y="0.0" width="320" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Horizontal Layout" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="VSq-Pr-6ay">
<rect key="frame" x="16" y="0.0" width="288" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="CU7-Hg-6kG" kind="show" id="yzb-gl-6Xz"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="Efh-hp-Yw4" style="IBUITableViewCellStyleDefault" id="e4W-KK-bkI">
<rect key="frame" x="0.0" y="44" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="e4W-KK-bkI" id="WDz-rM-Z2L">
<rect key="frame" x="0.0" y="0.0" width="320" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Vertical Layout" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Efh-hp-Yw4">
<rect key="frame" x="16" y="0.0" width="288" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="9P2-Ud-D2M" kind="show" id="H8w-EO-laS"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="9We-VT-VYi" style="IBUITableViewCellStyleDefault" id="5Ku-tY-Gtv">
<rect key="frame" x="0.0" y="88" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="5Ku-tY-Gtv" id="M7f-Mo-aWc">
<rect key="frame" x="0.0" y="0.0" width="320" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Custom Layout" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="9We-VT-VYi">
<rect key="frame" x="16" y="0.0" width="288" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="ctO-Ld-yhL" kind="show" id="qss-AL-dgi"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="c9c-gc-NDL" style="IBUITableViewCellStyleDefault" id="7Dq-og-5lN">
<rect key="frame" x="0.0" y="132" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="7Dq-og-5lN" id="XGb-gg-zbn">
<rect key="frame" x="0.0" y="0.0" width="320" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Picker" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="c9c-gc-NDL">
<rect key="frame" x="16" y="0.0" width="288" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="nUW-3u-2O9" kind="show" id="SPm-WC-Yf4"/>
</connections>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
<connections>
<outlet property="dataSource" destination="pMz-7t-sA5" id="OC9-mx-dmD"/>
<outlet property="delegate" destination="pMz-7t-sA5" id="nwI-aQ-G7d"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="InfiniteLayout" id="6dR-xO-LQz"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="N5O-nh-h2i" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-770" y="61"/>
</scene>
<!--Custom Layout-->
<scene sceneID="Nwi-KZ-nuX">
<objects>
<viewController id="ctO-Ld-yhL" customClass="CustomViewController" customModule="InfiniteLayout_Example" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="pkO-J5-FlB"/>
<viewControllerLayoutGuide type="bottom" id="q9H-d0-4cm"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="C5p-bu-Djh">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="enX-ef-ELn" customClass="InfiniteCollectionView" customModule="InfiniteLayout">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewLayout key="collectionViewLayout" id="ZR7-Jn-ewG" customClass="CustomLayout" customModule="InfiniteLayout_Example" customModuleProvider="target"/>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="w1M-Ws-9fK" customClass="Cell" customModule="InfiniteLayout_Example" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gVT-2b-OS8" customClass="CellView" customModule="InfiniteLayout_Example" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="styleIndex">
<integer key="value" value="2"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
</subviews>
</view>
<constraints>
<constraint firstItem="gVT-2b-OS8" firstAttribute="top" secondItem="w1M-Ws-9fK" secondAttribute="top" id="9qG-Sx-gVG"/>
<constraint firstAttribute="bottom" secondItem="gVT-2b-OS8" secondAttribute="bottom" id="BOm-tM-pkP"/>
<constraint firstAttribute="trailing" secondItem="gVT-2b-OS8" secondAttribute="trailing" id="HC4-Mv-T4P"/>
<constraint firstItem="gVT-2b-OS8" firstAttribute="leading" secondItem="w1M-Ws-9fK" secondAttribute="leading" id="jH9-f5-fxA"/>
</constraints>
<connections>
<outlet property="cellView" destination="gVT-2b-OS8" id="Em8-Ah-Jzb"/>
</connections>
</collectionViewCell>
</cells>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isItemPagingEnabled" value="YES"/>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="dataSource" destination="ctO-Ld-yhL" id="bXu-Jz-K7t"/>
<outlet property="delegate" destination="ctO-Ld-yhL" id="Vz4-5J-frZ"/>
</connections>
</collectionView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="enX-ef-ELn" firstAttribute="top" secondItem="C5p-bu-Djh" secondAttribute="top" id="2nB-Om-PsD"/>
<constraint firstAttribute="bottom" secondItem="enX-ef-ELn" secondAttribute="bottom" id="Tdv-eb-r3X"/>
<constraint firstAttribute="trailing" secondItem="enX-ef-ELn" secondAttribute="trailing" id="ZM0-nc-pUD"/>
<constraint firstItem="enX-ef-ELn" firstAttribute="leading" secondItem="C5p-bu-Djh" secondAttribute="leading" id="uX4-ox-gnL"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Custom Layout" id="hZl-1w-5Nq"/>
<connections>
<outlet property="infiniteCollectionView" destination="enX-ef-ELn" id="jKo-DT-4uH"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="4s9-AY-FII" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-770" y="802"/>
</scene>
<!--Infinite Delegate-->
<scene sceneID="HqS-9O-oG4">
<objects>
<viewController automaticallyAdjustsScrollViewInsets="NO" id="nUW-3u-2O9" customClass="PickerController" customModule="InfiniteLayout_Example" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="zFz-ZQ-lzW"/>
<viewControllerLayoutGuide type="bottom" id="ZuO-bs-QWL"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Vhd-CK-34X">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="Yg1-5Z-6FI" customClass="InfiniteCollectionView" customModule="InfiniteLayout">
<rect key="frame" x="0.0" y="288" width="320" height="192"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="1000" id="PTo-iT-zZX">
<size key="itemSize" width="200" height="150"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="10" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="7Np-kQ-f93" customClass="Cell" customModule="InfiniteLayout_Example" customModuleProvider="target">
<rect key="frame" x="0.0" y="21" width="200" height="150"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO">
<rect key="frame" x="0.0" y="0.0" width="200" height="150"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Uz9-xR-d0L" customClass="CellView" customModule="InfiniteLayout_Example" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="200" height="150"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="styleIndex">
<integer key="value" value="1"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
</subviews>
</view>
<constraints>
<constraint firstItem="Uz9-xR-d0L" firstAttribute="top" secondItem="7Np-kQ-f93" secondAttribute="top" id="2lt-hb-Zl9"/>
<constraint firstItem="Uz9-xR-d0L" firstAttribute="leading" secondItem="7Np-kQ-f93" secondAttribute="leading" id="Hj7-OH-iis"/>
<constraint firstAttribute="trailing" secondItem="Uz9-xR-d0L" secondAttribute="trailing" id="mr0-wj-ftP"/>
<constraint firstAttribute="bottom" secondItem="Uz9-xR-d0L" secondAttribute="bottom" id="t8H-tx-AHw"/>
</constraints>
<connections>
<outlet property="cellView" destination="Uz9-xR-d0L" id="Q84-nb-acR"/>
</connections>
</collectionViewCell>
</cells>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isItemPagingEnabled" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="velocityMultiplier">
<real key="value" value="1"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="dataSource" destination="nUW-3u-2O9" id="vHT-UO-3ny"/>
<outlet property="delegate" destination="nUW-3u-2O9" id="cXx-OK-csN"/>
<outlet property="infiniteDelegate" destination="nUW-3u-2O9" id="FQk-xA-mjb"/>
</connections>
</collectionView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="n2a-eR-E9T" customClass="CellView" customModule="InfiniteLayout_Example" customModuleProvider="target">
<rect key="frame" x="53.5" y="66.5" width="213" height="213"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="n2a-eR-E9T" firstAttribute="height" secondItem="Vhd-CK-34X" secondAttribute="width" multiplier="2:3" id="15l-Xa-cgF"/>
<constraint firstItem="n2a-eR-E9T" firstAttribute="centerY" secondItem="Yg1-5Z-6FI" secondAttribute="top" multiplier="0.6" id="831-T2-ANf"/>
<constraint firstItem="Yg1-5Z-6FI" firstAttribute="height" secondItem="Vhd-CK-34X" secondAttribute="height" multiplier="0.4" id="A7s-lr-k2k"/>
<constraint firstItem="ZuO-bs-QWL" firstAttribute="top" secondItem="Yg1-5Z-6FI" secondAttribute="bottom" id="GmZ-Db-ynH"/>
<constraint firstAttribute="trailing" secondItem="Yg1-5Z-6FI" secondAttribute="trailing" id="PSV-WU-ltt"/>
<constraint firstItem="Yg1-5Z-6FI" firstAttribute="leading" secondItem="Vhd-CK-34X" secondAttribute="leading" id="UQ7-m3-LKy"/>
<constraint firstItem="n2a-eR-E9T" firstAttribute="centerX" secondItem="Vhd-CK-34X" secondAttribute="centerX" id="hN7-qa-9iE"/>
<constraint firstItem="n2a-eR-E9T" firstAttribute="width" secondItem="Vhd-CK-34X" secondAttribute="width" multiplier="2:3" id="k1E-14-EKC"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Picker" id="Op4-F3-Cvs"/>
<connections>
<outlet property="infiniteCollectionView" destination="Yg1-5Z-6FI" id="dYW-hl-GxB"/>
<outlet property="selectedView" destination="n2a-eR-E9T" id="kE8-NA-C2Q"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="jlK-LR-KNy" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="22" y="802"/>
</scene>
<!--Horizontal Layout-->
<scene sceneID="0Xz-LA-moA">
<objects>
<collectionViewController id="CU7-Hg-6kG" customClass="BaseCollectionViewController" customModule="InfiniteLayout_Example" customModuleProvider="target" sceneMemberID="viewController">
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" id="Iuy-Ov-jLz" customClass="InfiniteCollectionView" customModule="InfiniteLayout">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="1000" id="i7U-Tf-kfd">
<size key="itemSize" width="250" height="150"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="10" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="Vf0-ro-DM5" customClass="Cell" customModule="InfiniteLayout_Example" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="150" height="100"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="BVQ-cb-bj4" customClass="Cell" customModule="InfiniteLayout_Example" customModuleProvider="target">
<rect key="frame" x="0.0" y="133" width="250" height="150"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO">
<rect key="frame" x="0.0" y="0.0" width="150" height="100"/>
<rect key="frame" x="0.0" y="0.0" width="250" height="150"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SWd-w1-K3N" customClass="CellView" customModule="InfiniteLayout_Example" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="150" height="100"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="1wM-ge-YKX" customClass="CellView" customModule="InfiniteLayout_Example" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="250" height="150"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
</subviews>
</view>
<constraints>
<constraint firstItem="SWd-w1-K3N" firstAttribute="leading" secondItem="Vf0-ro-DM5" secondAttribute="leading" id="HM6-Rd-74h"/>
<constraint firstItem="SWd-w1-K3N" firstAttribute="top" secondItem="Vf0-ro-DM5" secondAttribute="top" id="jJh-U5-WWC"/>
<constraint firstAttribute="bottom" secondItem="SWd-w1-K3N" secondAttribute="bottom" id="n3V-C9-rAP"/>
<constraint firstAttribute="trailing" secondItem="SWd-w1-K3N" secondAttribute="trailing" id="oPa-mO-RJ6"/>
<constraint firstAttribute="bottom" secondItem="1wM-ge-YKX" secondAttribute="bottom" id="44V-6k-Vxi"/>
<constraint firstAttribute="trailing" secondItem="1wM-ge-YKX" secondAttribute="trailing" id="BO0-dS-ek7"/>
<constraint firstItem="1wM-ge-YKX" firstAttribute="leading" secondItem="BVQ-cb-bj4" secondAttribute="leading" id="O2r-kl-QZo"/>
<constraint firstItem="1wM-ge-YKX" firstAttribute="top" secondItem="BVQ-cb-bj4" secondAttribute="top" id="kT9-T5-w19"/>
</constraints>
<connections>
<outlet property="cellView" destination="SWd-w1-K3N" id="2A6-17-L1b"/>
<outlet property="cellView" destination="1wM-ge-YKX" id="BFc-xc-0VL"/>
</connections>
</collectionViewCell>
</cells>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isItemPagingEnabled" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="velocityMultiplier">
<real key="value" value="1"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="dataSource" destination="sSL-wr-E9v" id="weE-ef-YRt"/>
<outlet property="delegate" destination="sSL-wr-E9v" id="hva-cg-vBg"/>
<outlet property="dataSource" destination="CU7-Hg-6kG" id="BOZ-dL-WLG"/>
<outlet property="delegate" destination="CU7-Hg-6kG" id="NKU-4F-wIF"/>
</connections>
</collectionView>
<navigationItem key="navigationItem" id="qS4-kF-4vO"/>
<navigationItem key="navigationItem" title="Horizontal Layout" id="AaD-SQ-gYu"/>
</collectionViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="bMF-CJ-xJ6" userLabel="First Responder" sceneMemberID="firstResponder"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="Dsp-JP-Q6i" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-68" y="36.945812807881772"/>
<point key="canvasLocation" x="22" y="-599"/>
</scene>
<!--Vertical Layout-->
<scene sceneID="ccn-9j-1sQ">
<objects>
<collectionViewController id="9P2-Ud-D2M" customClass="BaseCollectionViewController" customModule="InfiniteLayout_Example" customModuleProvider="target" sceneMemberID="viewController">
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" id="iW9-Tg-dTG" customClass="InfiniteCollectionView" customModule="InfiniteLayout">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="1000" id="t85-Nu-Mt1">
<size key="itemSize" width="150" height="100"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="10"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="OtA-Vt-ejC" customClass="Cell" customModule="InfiniteLayout_Example" customModuleProvider="target">
<rect key="frame" x="85" y="0.0" width="150" height="100"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO">
<rect key="frame" x="0.0" y="0.0" width="150" height="100"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fuL-Uj-Mda" customClass="CellView" customModule="InfiniteLayout_Example" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="150" height="100"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
</subviews>
</view>
<constraints>
<constraint firstItem="fuL-Uj-Mda" firstAttribute="leading" secondItem="OtA-Vt-ejC" secondAttribute="leading" id="KLH-6Z-vhB"/>
<constraint firstAttribute="trailing" secondItem="fuL-Uj-Mda" secondAttribute="trailing" id="bzB-oG-udJ"/>
<constraint firstAttribute="bottom" secondItem="fuL-Uj-Mda" secondAttribute="bottom" id="fgE-nQ-BGU"/>
<constraint firstItem="fuL-Uj-Mda" firstAttribute="top" secondItem="OtA-Vt-ejC" secondAttribute="top" id="t4I-qE-DtN"/>
</constraints>
<connections>
<outlet property="cellView" destination="fuL-Uj-Mda" id="AN4-RB-ul0"/>
</connections>
</collectionViewCell>
</cells>
<connections>
<outlet property="dataSource" destination="9P2-Ud-D2M" id="juO-P6-XzS"/>
<outlet property="delegate" destination="9P2-Ud-D2M" id="ns0-fe-DSq"/>
</connections>
</collectionView>
<navigationItem key="navigationItem" title="Vertical Layout" id="2E2-oh-ELb"/>
</collectionViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Lvb-qy-gZV" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="22" y="61"/>
</scene>
</scenes>
</document>
@@ -0,0 +1,25 @@
//
// BaseCollectionViewController.swift
// InfiniteLayout_Example
//
// Created by Arnaud Dorgans on 29/12/2017.
// Copyright © 2017 CocoaPods. All rights reserved.
//
import UIKit
import InfiniteLayout
class BaseCollectionViewController: InfiniteCollectionViewController {
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? Cell else {
fatalError()
}
cell.update(index: self.infiniteCollectionView!.indexPath(from: indexPath).row)
return cell
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
}
+32 -2
View File
@@ -17,12 +17,30 @@ class Cell: UICollectionViewCell {
}
}
enum CellStyle {
case circular
case `default`
static let all = [circular, `default`]
}
@IBDesignable class CellView: UIView {
let titleLabel = UILabel()
let colors = [#colorLiteral(red: 0.5254901961, green: 0.6901960784, blue: 0.9137254902, alpha: 1), #colorLiteral(red: 0.5254901961, green: 0.6196078431, blue: 0.9137254902, alpha: 1), #colorLiteral(red: 0.6078431373, green: 0.5254901961, blue: 0.9137254902, alpha: 1), #colorLiteral(red: 0.9137254902, green: 0.5254901961, blue: 0.8392156863, alpha: 1), #colorLiteral(red: 0.9137254902, green: 0.5254901961, blue: 0.6, alpha: 1), #colorLiteral(red: 0.9137254902, green: 0.6784313725, blue: 0.5254901961, alpha: 1), #colorLiteral(red: 0.9137254902, green: 0.9058823529, blue: 0.5254901961, alpha: 1), #colorLiteral(red: 0.5254901961, green: 0.9137254902, blue: 0.5921568627, alpha: 1), #colorLiteral(red: 0.5254901961, green: 0.8, blue: 0.9137254902, alpha: 1)]
@IBInspectable var styleIndex: Int {
get { return CellStyle.all.index(of: style)! }
set { style = CellStyle.all[newValue % CellStyle.all.count] }
}
var style: CellStyle = .default {
didSet {
updateStyle()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
sharedInit()
@@ -45,14 +63,26 @@ class Cell: UICollectionViewCell {
self.addSubview(titleLabel)
titleLabel.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
titleLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
self.layer.cornerRadius = 8
}
func update(index: Int) {
self.titleLabel.text = String(index + 1)
self.backgroundColor = colors[index % colors.count]
}
func updateStyle() {
switch style {
case .default:
self.layer.cornerRadius = 8
case .circular:
self.layer.cornerRadius = self.frame.height / 2
}
}
override func layoutSubviews() {
super.layoutSubviews()
updateStyle()
}
override func prepareForInterfaceBuilder() {
self.update(index: 0)
+33
View File
@@ -0,0 +1,33 @@
//
// CustomLayout.swift
// InfiniteLayout_Example
//
// Created by Arnaud Dorgans on 28/12/2017.
// Copyright © 2017 CocoaPods. All rights reserved.
//
import UIKit
import InfiniteLayout
class CustomLayout: InfiniteLayout {
let minimumScale: CGFloat = 0.75
let rangeRatio: CGFloat = 1
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect).flatMap {
self.copyLayoutAttributes(from: $0)
}
guard let visibleRect = self.visibleCollectionViewRect() else {
return attributes
}
let centeredOffset = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
for attributes in attributes ?? [] {
let diff = self.scrollDirection == .horizontal ? centeredOffset.x - attributes.center.x : centeredOffset.y - attributes.center.y
let scale = max(min(diff / (min(visibleRect.width, visibleRect.height) * rangeRatio), 1), -1)
attributes.transform = attributes.transform.translatedBy(x: abs(scale * (visibleRect.width / 2)), y: 0)
attributes.transform = attributes.transform.rotated(by: scale * (CGFloat.pi / 2))
}
return attributes
}
}
@@ -0,0 +1,51 @@
//
// CustomViewController.swift
// InfiniteLayout
//
// Created by Arnoymous on 12/20/2017.
// Copyright (c) 2017 Arnoymous. All rights reserved.
//
import UIKit
import InfiniteLayout
class CustomViewController: UIViewController {
@IBOutlet weak var infiniteCollectionView: InfiniteCollectionView!
}
extension CustomViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 14
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! Cell
cell.update(index: self.infiniteCollectionView!.indexPath(from: indexPath).row)
return cell
}
}
extension CustomViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 100, height: 100)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return collectionView.frame.height
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
}
}
-1
View File
@@ -33,7 +33,6 @@
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
</array>
</dict>
</plist>
@@ -0,0 +1,41 @@
//
// PickerController.swift
// InfiniteLayout_Example
//
// Created by Arnaud Dorgans on 03/01/2018.
// Copyright © 2018 CocoaPods. All rights reserved.
//
import UIKit
import InfiniteLayout
class PickerController: UIViewController {
@IBOutlet weak var selectedView: CellView!
@IBOutlet weak var infiniteCollectionView: InfiniteCollectionView!
}
extension PickerController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? Cell else {
fatalError()
}
cell.update(index: self.infiniteCollectionView.indexPath(from: indexPath).row)
return cell
}
}
extension PickerController: InfiniteCollectionViewDelegate {
func infiniteCollectionView(_ infiniteCollectionView: InfiniteCollectionView, didChangeCenteredIndexPath centeredIndexPath: IndexPath?) {
guard let indexPath = centeredIndexPath else {
return
}
self.selectedView.update(index: self.infiniteCollectionView.indexPath(from: indexPath).row)
}
}
@@ -1,55 +0,0 @@
//
// ViewController.swift
// InfiniteLayout
//
// Created by Arnoymous on 12/20/2017.
// Copyright (c) 2017 Arnoymous. All rights reserved.
//
import UIKit
import InfiniteLayout
class ViewController: InfiniteCollectionViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard let collectionView = self.collectionView else {
return
}
let cells = collectionView.indexPathsForVisibleItems.sorted()
for i in 0..<cells.count {
guard let cell = collectionView.cellForItem(at: cells[i]) else {
return
}
cell.alpha = 0
UIView.animate(withDuration: 0.3, delay: TimeInterval(i) * 0.05, options: [], animations: {
cell.alpha = 1
}, completion: nil)
}
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 14
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! Cell
cell.update(index: self.infiniteCollectionView!.indexPath(from: indexPath).row)
return cell
}
}
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height: CGFloat = 100
let width: CGFloat = height * 2
return CGSize(width: width, height: height)
}
}
+5 -2
View File
@@ -1,5 +1,7 @@
PODS:
- InfiniteLayout (0.1.0)
- CocoaProxy (0.1.1)
- InfiniteLayout (0.1.3):
- CocoaProxy (~> 0.1)
DEPENDENCIES:
- InfiniteLayout (from `../`)
@@ -9,7 +11,8 @@ EXTERNAL SOURCES:
:path: ../
SPEC CHECKSUMS:
InfiniteLayout: 82a21b8255623e2d72174f3082bef9e576140621
CocoaProxy: 35ab81e24325b33834cffe45a3d1fd48ca67ef3a
InfiniteLayout: 0ab39bf2a4d9ce5c473ebccfc0d3b7278de18ac9
PODFILE CHECKSUM: 3a658536624f41ec07c5a7a2c55407b9b8f48528
+4 -4
View File
@@ -8,8 +8,8 @@
Pod::Spec.new do |s|
s.name = 'InfiniteLayout'
s.version = '0.1.1'
s.summary = 'Vertical and Horizontal infinite scrolling for UICollectionView'
s.version = '0.1.6'
s.summary = 'Horizontal and Vertical infinite scrolling feature for UICollectionView'
# This description is used to generate tags and improve search results.
# * Think: What does it do? Why did you write it? What is the focus?
@@ -18,7 +18,7 @@ Pod::Spec.new do |s|
# * Finally, don't worry about the indent, CocoaPods strips it!
s.description = <<-DESC
Vertical and Horizontal infinite scrolling for UICollectionView with Paging and NSProxy delegate
Horizontal and Vertical infinite scrolling feature for UICollectionView with Paging and NSProxy delegate
DESC
s.homepage = 'https://github.com/Arnoymous/InfiniteLayout'
@@ -40,5 +40,5 @@ Vertical and Horizontal infinite scrolling for UICollectionView with Paging and
# s.public_header_files = 'Pod/Classes/**/*.h'
# s.frameworks = 'UIKit', 'MapKit'
# s.dependency 'AFNetworking', '~> 2.3'
s.dependency 'CocoaProxy', '~> 0.1'
end
@@ -7,15 +7,22 @@
import UIKit
@objc public protocol InfiniteCollectionViewDelegate {
@objc optional func infiniteCollectionView(_ infiniteCollectionView: InfiniteCollectionView, didChangeCenteredIndexPath centeredIndexPath: IndexPath?)
}
open class InfiniteCollectionView: UICollectionView {
lazy var delegateProxy = InfiniteCollectionViewDelegateProxy(self, exceptions: ["scrollViewDidScroll:",
"scrollViewWillEndDragging:withVelocity:targetContentOffset:"])
lazy var dataSourceProxy = InfiniteCollectionViewDataSourceProxy(self, exceptions: ["numberOfSectionsInCollectionView:",
"collectionView:numberOfItemsInSection:"])
lazy var delegateProxy = InfiniteCollectionViewDelegateProxy(collectionView: self)
lazy var dataSourceProxy = InfiniteCollectionViewDataSourceProxy(collectionView: self)
@IBInspectable var isItemPagingEnabled: Bool = false
@IBInspectable var velocityMultiplier: CGFloat = 500 {
@IBOutlet open var infiniteDelegate: InfiniteCollectionViewDelegate?
open var centeredIndexPath: IndexPath?
@IBInspectable open var isItemPagingEnabled: Bool = false
@IBInspectable open var velocityMultiplier: CGFloat = 500 {
didSet {
self.infiniteLayout.velocityMultiplier = velocityMultiplier
}
@@ -56,24 +63,24 @@ open class InfiniteCollectionView: UICollectionView {
return self.collectionViewLayout as? InfiniteLayout
}
private static func infiniteLayout(layout: UICollectionViewLayout) -> InfiniteLayout {
guard let infiniteLayout = layout as? InfiniteLayout else {
return InfiniteLayout(layout: layout)
}
return infiniteLayout
}
public override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: InfiniteLayout(layout: layout))
sharedInit()
super.init(frame: frame, collectionViewLayout: InfiniteCollectionView.infiniteLayout(layout: layout))
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let layout = self.collectionViewLayout
if !(layout is InfiniteLayout) {
self.collectionViewLayout = InfiniteLayout(layout: layout)
let infiniteLayout = InfiniteCollectionView.infiniteLayout(layout: self.collectionViewLayout)
if self.collectionViewLayout != infiniteLayout {
self.collectionViewLayout = infiniteLayout
}
sharedInit()
}
private func sharedInit() {
delegateProxy.collectionView = self
dataSourceProxy.collectionView = self
}
open override func layoutSubviews() {
@@ -94,6 +101,12 @@ extension InfiniteCollectionView: UICollectionViewDelegate {
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
delegateProxy.delegate?.scrollViewDidScroll?(scrollView)
self.loopCollectionViewIfNeeded()
let preferredVisibleIndexPath = infiniteLayout.preferredVisibleLayoutAttributes()?.indexPath
if self.centeredIndexPath != preferredVisibleIndexPath {
self.centeredIndexPath = preferredVisibleIndexPath
self.infiniteDelegate?.infiniteCollectionView?(self, didChangeCenteredIndexPath: preferredVisibleIndexPath)
}
}
// MARK: Paging
@@ -1,19 +0,0 @@
//
// InfiniteCollectionViewProxy.h
// InfiniteLayout
//
// Created by Arnaud Dorgans on 21/12/2017.
//
#import <Foundation/Foundation.h>
@interface _InfiniteCollectionViewProxy<T: id<NSObject>> : NSProxy <UICollectionViewDelegate, UICollectionViewDataSource>
-(nonnull instancetype)init:(nullable T)collectionView exceptions:(nonnull NSArray<NSString*>*)exceptions;
@property (nonatomic, weak, nullable) T collectionView;
@property (nonatomic, weak, nullable) T delegate;
@property (nonatomic, nonnull, retain) NSArray* exceptions;
@end
@@ -1,52 +0,0 @@
//
// InfiniteCollectionViewProxy.m
// InfiniteLayout
//
// Created by Arnaud Dorgans on 21/12/2017.
//
#import "InfiniteCollectionViewProxy.h"
@implementation _InfiniteCollectionViewProxy
-(instancetype)init:(nullable id)collectionView exceptions:(nonnull NSArray<NSString*>*)exceptions {
self.collectionView = collectionView;
self.exceptions = exceptions;
return self;
}
- (BOOL)respondsToSelector:(SEL)aSelector
{
return ([self.collectionView respondsToSelector:aSelector] || [self.delegate respondsToSelector:aSelector]);
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSObject *delegateForResonse = [self.delegate respondsToSelector:aSelector] ? self.delegate : self.collectionView;
NSMethodSignature *signature = [delegateForResonse respondsToSelector:aSelector] ? [delegateForResonse methodSignatureForSelector:aSelector] : nil;
return signature;
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
NSString *selectorName = NSStringFromSelector(invocation.selector);
NSArray<id<NSObject>> *delegates = @[self.delegate, self.collectionView];
if ([self.exceptions containsObject:selectorName]) {
delegates = [[delegates reverseObjectEnumerator] allObjects];
}
for (int i = 0; i < delegates.count; i++) {
if ([delegates[i] respondsToSelector:invocation.selector]) {
[self invokeInvocation:invocation onDelegate:delegates[i]];
return;
}
}
}
- (void)invokeInvocation:(NSInvocation *)invocation onDelegate:(id<NSObject>)delegate
{
if ([delegate respondsToSelector:invocation.selector]) {
[invocation invokeWithTarget:delegate];
}
}
@end
@@ -0,0 +1,85 @@
//
// Proxy.swift
// InfiniteLayout
//
// Created by Arnaud Dorgans on 20/12/2017.
//
import UIKit
import CocoaProxy
class InfiniteCollectionViewProxy<T: NSObjectProtocol>: CocoaProxy {
var collectionView: InfiniteCollectionView! {
get { return self.proxies.first as? InfiniteCollectionView }
set {
if !self.proxies.isEmpty {
self.proxies.removeFirst()
}
self.proxies.insert(newValue, at: 0)
}
}
var delegate: T? {
get {
guard self.proxies.count > 1 else {
return nil
}
return self.proxies.last as? T
} set {
while self.proxies.count > 1 {
self.proxies.removeLast()
}
guard let delegate = newValue else {
return
}
self.proxies.append(delegate)
}
}
override func proxies(for aSelector: Selector) -> [NSObjectProtocol] {
return super.proxies(for: aSelector).reversed()
}
init(collectionView: InfiniteCollectionView) {
super.init(proxies: [])
self.collectionView = collectionView
}
}
class InfiniteCollectionViewDelegateProxy: InfiniteCollectionViewProxy<UICollectionViewDelegate>, UICollectionViewDelegate {
override func proxies(for aSelector: Selector) -> [NSObjectProtocol] {
return super.proxies(for: aSelector)
.first { proxy in
guard !(aSelector == #selector(UIScrollViewDelegate.scrollViewDidScroll(_:)) ||
aSelector == #selector(UIScrollViewDelegate.scrollViewWillEndDragging(_:withVelocity:targetContentOffset:))) else {
return proxy is InfiniteCollectionView
}
return true
}.flatMap { [$0] } ?? []
}
}
class InfiniteCollectionViewDataSourceProxy: InfiniteCollectionViewProxy<UICollectionViewDataSource>, UICollectionViewDataSource {
override func proxies(for aSelector: Selector) -> [NSObjectProtocol] {
return super.proxies(for: aSelector)
.first { proxy in
guard !(aSelector == #selector(UICollectionViewDataSource.numberOfSections(in:)) ||
aSelector == #selector(UICollectionViewDataSource.collectionView(_:numberOfItemsInSection:))) else {
return proxy is InfiniteCollectionView
}
return true
}.flatMap { [$0] } ?? []
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.collectionView.collectionView(collectionView, numberOfItemsInSection: section)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
return self.delegate?.collectionView(collectionView, cellForItemAt: indexPath) ??
self.collectionView.collectionView(collectionView, cellForItemAt: indexPath)
}
}
+27 -11
View File
@@ -43,8 +43,13 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
override open func prepare() {
let collectionViewContentSize = super.collectionViewContentSize
self.contentSize = CGSize(width: collectionViewContentSize.width, height: collectionViewContentSize.height)
self.isEnabled = (scrollDirection == .horizontal ? self.contentSize.width : self.contentSize.height) >=
InfiniteLayout.minimumContentSize.width
self.isEnabled = {
guard let collectionView = self.collectionView, collectionView.bounds != .zero else {
return false
}
return (scrollDirection == .horizontal ? self.contentSize.width : self.contentSize.height) >=
InfiniteLayout.minimumContentSize.width
}()
super.prepare()
}
@@ -119,7 +124,7 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
}
private func layoutAttributes(from layoutAttributes: UICollectionViewLayoutAttributes, page: CGPoint) -> UICollectionViewLayoutAttributes! {
guard let attributes = layoutAttributes.copy() as? UICollectionViewLayoutAttributes else {
guard let attributes = self.copyLayoutAttributes(layoutAttributes) else {
return nil
}
attributes.frame = rect(from: attributes.frame, page: page)
@@ -145,7 +150,7 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
}
// MARK: Paging
func collectionViewRect() -> CGRect? {
public func collectionViewRect() -> CGRect? {
guard let collectionView = self.collectionView else {
return nil
}
@@ -162,7 +167,7 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
return visibleRect
}
func visibleCollectionViewRect() -> CGRect? {
public func visibleCollectionViewRect() -> CGRect? {
guard let collectionView = self.collectionView,
var collectionViewRect = self.collectionViewRect() else {
return nil
@@ -178,10 +183,10 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
}
return (self.layoutAttributesForElements(in: CGRect(origin: offset ?? collectionView.contentOffset, size: collectionView.frame.size)) ?? [])
.sorted(by: { lhs, rhs in
guard let lhs = self.centerredContentOffset(forRect: lhs.frame) else {
guard let lhs = self.centeredContentOffset(forRect: lhs.frame) else {
return false
}
guard let rhs = self.centerredContentOffset(forRect: rhs.frame) else {
guard let rhs = self.centeredContentOffset(forRect: rhs.frame) else {
return true
}
let value: (CGPoint)->CGFloat = {
@@ -202,14 +207,14 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
let targetDirection = direction(targetOffset ?? currentOffset)
return self.visibleLayoutAttributes(at: offset)
.first { attributes in
guard let offset = self.centerredContentOffset(forRect: attributes.frame) else {
guard let offset = self.centeredContentOffset(forRect: attributes.frame) else {
return false
}
return direction(offset) == targetDirection || velocity == 0
}
}
func centerredContentOffset(forRect rect: CGRect) -> CGPoint? {
func centeredContentOffset(forRect rect: CGRect) -> CGPoint? {
guard let collectionView = self.collectionView,
let collectionRect = self.collectionViewRect() else {
return nil
@@ -226,7 +231,7 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
y: self.scrollDirection == .vertical ? collectionView.contentOffset.y + velocity.y * velocityMultiplier : targetContentOffset.pointee.y)
guard let preferredAttributes = self.preferredVisibleLayoutAttributes(at: newTarget, velocity: velocity, targetOffset: targetContentOffset.pointee),
let offset = self.centerredContentOffset(forRect: preferredAttributes.frame) else {
let offset = self.centeredContentOffset(forRect: preferredAttributes.frame) else {
return
}
targetContentOffset.pointee = offset
@@ -237,7 +242,7 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
return
}
guard let preferredAttributes = self.preferredVisibleLayoutAttributes(),
let offset = self.centerredContentOffset(forRect: preferredAttributes.frame),
let offset = self.centeredContentOffset(forRect: preferredAttributes.frame),
collectionView.contentOffset != offset else {
return
}
@@ -245,4 +250,15 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
collectionView.contentOffset = offset
}
}
// MARK: Copy
public func copyLayoutAttributes(_ attributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes? {
return attributes.copy() as? UICollectionViewLayoutAttributes
}
public func copyLayoutAttributes(from array: [UICollectionViewLayoutAttributes]) -> [UICollectionViewLayoutAttributes] {
return array.map { self.copyLayoutAttributes($0) }
.filter { $0 != nil }
.map { $0! }
}
}
-16
View File
@@ -1,16 +0,0 @@
//
// Proxy.swift
// InfiniteLayout
//
// Created by Arnaud Dorgans on 20/12/2017.
//
import UIKit
class InfiniteCollectionViewDelegateProxy: _InfiniteCollectionViewProxy<UICollectionViewDelegate> {
}
class InfiniteCollectionViewDataSourceProxy: _InfiniteCollectionViewProxy<UICollectionViewDataSource> {
}
+32 -3
View File
@@ -26,10 +26,10 @@ pod 'InfiniteLayout'
@IBOutlet weak var collectionView: InfiniteCollectionView!
```
InfiniteCollectionView don't need any other delegate or dataSource,
just use UICollectionViewDataSource and UICollectionViewDelegate as you'll use it in any other UICollectionView.
InfiniteCollectionView doesn't need any other delegate or dataSource,
just use UICollectionViewDataSource and UICollectionViewDelegate in the same way as you'll use it in any other UICollectionView.
InfiniteLayout provide 3 class for infinite scrolling:
InfiniteLayout provides 3 classes for infinite scrolling:
**InfiniteLayout**: an UICollectionViewFlowLayout
@@ -37,6 +37,35 @@ InfiniteLayout provide 3 class for infinite scrolling:
**InfiniteCollectionViewController**: an UICollectionViewController with InfiniteCollectionView
### IndexPath
InfiniteCollectionView may create fake indexPath,
To get the real indexPath call
```swift
func indexPath(from infiniteIndexPath: IndexPath) -> IndexPath
```
To get the real section call
```swift
func section(from infiniteSection: Int) -> Int
```
### Paging
InfiniteCollectionView provide a paging functionality, you can enable it by setting the **isItemPagingEnabled** flag to **true**,
When the **isItemPagingEnabled** flag is enabled you can adjust the deceleration rate by setting the **velocityMultiplier**, the more the value is high, the more the deceleration is long
### Picker
InfiniteCollectionView provide an **infiniteDelegate** protocol used to get the centered IndexPath, usefull if you want to use an InfiniteCollectionView like a Picker.
```swift
func infiniteCollectionView(_ infiniteCollectionView: InfiniteCollectionView, didChangeCenteredIndexPath centeredIndexPath: IndexPath?)
```
## Author