Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions Example/Example.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
935BD6E51CE26F0B00E5FDF7 /* Pattern1ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 935BD6DE1CE26F0B00E5FDF7 /* Pattern1ViewController.swift */; };
935BD6E61CE26F0B00E5FDF7 /* Pattern2.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 935BD6DF1CE26F0B00E5FDF7 /* Pattern2.storyboard */; };
935BD6E71CE26F0B00E5FDF7 /* Pattern2ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 935BD6E01CE26F0B00E5FDF7 /* Pattern2ViewController.swift */; };
A16472372051129D00A6D53D /* Pattern3ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A16472362051129D00A6D53D /* Pattern3ViewController.swift */; };
A164723B205117A800A6D53D /* Pattern3.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A164723A205117A800A6D53D /* Pattern3.storyboard */; };
EDA05AD81D92901C00F7C2C5 /* InfiniteCollectionView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDA05AD71D92901900F7C2C5 /* InfiniteCollectionView.framework */; };
EDA05AD91D92901C00F7C2C5 /* InfiniteCollectionView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EDA05AD71D92901900F7C2C5 /* InfiniteCollectionView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
Expand All @@ -34,7 +36,7 @@
isa = PBXContainerItemProxy;
containerPortal = EDA05AD21D92901900F7C2C5 /* InfiniteCollectionView.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 935BD70C1CE26F8E00E5FDF7;
remoteGlobalIDString = OBJ_17;
remoteInfo = InfiniteCollectionView;
};
/* End PBXContainerItemProxy section */
Expand Down Expand Up @@ -67,6 +69,8 @@
935BD6DE1CE26F0B00E5FDF7 /* Pattern1ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Pattern1ViewController.swift; sourceTree = "<group>"; };
935BD6DF1CE26F0B00E5FDF7 /* Pattern2.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Pattern2.storyboard; sourceTree = "<group>"; };
935BD6E01CE26F0B00E5FDF7 /* Pattern2ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Pattern2ViewController.swift; sourceTree = "<group>"; };
A16472362051129D00A6D53D /* Pattern3ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pattern3ViewController.swift; sourceTree = "<group>"; };
A164723A205117A800A6D53D /* Pattern3.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Pattern3.storyboard; sourceTree = "<group>"; };
EDA05AD21D92901900F7C2C5 /* InfiniteCollectionView.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = InfiniteCollectionView.xcodeproj; path = ../InfiniteCollectionView.xcodeproj; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -104,6 +108,7 @@
children = (
ED510E6D1DDD513200470C8B /* Pattern1 */,
ED510E6E1DDD513F00470C8B /* Pattern2 */,
A16472332051126300A6D53D /* Pattern3 */,
935BD6C81CE26EB600E5FDF7 /* AppDelegate.swift */,
935BD6CF1CE26EB600E5FDF7 /* Assets.xcassets */,
935BD6DA1CE26F0B00E5FDF7 /* ImageCollectionViewCell.swift */,
Expand All @@ -116,6 +121,15 @@
path = Example;
sourceTree = "<group>";
};
A16472332051126300A6D53D /* Pattern3 */ = {
isa = PBXGroup;
children = (
A164723A205117A800A6D53D /* Pattern3.storyboard */,
A16472362051129D00A6D53D /* Pattern3ViewController.swift */,
);
name = Pattern3;
sourceTree = "<group>";
};
ED510E6D1DDD513200470C8B /* Pattern1 */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -227,6 +241,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A164723B205117A800A6D53D /* Pattern3.storyboard in Resources */,
935BD6D01CE26EB600E5FDF7 /* Assets.xcassets in Resources */,
935BD6E21CE26F0B00E5FDF7 /* ImageCollectionViewCell.xib in Resources */,
935BD6D31CE26EB600E5FDF7 /* LaunchScreen.storyboard in Resources */,
Expand All @@ -246,6 +261,7 @@
935BD6C91CE26EB600E5FDF7 /* AppDelegate.swift in Sources */,
935BD6E11CE26F0B00E5FDF7 /* ImageCollectionViewCell.swift in Sources */,
935BD6E31CE26F0B00E5FDF7 /* MainViewController.swift in Sources */,
A16472372051129D00A6D53D /* Pattern3ViewController.swift in Sources */,
935BD6E51CE26F0B00E5FDF7 /* Pattern1ViewController.swift in Sources */,
935BD6E71CE26F0B00E5FDF7 /* Pattern2ViewController.swift in Sources */,
);
Expand Down Expand Up @@ -379,7 +395,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = io.github.hryk224.Example;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 4.0;
};
name = Debug;
};
Expand All @@ -393,7 +409,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = io.github.hryk224.Example;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 4.0;
};
name = Release;
};
Expand Down
7 changes: 6 additions & 1 deletion Example/Example/MainViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ final class MainViewController: UIViewController {
enum Pattern: Int, CustomStringConvertible {
case pattern1
case pattern2
static var count: Int { return 2 }
case pattern3
static var count: Int { return 3 }
var description: String {
switch self {
case .pattern1: return "pattern1"
case .pattern2: return "pattern2"
case .pattern3: return "pattern3"
}
}
}
Expand Down Expand Up @@ -65,6 +67,9 @@ extension MainViewController: UITableViewDelegate, UITableViewDataSource {
case .pattern2:
let controller = Pattern2ViewController.createFromStoryboard()
navigationController?.pushViewController(controller, animated: true)
case .pattern3:
let controller = Pattern3ViewController.createFromStoryboard()
navigationController?.pushViewController(controller, animated: true)
}
}
}
2 changes: 1 addition & 1 deletion Example/Example/Pattern1ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ final class Pattern1ViewController: UIViewController {
let storyboard = UIStoryboard(name: "Pattern1", bundle: nil)
return storyboard.instantiateInitialViewController() as! Pattern1ViewController
}
func rotate(_ notification: Notification) {
@objc func rotate(_ notification: Notification) {
layout.itemSize = UIScreen.main.bounds.size
layout.invalidateLayout()
collectionView.rotate(notification)
Expand Down
4 changes: 2 additions & 2 deletions Example/Example/Pattern2ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ final class InfiniteTableViewCell: UITableViewCell {
pageControl.numberOfPages = 4
}
}
func rotate(_ notification: Notification) {
@objc func rotate(_ notification: Notification) {
let size = CGSize(width: UIScreen.main.bounds.width, height: 239)
layout.itemSize = size
layout.invalidateLayout()
Expand Down Expand Up @@ -137,7 +137,7 @@ extension Infinite2TableViewCell: InfiniteCollectionViewDataSource, InfiniteColl
func infiniteCollectionView(_ collectionView: UICollectionView, didSelectItemAt usableIndexPath: IndexPath) {
print("didSelectItemAt: \(usableIndexPath.item)")
}
func rotate(_ notification: Notification) {
@objc func rotate(_ notification: Notification) {
collectionView.collectionViewLayout.invalidateLayout()
collectionView.rotate(notification)
collectionView.layoutIfNeeded()
Expand Down
54 changes: 54 additions & 0 deletions Example/Example/Pattern3.storyboard
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?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="jtB-7l-rQl">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Pattern3 View Controller-->
<scene sceneID="w99-5n-3Mx">
<objects>
<viewController automaticallyAdjustsScrollViewInsets="NO" id="jtB-7l-rQl" customClass="Pattern3ViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Vix-Nr-Wbb"/>
<viewControllerLayoutGuide type="bottom" id="rTP-xN-QW3"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="fk8-nc-mgC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="Lwf-cA-VEr" customClass="InfiniteCollectionView" customModule="InfiniteCollectionView">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="9XM-Ng-ou9">
<size key="itemSize" width="600" height="600"/>
<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"/>
</collectionViewFlowLayout>
<cells/>
</collectionView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="Lwf-cA-VEr" firstAttribute="leading" secondItem="fk8-nc-mgC" secondAttribute="leading" id="NFN-BY-c0F"/>
<constraint firstItem="rTP-xN-QW3" firstAttribute="top" secondItem="Lwf-cA-VEr" secondAttribute="bottom" id="Rm1-Pt-2ET"/>
<constraint firstItem="Lwf-cA-VEr" firstAttribute="top" secondItem="fk8-nc-mgC" secondAttribute="top" id="mQv-aQ-Qp8"/>
<constraint firstAttribute="trailing" secondItem="Lwf-cA-VEr" secondAttribute="trailing" id="o9s-cD-XIp"/>
</constraints>
</view>
<connections>
<outlet property="collectionView" destination="Lwf-cA-VEr" id="Tfg-hy-FJX"/>
<outlet property="layout" destination="9XM-Ng-ou9" id="rvd-rt-iwV"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="6qE-8b-tDF" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-468" y="96"/>
</scene>
</scenes>
</document>
63 changes: 63 additions & 0 deletions Example/Example/Pattern3ViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// Pattern3ViewController.swift
// Example
//
// Created by iamchiwon on 2018. 3. 8..
// Copyright © 2018년 hiroyuki yoshida. All rights reserved.
//

import UIKit
import InfiniteCollectionView

final class Pattern3ViewController: UIViewController {
var itemsCount: Int = 5
@IBOutlet weak var collectionView: InfiniteCollectionView! {
didSet {
collectionView.infiniteDataSource = self
collectionView.infiniteDelegate = self
collectionView.register(ImageCollectionViewCell.nib, forCellWithReuseIdentifier: ImageCollectionViewCell.identifier)
}
}
@IBOutlet weak var layout: UICollectionViewFlowLayout! {
didSet {
layout.itemSize = UIScreen.main.bounds.size
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
NotificationCenter.default.addObserver(self, selector: #selector(Pattern1ViewController.rotate(_:)), name: .UIDeviceOrientationDidChange, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)
}
static func createFromStoryboard() -> Pattern3ViewController {
let storyboard = UIStoryboard(name: "Pattern3", bundle: nil)
return storyboard.instantiateInitialViewController() as! Pattern3ViewController
}
@objc func rotate(_ notification: Notification) {
layout.itemSize = UIScreen.main.bounds.size
layout.invalidateLayout()
collectionView.rotate(notification)
collectionView.layoutIfNeeded()
collectionView.setNeedsLayout()
}
}

// MARK: - InfiniteCollectionViewDataSource, InfiniteCollectionViewDelegate
extension Pattern3ViewController: InfiniteCollectionViewDataSource, InfiniteCollectionViewDelegate {
func number(ofItems collectionView: UICollectionView) -> Int {
return itemsCount
}
func collectionView(_ collectionView: UICollectionView, dequeueForItemAt dequeueIndexPath: IndexPath, cellForItemAt usableIndexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ImageCollectionViewCell.identifier, for: dequeueIndexPath) as! ImageCollectionViewCell
cell.configure(indexPath: usableIndexPath)
return cell
}
func infiniteCollectionView(_ collectionView: UICollectionView, didSelectItemAt usableIndexPath: IndexPath) {
print("didSelectItemAt: \(usableIndexPath.item)")
}
func scrollView(_ scrollView: UIScrollView, pageIndex: Int) {
print("scrollView: \(pageIndex)")
}
}

2 changes: 2 additions & 0 deletions InfiniteCollectionView.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
PRODUCT_BUNDLE_IDENTIFIER = InfiniteCollectionView;
PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SWIFT_VERSION = 4.0;
TARGET_NAME = InfiniteCollectionView;
};
name = Debug;
Expand All @@ -155,6 +156,7 @@
PRODUCT_BUNDLE_IDENTIFIER = InfiniteCollectionView;
PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SWIFT_VERSION = 4.0;
TARGET_NAME = InfiniteCollectionView;
};
name = Release;
Expand Down
25 changes: 24 additions & 1 deletion Sources/InfiniteCollectionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ open class InfiniteCollectionView: UICollectionView {
deinit {
NotificationCenter.default.removeObserver(self, name: .UIDeviceOrientationDidChange, object: nil)
}
open func rotate(_ notification: Notification) {
@objc open func rotate(_ notification: Notification) {
setContentOffset(CGPoint(x: CGFloat(pageIndex + indexOffset) * itemWidth, y: contentOffset.y), animated: false)
}
open override func selectItem(at indexPath: IndexPath?, animated: Bool, scrollPosition: UICollectionViewScrollPosition) {
Expand Down Expand Up @@ -76,10 +76,18 @@ private extension InfiniteCollectionView {
guard let layout = collectionViewLayout as? UICollectionViewFlowLayout else { return 0 }
return layout.itemSize.width + layout.minimumInteritemSpacing
}
var itemHeight: CGFloat {
guard let layout = collectionViewLayout as? UICollectionViewFlowLayout else { return 0 }
return layout.itemSize.height + layout.minimumLineSpacing
}
var totalContentWidth: CGFloat {
let numberOfCells: CGFloat = CGFloat(infiniteDataSource?.number(ofItems: self) ?? 0)
return numberOfCells * itemWidth
}
var totalContentHeight: CGFloat {
let numberOfCells: CGFloat = CGFloat(infiniteDataSource?.number(ofItems: self) ?? 0)
return numberOfCells * itemHeight
}
func configure() {
delegate = self
dataSource = self
Expand All @@ -103,6 +111,21 @@ private extension InfiniteCollectionView {
indexOffset += offset
reloadData()
}
let centerY = (scrollView.contentSize.height - bounds.height) / 2
let distFromCenterY = centerY - currentOffset.y
if fabs(distFromCenterY) > (totalContentHeight / 4) {
let cellcount = distFromCenterY / itemHeight
let shiftCells = Int((cellcount > 0) ? floor(cellcount) : ceil(cellcount))
let offsetCorrection = (abs(cellcount).truncatingRemainder(dividingBy: 1)) * itemHeight
if centerY > contentOffset.y {
contentOffset = CGPoint(x: currentOffset.x, y: centerY - offsetCorrection)
} else {
contentOffset = CGPoint(x: currentOffset.x, y: centerY + offsetCorrection)
}
let offset = correctedIndex(shiftCells)
indexOffset += offset
reloadData()
}
let centerPoint = CGPoint(x: scrollView.frame.size.width / 2 + scrollView.contentOffset.x, y: scrollView.frame.size.height / 2 + scrollView.contentOffset.y)
guard let indexPath = indexPathForItem(at: centerPoint) else { return }
pageIndex = correctedIndex(indexPath.item - indexOffset)
Expand Down