Compare commits

...

25 Commits

Author SHA1 Message Date
Arnaud Dorgans 227269190f Merge pull request #13 from arnauddorgans/release/0.4.2
0.4.2
2019-09-05 18:14:46 +02:00
Arnaud Dorgans 38f6b056f1 Update README.md 2019-09-05 18:13:40 +02:00
Arnaud Dorgans 90a0ce56da release(0.4.2) @dlbuckley pr, Swift Package Manager 2019-09-05 18:02:11 +02:00
Arnaud Dorgans 0e9d75b59d Update README.md 2019-09-05 16:42:16 +02:00
Arnaud Dorgans da9c8b1372 Merge pull request #12 from dlbuckley/feature/add_willChangeCenteredIndexPath
Added willChangeCenteredIndexPath method to InfiniteCollectionViewDelegate protocol
2019-09-05 16:40:21 +02:00
Dale Buckley 83960eb567 rx fix 2019-09-05 12:15:27 +01:00
Dale Buckley cae11d5404 fixed a typo 2019-09-05 11:57:12 +01:00
Dale Buckley ab7324dc5b refactored based on code review comments by @arnauddorgans 2019-09-05 11:53:15 +01:00
Dale Buckley 8cd7e843af Added willChangeCenteredIndexPath method to InfiniteCollectionViewDelegate protocol 2019-08-29 15:08:01 +01:00
Arnaud Dorgans 519d724e17 Merge pull request #9 from lm2343635/master
RxSwift 5 compatible.
2019-05-22 09:29:53 +02:00
Meng Li d80114e454 Fix the errors. 2019-05-22 12:15:21 +09:00
Meng Li 1d4c698ab0 Update to RxSwift 5. 2019-05-22 12:11:52 +09:00
Arnaud Dorgans 0ebf480310 Merge pull request #8 from lm2343635/master
Swift 5.0 and Xcode 10.2.
2019-04-13 10:43:51 +02:00
Meng Li b178f69898 Update build script. 2019-04-09 15:20:18 +09:00
Meng Li 62782d83f9 Update .travis.yml 2019-04-09 14:49:44 +09:00
Meng Li b3038a90ec Update podspec. 2019-04-09 14:21:00 +09:00
Meng Li 03ba583c49 Swift 5.0 and Xcode 10.2. 2019-04-09 14:19:36 +09:00
Arnaud Dorgans f29e4b0716 travis fix 2019-03-20 14:15:49 +01:00
Arnaud Dorgans 41ce466ae3 bump swift version to 4.2, fix delegate proxy 2019-03-20 11:24:38 +01:00
Arnaud Dorgans c3688a9e1d fix isEnabled 2018-10-24 22:27:38 +02:00
Arnaud Dorgans 512885a166 bump & add public isEnabled property 2018-10-24 22:07:54 +02:00
Arnaud Dorgans 8fad95711e Update README.md 2018-08-29 18:17:52 +02:00
Arnaud Dorgans d6e792e3ec Update README.md 2018-08-29 18:15:39 +02:00
Arnaud Dorgans fcea3c29e7 bump 2018-08-12 14:58:45 +02:00
Arnaud Dorgans 7eb29bd82a fix scroll to index 2018-08-12 14:58:27 +02:00
26 changed files with 296 additions and 89 deletions
-1
View File
@@ -1 +0,0 @@
4.0
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
+7 -8
View File
@@ -2,13 +2,12 @@
# * http://www.objc.io/issue-6/travis-ci.html
# * https://github.com/supermarin/xcpretty#usage
osx_image: xcode7.3
language: objective-c
# cache: cocoapods
# podfile: Example/Podfile
# before_install:
# - gem install cocoapods # Since Travis is not always on latest version
# - pod install --project-directory=Example
osx_image: xcode10.2
language: swift
before_install:
- gem install cocoapods # Since Travis is not always on latest version
- pod repo update
- pod install --project-directory=Example
script:
- set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/InfiniteLayout.xcworkspace -scheme InfiniteLayout-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty
- set -o pipefail && xcodebuild -workspace Example/InfiniteLayout.xcworkspace -scheme InfiniteLayout-Example -sdk iphonesimulator build CODE_SIGNING_REQUIRED=NO | xcpretty -c
- pod lib lint
@@ -262,18 +262,18 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0830;
LastUpgradeCheck = 0830;
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = CocoaPods;
TargetAttributes = {
607FACCF1AFB9204008FA782 = {
CreatedOnToolsVersion = 6.3.1;
DevelopmentTeam = CPE39ZT2AY;
LastSwiftMigration = 0900;
LastSwiftMigration = 1020;
};
607FACE41AFB9204008FA782 = {
CreatedOnToolsVersion = 6.3.1;
DevelopmentTeam = CPE39ZT2AY;
LastSwiftMigration = 0900;
LastSwiftMigration = 1020;
TestTargetID = 607FACCF1AFB9204008FA782;
};
};
@@ -283,6 +283,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
Base,
);
@@ -324,12 +325,13 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-InfiniteLayout_Example/Pods-InfiniteLayout_Example-frameworks.sh",
"${PODS_ROOT}/Target Support Files/Pods-InfiniteLayout_Example/Pods-InfiniteLayout_Example-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/CocoaProxy/CocoaProxy.framework",
"${BUILT_PRODUCTS_DIR}/Differentiator/Differentiator.framework",
"${BUILT_PRODUCTS_DIR}/InfiniteLayout/InfiniteLayout.framework",
"${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework",
"${BUILT_PRODUCTS_DIR}/RxDataSources/RxDataSources.framework",
"${BUILT_PRODUCTS_DIR}/RxRelay/RxRelay.framework",
"${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework",
);
name = "[CP] Embed Pods Frameworks";
@@ -339,11 +341,12 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/InfiniteLayout.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxDataSources.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxRelay.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InfiniteLayout_Example/Pods-InfiniteLayout_Example-frameworks.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-InfiniteLayout_Example/Pods-InfiniteLayout_Example-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
BB5E5FB53E7C451064DBC9A2 /* [CP] Check Pods Manifest.lock */ = {
@@ -441,6 +444,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
@@ -449,12 +453,14 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@@ -487,6 +493,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
@@ -494,6 +501,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
@@ -502,12 +510,14 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@@ -532,6 +542,7 @@
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 5.0;
VALIDATE_PRODUCT = YES;
};
name = Release;
@@ -547,8 +558,7 @@
MODULE_NAME = ExampleApp;
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
};
name = Debug;
@@ -564,8 +574,7 @@
MODULE_NAME = ExampleApp;
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
};
name = Release;
@@ -587,8 +596,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
@@ -605,8 +613,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 5.0;
};
name = Release;
};
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0900"
LastUpgradeVersion = "1020"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -40,7 +40,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
@@ -70,7 +69,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
+1 -1
View File
@@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
+1 -1
View File
@@ -31,7 +31,7 @@ enum CellStyle {
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)! }
get { return CellStyle.all.firstIndex(of: style)! }
set { style = CellStyle.all[newValue % CellStyle.all.count] }
}
@@ -12,6 +12,7 @@ import InfiniteLayout
class CustomViewController: UIViewController {
@IBOutlet weak var infiniteCollectionView: InfiniteCollectionView!
}
extension CustomViewController: UICollectionViewDataSource {
+1 -2
View File
@@ -1,4 +1,5 @@
use_frameworks!
platform :ios, '10.0'
target 'InfiniteLayout_Example' do
pod 'InfiniteLayout', :path => '../'
@@ -6,7 +7,5 @@ target 'InfiniteLayout_Example' do
target 'InfiniteLayout_Tests' do
inherit! :search_paths
end
end
+27 -22
View File
@@ -1,24 +1,27 @@
PODS:
- CocoaProxy (0.1.1)
- Differentiator (3.0.2)
- InfiniteLayout (0.2.3.1):
- Differentiator (4.0.1)
- InfiniteLayout (0.4.1):
- CocoaProxy (~> 0)
- InfiniteLayout/Core (= 0.2.3.1)
- InfiniteLayout/Core (0.2.3.1):
- InfiniteLayout/Core (= 0.4.1)
- InfiniteLayout/Core (0.4.1):
- CocoaProxy (~> 0)
- InfiniteLayout/Rx (0.2.3.1):
- InfiniteLayout/Rx (0.4.1):
- CocoaProxy (~> 0)
- InfiniteLayout/Core (~> 0)
- RxCocoa (~> 4)
- RxDataSources (~> 3)
- RxSwift (~> 4)
- RxCocoa (4.1.0):
- RxSwift (~> 4.0)
- RxDataSources (3.0.2):
- Differentiator (~> 3.0)
- RxCocoa (~> 4.0)
- RxSwift (~> 4.0)
- RxSwift (4.1.0)
- RxCocoa (~> 5)
- RxDataSources (~> 4)
- RxSwift (~> 5)
- RxCocoa (5.0.0):
- RxRelay (~> 5)
- RxSwift (~> 5)
- RxDataSources (4.0.1):
- Differentiator (~> 4.0)
- RxCocoa (~> 5.0)
- RxSwift (~> 5.0)
- RxRelay (5.0.0):
- RxSwift (~> 5)
- RxSwift (5.0.0)
DEPENDENCIES:
- InfiniteLayout (from `../`)
@@ -30,6 +33,7 @@ SPEC REPOS:
- Differentiator
- RxCocoa
- RxDataSources
- RxRelay
- RxSwift
EXTERNAL SOURCES:
@@ -38,12 +42,13 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
CocoaProxy: 35ab81e24325b33834cffe45a3d1fd48ca67ef3a
Differentiator: a87be69eba49ec4ab460c7671143ee3a9eececfd
InfiniteLayout: 17bbab705aa4d941fa82a7e9b658c96d13ce91a3
RxCocoa: cc1fec49cdc8fabe645964de7c51c099a36c2aa8
RxDataSources: cb7c31e652a87ebb919da45f716bbb87b3765f6b
RxSwift: 4219941c1244c88002901bd87a69d3aea9ae71f0
Differentiator: 886080237d9f87f322641dedbc5be257061b0602
InfiniteLayout: 458eadbcb94afc3d777141990fbfe7a804a35609
RxCocoa: fcf32050ac00d801f34a7f71d5e8e7f23026dcd8
RxDataSources: efee07fa4de48477eca0a4611e6d11e2da9c1114
RxRelay: 4f7409406a51a55cd88483f21ed898c234d60f18
RxSwift: 8b0671caa829a763bbce7271095859121cbd895f
PODFILE CHECKSUM: 3501aeed91e62112dd38178a52f26b204b97c8c0
PODFILE CHECKSUM: 0dc7a9b37f9b7c5d5266beaab9e94861b80aa80f
COCOAPODS: 1.5.3
COCOAPODS: 1.6.1
+14 -10
View File
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = 'InfiniteLayout'
s.version = '0.2.3.2'
s.version = '0.4.2'
s.summary = 'Horizontal and Vertical infinite scrolling feature for UICollectionView with Paging, NSProxy delegate, Reactive extension'
# This description is used to generate tags and improve search results.
@@ -39,19 +39,23 @@ Horizontal and Vertical infinite scrolling feature for UICollectionView with Pag
# s.public_header_files = 'Pod/Classes/**/*.h'
# s.frameworks = 'UIKit', 'MapKit'
s.dependency 'CocoaProxy', '~> 0'
s.swift_versions = ['5.0', '5.1']
s.default_subspec = 'Core'
s.subspec 'Core' do |core|
core.source_files = 'InfiniteLayout/Classes/**/*'
core.source_files = 'Sources/InfiniteLayout/**/*'
core.dependency 'InfiniteLayout/CocoaProxy'
core.exclude_files = '**/*/SPMBridge.swift'
end
s.subspec 'CocoaProxy' do |core|
core.source_files = 'Sources/CocoaProxy/**/*'
end
s.subspec 'Rx' do |rx|
rx.dependency 'InfiniteLayout/Core', '~> 0'
rx.dependency 'RxSwift', '~> 4'
rx.dependency 'RxCocoa', '~> 4'
rx.dependency 'RxDataSources', '~> 3'
rx.source_files = 'InfiniteLayout/Rx/**/*'
rx.dependency 'InfiniteLayout/Core'
rx.dependency 'RxSwift', '~> 5'
rx.dependency 'RxCocoa', '~> 5'
rx.dependency 'RxDataSources', '~> 4'
rx.source_files = 'Sources/Rx/**/*'
end
end
View File
View File
+30
View File
@@ -0,0 +1,30 @@
// swift-tools-version:5.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "InfiniteLayout",
platforms: [.iOS(.v8), .tvOS(.v9)],
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "InfiniteLayout",
targets: ["InfiniteLayout"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "CocoaProxy",
dependencies: [],
publicHeadersPath: "./"),
.target(
name: "InfiniteLayout",
dependencies: ["CocoaProxy"])
]
)
+26 -4
View File
@@ -1,9 +1,10 @@
# InfiniteLayout
[![CI Status](http://img.shields.io/travis/arnauddorgans/InfiniteLayout.svg?style=flat)](https://travis-ci.org/arnauddorgans/InfiniteLayout)
[![Version](https://img.shields.io/cocoapods/v/InfiniteLayout.svg?style=flat)](http://cocoapods.org/pods/InfiniteLayout)
[![License](https://img.shields.io/cocoapods/l/InfiniteLayout.svg?style=flat)](http://cocoapods.org/pods/InfiniteLayout)
[![Platform](https://img.shields.io/cocoapods/p/InfiniteLayout.svg?style=flat)](http://cocoapods.org/pods/InfiniteLayout)
[![Version](https://img.shields.io/cocoapods/v/InfiniteLayout.svg?style=flat)](http://cocoapods.org/pods/InfiniteLayout)
[![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager)
<img src="https://github.com/arnauddorgans/InfiniteLayout/raw/master/horizontal.gif" width="250" height="540"><img src="https://github.com/arnauddorgans/InfiniteLayout/raw/master/vertical.gif" width="250" height="540"><img src="https://github.com/arnauddorgans/InfiniteLayout/raw/master/custom.gif" width="250" height="540">
@@ -12,10 +13,10 @@
To run the example project, clone the repo, and run `pod install` from the Example directory first.
## Requirements
## Installation
### [CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html)
InfiniteLayout is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your Podfile:
@@ -23,6 +24,27 @@ it, simply add the following line to your Podfile:
pod 'InfiniteLayout'
```
### [Swift Package Manager](https://github.com/apple/swift-package-manager)
Create a `Package.swift` file.
```swift
// swift-tools-version:5.0
import PackageDescription
let package = Package(
name: "InfiniteLayoutTestProject",
dependencies: [
.package(url: "https://github.com/arnauddorgans/InfiniteLayout.git", from: "0.4.2")
],
targets: [
.target(name: "InfiniteLayoutTestProject", dependencies: ["InfiniteLayout"])
]
)
```
## Usage
```swift
@@ -85,7 +107,7 @@ self.infiniteCollectionView.preferredCenteredIndexPath = nil // center the close
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?)
func infiniteCollectionView(_ infiniteCollectionView: InfiniteCollectionView, didChangeCenteredIndexPath from: IndexPath?, to: IndexPath?)
```
### Rx
+20
View File
@@ -0,0 +1,20 @@
//
// CocoaProxy.h
// CocoaProxy
//
// Created by Arnaud Dorgans on 27/12/2017.
//
#import <Foundation/Foundation.h>
@interface CocoaProxy : NSProxy
- (instancetype _Nonnull)init;
- (instancetype _Nonnull)initWithProxies:(nonnull NSArray<id<NSObject>>*)proxies;
- (NSArray<id<NSObject>> *_Nonnull)proxiesForSelector:(SEL _Nonnull )aSelector;
@property (nonatomic, strong) NSArray<id<NSObject>>* _Nonnull proxies;
@property (nonatomic, copy) BOOL (^ _Nullable proxyFilter)(id<NSObject> _Nonnull proxy, SEL _Nonnull selector);
@end
+80
View File
@@ -0,0 +1,80 @@
//
// CocoaProxy.m
// CocoaProxy
//
// Created by Arnaud Dorgans on 27/12/2017.
//
#import "CocoaProxy.h"
@interface CocoaProxy () { }
@property (nonatomic, strong) NSPointerArray *pointerArray;
@end
@implementation CocoaProxy
- (instancetype _Nonnull)initWithProxies:(nonnull NSArray<NSObject*>*)proxies {
[self setProxies: proxies];
return self;
}
- (instancetype _Nonnull)init {
return [self initWithProxies: @[]];
}
- (BOOL)respondsToSelector:(SEL)aSelector
{
return ([self methodSignatureForSelector: aSelector] != nil);
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
for (NSObject* proxy in [self proxiesForSelector: aSelector]) {
if ([proxy respondsToSelector: aSelector]) {
return [proxy methodSignatureForSelector: aSelector];
}
}
return nil;
}
- (NSArray<id<NSObject>> *_Nonnull)proxiesForSelector:(SEL _Nonnull )aSelector
{
if (self.proxyFilter) {
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
return self.proxyFilter(evaluatedObject, aSelector);
}];
return [self.proxies filteredArrayUsingPredicate: predicate];
}
return self.proxies;
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
for (NSObject* proxy in [self proxiesForSelector: invocation.selector]) {
[self invokeInvocation: invocation onProxy: proxy];
}
}
- (BOOL)invokeInvocation:(NSInvocation *)invocation onProxy:(id<NSObject>)proxy
{
if ([proxy respondsToSelector: invocation.selector]) {
[invocation invokeWithTarget: proxy];
return YES;
}
return NO;
}
- (void)setProxies:(NSArray<id<NSObject>> *)proxies {
self.pointerArray = [NSPointerArray weakObjectsPointerArray];
for (NSObject* proxy in proxies) {
[self.pointerArray addPointer: (void *)proxy];
}
}
- (NSArray<id<NSObject>> *)proxies {
return self.pointerArray.allObjects;
}
@end
@@ -8,8 +8,8 @@
import UIKit
@objc public protocol InfiniteCollectionViewDelegate {
@objc optional func infiniteCollectionView(_ infiniteCollectionView: InfiniteCollectionView, didChangeCenteredIndexPath centeredIndexPath: IndexPath?)
@objc optional func infiniteCollectionView(_ infiniteCollectionView: InfiniteCollectionView, didChangeCenteredIndexPath from: IndexPath?, to: IndexPath?)
}
open class InfiniteCollectionView: UICollectionView {
@@ -134,7 +134,7 @@ extension InfiniteCollectionView: UICollectionViewDataSource {
}
private var multiplier: Int {
return InfiniteDataSources.multiplier(estimatedItemSize: self.infiniteLayout.itemSize)
return InfiniteDataSources.multiplier(estimatedItemSize: self.infiniteLayout.itemSize, enabled: self.infiniteLayout.isEnabled)
}
public func section(from infiniteSection: Int) -> Int {
@@ -170,8 +170,9 @@ extension InfiniteCollectionView: UICollectionViewDelegate {
let preferredVisibleIndexPath = infiniteLayout.preferredVisibleLayoutAttributes()?.indexPath
if self.centeredIndexPath != preferredVisibleIndexPath {
let previousCenteredIndexPath = self.centeredIndexPath
self.centeredIndexPath = preferredVisibleIndexPath
self.infiniteDelegate?.infiniteCollectionView?(self, didChangeCenteredIndexPath: preferredVisibleIndexPath)
self.infiniteDelegate?.infiniteCollectionView?(self, didChangeCenteredIndexPath: previousCenteredIndexPath, to: self.centeredIndexPath)
}
}
@@ -202,5 +203,6 @@ extension InfiniteCollectionView: UICollectionViewDelegate {
if isItemPagingEnabled {
self.infiniteLayout.centerCollectionView(withVelocity: velocity, targetContentOffset: targetContentOffset)
}
self.delegateProxy.delegate?.scrollViewWillEndDragging?(scrollView, withVelocity: velocity, targetContentOffset: targetContentOffset)
}
}
@@ -6,7 +6,6 @@
//
import UIKit
import CocoaProxy
class InfiniteCollectionViewProxy<T: NSObjectProtocol>: CocoaProxy {
@@ -17,7 +17,10 @@ class InfiniteDataSources {
return IndexPath(item: infiniteIndexPath.item % numberOfItems, section: self.section(from: infiniteIndexPath.section, numberOfSections: numberOfSections))
}
static func multiplier(estimatedItemSize: CGSize) -> Int {
static func multiplier(estimatedItemSize: CGSize, enabled: Bool) -> Int {
guard enabled else {
return 1
}
let min = Swift.min(estimatedItemSize.width, estimatedItemSize.height)
let count = ceil(InfiniteLayout.minimumContentSize / min)
return Int(count)
@@ -15,7 +15,20 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
private var contentSize: CGSize = .zero
private (set) var isEnabled: Bool = false
private var hasValidLayout: Bool = false
@IBInspectable public var isEnabled: Bool = true {
didSet {
self.invalidateLayout()
}
}
public var currentPage: CGPoint {
guard let collectionView = self.collectionView else {
return .zero
}
return self.page(for: collectionView.contentOffset)
}
open override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
@@ -42,8 +55,8 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
override open func prepare() {
let collectionViewContentSize = super.collectionViewContentSize
self.contentSize = CGSize(width: collectionViewContentSize.width, height: collectionViewContentSize.height)
self.isEnabled = {
guard let collectionView = self.collectionView, collectionView.bounds != .zero else {
self.hasValidLayout = {
guard let collectionView = self.collectionView, collectionView.bounds != .zero, self.isEnabled else {
return false
}
return (scrollDirection == .horizontal ? self.contentSize.width : self.contentSize.height) >=
@@ -53,15 +66,22 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
}
override open var collectionViewContentSize: CGSize {
guard isEnabled else {
return super.collectionViewContentSize
guard hasValidLayout else {
return self.contentSize
}
return CGSize(width: scrollDirection == .horizontal ? self.contentSize.width * multiplier : self.contentSize.width,
height: scrollDirection == .vertical ? self.contentSize.height * multiplier : self.contentSize.height)
}
open override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let attributes = super.layoutAttributesForItem(at: indexPath) else {
return nil
}
return self.layoutAttributes(from: attributes, page: currentPage)
}
override open func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard isEnabled else {
guard hasValidLayout else {
return super.layoutAttributesForElements(in: rect)
}
let page = self.page(for: rect.origin)
@@ -143,7 +163,7 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
}
public func loopCollectionViewIfNeeded() {
guard let collectionView = self.collectionView, self.isEnabled else {
guard let collectionView = self.collectionView, self.hasValidLayout else {
return
}
let page = self.pageIndex(from: self.page(for: collectionView.contentOffset))
@@ -233,7 +253,7 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
}
public func centerCollectionView(withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
guard let collectionView = self.collectionView, self.isEnabled else {
guard let collectionView = self.collectionView, self.hasValidLayout else {
return
}
let newTarget = CGPoint(x: self.scrollDirection == .horizontal ? collectionView.contentOffset.x + velocity.x * velocityMultiplier : targetContentOffset.pointee.x,
@@ -247,7 +267,7 @@ open class InfiniteLayout: UICollectionViewFlowLayout {
}
public func centerCollectionViewIfNeeded(indexPath: IndexPath? = nil) {
guard let collectionView = self.collectionView, self.isEnabled else {
guard let collectionView = self.collectionView, self.hasValidLayout else {
return
}
guard let preferredAttributes = self.preferredVisibleLayoutAttributes(indexPath: indexPath),
+8
View File
@@ -0,0 +1,8 @@
//
// InfiniteCollectionView.swift
// InfiniteLayout
//
// Created by Arnaud Dorgans on 05/09/2019.
//
@_exported import CocoaProxy
@@ -31,14 +31,14 @@ class RxInfiniteCollectionViewDelegate: DelegateProxy<InfiniteCollectionView, In
}
}
public extension Reactive where Base: InfiniteCollectionView {
extension Reactive where Base: InfiniteCollectionView {
private var infiniteDelegate: RxInfiniteCollectionViewDelegate {
return RxInfiniteCollectionViewDelegate.proxy(for: self.base)
}
public var itemCentered: ControlEvent<IndexPath?> {
let source = infiniteDelegate.sentMessage(#selector(InfiniteCollectionViewDelegate.infiniteCollectionView(_:didChangeCenteredIndexPath:)))
let source = infiniteDelegate.sentMessage(#selector(InfiniteCollectionViewDelegate.infiniteCollectionView(_:didChangeCenteredIndexPath:to:)))
.map { $0.last as? IndexPath }
return ControlEvent(events: source)
}
@@ -52,13 +52,13 @@ public extension Reactive where Base: InfiniteCollectionView {
}
}
public extension Reactive where Base: RxInfiniteCollectionView {
extension Reactive where Base: RxInfiniteCollectionView {
public func items<S: Sequence, O: ObservableType>
(infinite: Bool)
-> (_ source: O)
-> (_ cellFactory: @escaping (UICollectionView, Int, S.Iterator.Element) -> UICollectionViewCell)
-> Disposable where O.E == S {
-> Disposable where O.Element == S {
return { source in
guard infinite else {
return self.items(source)
@@ -76,7 +76,7 @@ public extension Reactive where Base: RxInfiniteCollectionView {
(cellIdentifier: String, cellType: Cell.Type = Cell.self, infinite: Bool)
-> (_ source: O)
-> (_ configureCell: @escaping (Int, S.Iterator.Element, Cell) -> Void)
-> Disposable where O.E == S {
-> Disposable where O.Element == S {
guard infinite else {
return self.items(cellIdentifier: cellIdentifier, cellType: cellType)
}
@@ -9,13 +9,15 @@ import UIKit
import RxDataSources
open class RxInfiniteCollectionViewSectionedReloadDataSource<S: SectionModelType>: RxCollectionViewSectionedReloadDataSource<S> {
public var isEnabled: Bool = true
open override subscript(section: Int) -> S {
let section = InfiniteDataSources.section(from: section, numberOfSections: sectionModels.count)
return self.sectionModels[section]
}
open override subscript(indexPath: IndexPath) -> I {
open override subscript(indexPath: IndexPath) -> Item {
get {
let indexPath = InfiniteDataSources.indexPath(from: indexPath,
numberOfSections: sectionModels.count,
@@ -33,7 +35,7 @@ open class RxInfiniteCollectionViewSectionedReloadDataSource<S: SectionModelType
guard let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
fatalError()
}
return InfiniteDataSources.multiplier(estimatedItemSize: layout.itemSize)
return InfiniteDataSources.multiplier(estimatedItemSize: layout.itemSize, enabled: isEnabled)
}
open override func numberOfSections(in collectionView: UICollectionView) -> Int {
@@ -54,12 +56,14 @@ open class RxInfiniteCollectionViewSectionedReloadDataSource<S: SectionModelType
open class RxInfiniteCollectionViewSectionedAnimatedDataSource<S: AnimatableSectionModelType>: RxCollectionViewSectionedAnimatedDataSource<S> {
public var isEnabled: Bool = true
open override subscript(section: Int) -> S {
let section = InfiniteDataSources.section(from: section, numberOfSections: sectionModels.count)
return self.sectionModels[section]
}
open override subscript(indexPath: IndexPath) -> I {
open override subscript(indexPath: IndexPath) -> Item {
get {
let indexPath = InfiniteDataSources.indexPath(from: indexPath,
numberOfSections: sectionModels.count,
@@ -77,7 +81,7 @@ open class RxInfiniteCollectionViewSectionedAnimatedDataSource<S: AnimatableSect
guard let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
fatalError()
}
return InfiniteDataSources.multiplier(estimatedItemSize: layout.itemSize)
return InfiniteDataSources.multiplier(estimatedItemSize: layout.itemSize, enabled: isEnabled)
}
open override func numberOfSections(in collectionView: UICollectionView) -> Int {