This repository has been archived by the owner on Sep 18, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Animate layout during collection/table view cell updates
Using method swizzling to hook into animated cell updates of UICollectionView and UITableView. - The implementation for UICollectionView is based on public API ([UICollectionViewLayout finalizeCollectionViewUpdates] and should not cause any problems. - The implementation for UITableView swizzles a private method ([UITableView _endCellAnimationsWithContext:]. The swizzled method also has to create its own animation block to update the container view's contentSize because there is no delegate method to run an animation inside the table view's animation block.
- Loading branch information
Showing
6 changed files
with
143 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/* | ||
OLEContainerScrollView | ||
Copyright (c) 2014 Ole Begemann. | ||
https://github.com/ole/OLEContainerScrollView | ||
*/ | ||
|
||
void swizzleUICollectionViewLayoutFinalizeCollectionViewUpdates(); | ||
void swizzleUITableView(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
OLEContainerScrollView | ||
Copyright (c) 2014 Ole Begemann. | ||
https://github.com/ole/OLEContainerScrollView | ||
*/ | ||
|
||
@import UIKit; | ||
|
||
#import "OLEContainerScrollView+Swizzling.h" | ||
#import "OLESwizzling.h" | ||
#import "OLEContainerScrollView.h" | ||
#import "OLEContainerScrollViewContentView.h" | ||
|
||
void swizzleUICollectionViewLayoutFinalizeCollectionViewUpdates() | ||
{ | ||
Class classToSwizzle = [UICollectionViewLayout class]; | ||
SEL selectorToSwizzle = @selector(finalizeCollectionViewUpdates); | ||
|
||
__block IMP originalIMP = NULL; | ||
originalIMP = OLEReplaceMethodWithBlock(classToSwizzle, selectorToSwizzle, ^(UICollectionViewLayout *_self) { | ||
// Call original implementation | ||
((void ( *)(id, SEL))originalIMP)(_self, selectorToSwizzle); | ||
|
||
// Manually set the collection view's contentSize to its new size (after the updates have been performed) to cause | ||
// a relayout of all views in the container scroll view. | ||
// We do this to animate the resizing of the collection view and its adjacent views in the container scroll view | ||
// in sync with the cell update animations (finalizeCollectionViewUpdates is called inside the animation block). | ||
// If we don't do this, the collection view will set its new content size only after the cell update animations | ||
// have finished, which is too late for us. | ||
UICollectionView *collectionView = _self.collectionView; | ||
BOOL collectionViewIsInsideOLEContainerScrollView = [collectionView.superview isKindOfClass:[OLEContainerScrollViewContentView class]]; | ||
if (collectionViewIsInsideOLEContainerScrollView) { | ||
collectionView.contentSize = _self.collectionViewContentSize; | ||
} | ||
}); | ||
} | ||
|
||
@interface UITableView (Swizzling) | ||
- (void)_endCellAnimationsWithContext:(id)context; | ||
@end | ||
|
||
void swizzleUITableView() | ||
{ | ||
Class classToSwizzle = [UITableView class]; | ||
NSString *obfuscatedSelector = [NSString stringWithFormat:@"_%@llAnimat%@hContext:", @"endCe", @"ionsWit"]; | ||
SEL selectorToSwizzle = NSSelectorFromString(obfuscatedSelector); | ||
|
||
__block IMP originalIMP = NULL; | ||
originalIMP = OLEReplaceMethodWithBlock(classToSwizzle, selectorToSwizzle, ^(UITableView *_self, id context) { | ||
// Call original implementation | ||
((void ( *)(id, SEL, id))originalIMP)(_self, selectorToSwizzle, context); | ||
|
||
[UIView animateWithDuration:0.25 animations:^{ | ||
|
||
// Manually set the collection view's contentSize to its new size (after the updates have been performed) to cause | ||
// a relayout of all views in the container scroll view. | ||
// We do this to animate the resizing of the collection view and its adjacent views in the container scroll view | ||
// in sync with the cell update animations (finalizeCollectionViewUpdates is called inside the animation block). | ||
// If we don't do this, the collection view will set its new content size only after the cell update animations | ||
// have finished, which is too late for us. | ||
BOOL tableViewIsInsideOLEContainerScrollView = [_self.superview isKindOfClass:[OLEContainerScrollViewContentView class]]; | ||
if (tableViewIsInsideOLEContainerScrollView) { | ||
NSString *obfuscatedPropertyKey = [NSString stringWithFormat:@"_%@entSize", @"cont"]; | ||
_self.contentSize = [[_self valueForKey:obfuscatedPropertyKey] CGSizeValue]; | ||
} | ||
}]; | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/* | ||
OLEContainerScrollView | ||
Copyright (c) 2014 Ole Begemann. | ||
https://github.com/ole/OLEContainerScrollView | ||
*/ | ||
|
||
#import <objc/runtime.h> | ||
|
||
IMP OLEReplaceMethodWithBlock(Class c, SEL origSEL, id block); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
OLEContainerScrollView | ||
Copyright (c) 2014 Ole Begemann. | ||
https://github.com/ole/OLEContainerScrollView | ||
*/ | ||
|
||
#import "OLESwizzling.h" | ||
|
||
// Adapted from Peter Steinberger's PSPDFReplaceMethodWithBlock | ||
// See http://petersteinberger.com/blog/2014/a-story-about-swizzling-the-right-way-and-touch-forwarding/ | ||
IMP OLEReplaceMethodWithBlock(Class c, SEL origSEL, id block) | ||
{ | ||
NSCParameterAssert(block); | ||
|
||
// get original method | ||
Method origMethod = class_getInstanceMethod(c, origSEL); | ||
NSCParameterAssert(origMethod); | ||
|
||
// convert block to IMP trampoline and replace method implementation | ||
IMP newIMP = imp_implementationWithBlock(block); | ||
|
||
// Try adding the method if not yet in the current class | ||
if (!class_addMethod(c, origSEL, newIMP, method_getTypeEncoding(origMethod))) { | ||
return method_setImplementation(origMethod, newIMP); | ||
}else { | ||
return method_getImplementation(origMethod); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters