77
88#import " LXReorderableCollectionViewFlowLayout.h"
99#import < QuartzCore/QuartzCore.h>
10+ #import < objc/runtime.h>
1011
1112#define LX_FRAMES_PER_SECOND 60.0
1213
@@ -28,6 +29,20 @@ typedef NS_ENUM(NSInteger, LXScrollingDirection) {
2829static NSString * const kLXScrollingDirectionKey = @" LXScrollingDirection" ;
2930static NSString * const kLXCollectionViewKeyPath = @" collectionView" ;
3031
32+ @interface CADisplayLink (LX_userInfo)
33+ @property (nonatomic , copy ) NSDictionary *LX_userInfo;
34+ @end
35+
36+ @implementation CADisplayLink (LX_userInfo)
37+ - (void ) setLX_userInfo : (NSDictionary *) LX_userInfo {
38+ objc_setAssociatedObject (self, " LX_userInfo" , LX_userInfo, OBJC_ASSOCIATION_COPY );
39+ }
40+
41+ - (NSDictionary *) LX_userInfo {
42+ return objc_getAssociatedObject (self, " LX_userInfo" );
43+ }
44+ @end
45+
3146@interface UICollectionViewCell (LXReorderableCollectionViewFlowLayout)
3247
3348- (UIImage *)LX_rasterizedImage ;
@@ -52,7 +67,7 @@ @interface LXReorderableCollectionViewFlowLayout ()
5267@property (strong , nonatomic ) UIView *currentView;
5368@property (assign , nonatomic ) CGPoint currentViewCenter;
5469@property (assign , nonatomic ) CGPoint panTranslationInCollectionView;
55- @property (strong , nonatomic ) NSTimer *scrollingTimer ;
70+ @property (strong , nonatomic ) CADisplayLink *displayLink ;
5671
5772@property (assign , nonatomic , readonly ) id <LXReorderableCollectionViewDataSource> dataSource;
5873@property (assign , nonatomic , readonly ) id <LXReorderableCollectionViewDelegateFlowLayout> delegate;
@@ -139,48 +154,54 @@ - (void)invalidateLayoutIfNecessary {
139154
140155 self.selectedItemIndexPath = newIndexPath;
141156
142- [self .dataSource collectionView: self .collectionView itemAtIndexPath: previousIndexPath willMoveToIndexPath: newIndexPath];
143-
157+ if ([self .dataSource respondsToSelector: @selector (collectionView:itemAtIndexPath:willMoveToIndexPath: )]) {
158+ [self .dataSource collectionView: self .collectionView itemAtIndexPath: previousIndexPath willMoveToIndexPath: newIndexPath];
159+ }
160+
144161 __weak typeof (self) weakSelf = self;
145162 [self .collectionView performBatchUpdates: ^{
146163 __strong typeof (self) strongSelf = weakSelf;
147164 if (strongSelf) {
148165 [strongSelf.collectionView deleteItemsAtIndexPaths: @[ previousIndexPath ]];
149166 [strongSelf.collectionView insertItemsAtIndexPaths: @[ newIndexPath ]];
150167 }
151- } completion: nil ];
168+ } completion: ^(BOOL finished) {
169+ __strong typeof (self) strongSelf = weakSelf;
170+ if ([strongSelf.dataSource respondsToSelector: @selector (collectionView:itemAtIndexPath:didMoveToIndexPath: )]) {
171+ [strongSelf.dataSource collectionView: strongSelf.collectionView itemAtIndexPath: previousIndexPath didMoveToIndexPath: newIndexPath];
172+ }
173+ }];
152174}
153175
154176- (void )invalidatesScrollTimer {
155- if (self.scrollingTimer . isValid ) {
156- [self .scrollingTimer invalidate ];
177+ if (! self.displayLink . paused ) {
178+ [self .displayLink invalidate ];
157179 }
158- self.scrollingTimer = nil ;
180+ self.displayLink = nil ;
159181}
160182
161183- (void )setupScrollTimerInDirection : (LXScrollingDirection)direction {
162- if (self.scrollingTimer . isValid ) {
163- LXScrollingDirection oldDirection = [self .scrollingTimer.userInfo [kLXScrollingDirectionKey ] integerValue ];
164-
184+ if (! self.displayLink . paused ) {
185+ LXScrollingDirection oldDirection = [self .displayLink.LX_userInfo [kLXScrollingDirectionKey ] integerValue ];
186+
165187 if (direction == oldDirection) {
166188 return ;
167189 }
168190 }
169191
170192 [self invalidatesScrollTimer ];
171-
172- self.scrollingTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 / LX_FRAMES_PER_SECOND
173- target: self
174- selector: @selector (handleScroll: )
175- userInfo: @{ kLXScrollingDirectionKey : @(direction) }
176- repeats: YES ];
193+
194+ self.displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector (handleScroll: )];
195+ self.displayLink .LX_userInfo = @{ kLXScrollingDirectionKey : @(direction) };
196+
197+ [self .displayLink addToRunLoop: [NSRunLoop mainRunLoop ] forMode: NSRunLoopCommonModes ];
177198}
178199
179200#pragma mark - Target/Action methods
180201
181202// Tight loop, allocate memory sparely, even if they are stack allocation.
182- - (void )handleScroll : (NSTimer *)timer {
183- LXScrollingDirection direction = (LXScrollingDirection)[timer.userInfo [kLXScrollingDirectionKey ] integerValue ];
203+ - (void )handleScroll : (CADisplayLink *)displayLink {
204+ LXScrollingDirection direction = (LXScrollingDirection)[displayLink.LX_userInfo [kLXScrollingDirectionKey ] integerValue ];
184205 if (direction == LXScrollingDirectionUnknown) {
185206 return ;
186207 }
0 commit comments