PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/TeamTalk/Pods/PSTCollectionView/PSTCollectionView/PSTCollectionViewLayout.m

https://gitlab.com/lisit1003/TTiOSClient
Objective C | 481 lines | 371 code | 86 blank | 24 comment | 53 complexity | 290282ed1b2653ba23e164376c47c355 MD5 | raw file
  1. //
  2. // PSTCollectionViewLayout.m
  3. // PSPDFKit
  4. //
  5. // Copyright (c) 2012-2013 Peter Steinberger. All rights reserved.
  6. //
  7. #import "PSTCollectionView.h"
  8. #import "PSTCollectionViewItemKey.h"
  9. #import "PSTCollectionViewData.h"
  10. #import <objc/runtime.h>
  11. @interface PSTCollectionView ()
  12. - (id)currentUpdate;
  13. - (NSDictionary *)visibleViewsDict;
  14. - (PSTCollectionViewData *)collectionViewData;
  15. - (CGRect)visibleBoundRects; // visibleBounds is flagged as private API (wtf)
  16. @end
  17. @interface PSTCollectionReusableView ()
  18. - (void)setIndexPath:(NSIndexPath *)indexPath;
  19. @end
  20. @interface PSTCollectionViewUpdateItem ()
  21. - (BOOL)isSectionOperation;
  22. @end
  23. @interface PSTCollectionViewLayoutAttributes () {
  24. struct {
  25. unsigned int isCellKind:1;
  26. unsigned int isDecorationView:1;
  27. unsigned int isHidden:1;
  28. }_layoutFlags;
  29. char filler[20]; // [HACK] Our class needs to be larger than Apple's class for the superclass change to work.
  30. }
  31. @property (nonatomic) PSTCollectionViewItemType elementCategory;
  32. @property (nonatomic, copy) NSString *elementKind;
  33. @end
  34. @interface PSTCollectionViewUpdateItem ()
  35. - (NSIndexPath *)indexPath;
  36. @end
  37. @implementation PSTCollectionViewLayoutAttributes
  38. ///////////////////////////////////////////////////////////////////////////////////////////
  39. #pragma mark - Static
  40. + (instancetype)layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath {
  41. PSTCollectionViewLayoutAttributes *attributes = [self new];
  42. attributes.elementKind = PSTCollectionElementKindCell;
  43. attributes.elementCategory = PSTCollectionViewItemTypeCell;
  44. attributes.indexPath = indexPath;
  45. return attributes;
  46. }
  47. + (instancetype)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath {
  48. PSTCollectionViewLayoutAttributes *attributes = [self new];
  49. attributes.elementCategory = PSTCollectionViewItemTypeSupplementaryView;
  50. attributes.elementKind = elementKind;
  51. attributes.indexPath = indexPath;
  52. return attributes;
  53. }
  54. + (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath {
  55. PSTCollectionViewLayoutAttributes *attributes = [self new];
  56. attributes.elementCategory = PSTCollectionViewItemTypeDecorationView;
  57. attributes.elementKind = elementKind;
  58. attributes.indexPath = indexPath;
  59. return attributes;
  60. }
  61. ///////////////////////////////////////////////////////////////////////////////////////////
  62. #pragma mark - NSObject
  63. - (id)init {
  64. if ((self = [super init])) {
  65. _alpha = 1.f;
  66. _transform3D = CATransform3DIdentity;
  67. }
  68. return self;
  69. }
  70. - (NSUInteger)hash {
  71. return ([_elementKind hash] * 31) + [_indexPath hash];
  72. }
  73. - (BOOL)isEqual:(id)other {
  74. if ([other isKindOfClass:self.class]) {
  75. PSTCollectionViewLayoutAttributes *otherLayoutAttributes = (PSTCollectionViewLayoutAttributes *)other;
  76. if (_elementCategory == otherLayoutAttributes.elementCategory && [_elementKind isEqual:otherLayoutAttributes.elementKind] && [_indexPath isEqual:otherLayoutAttributes.indexPath]) {
  77. return YES;
  78. }
  79. }
  80. return NO;
  81. }
  82. - (NSString *)description {
  83. return [NSString stringWithFormat:@"<%@: %p frame:%@ indexPath:%@ elementKind:%@>", NSStringFromClass(self.class), self, NSStringFromCGRect(self.frame), self.indexPath, self.elementKind];
  84. }
  85. ///////////////////////////////////////////////////////////////////////////////////////////
  86. #pragma mark - Public
  87. - (PSTCollectionViewItemType)representedElementCategory {
  88. return _elementCategory;
  89. }
  90. ///////////////////////////////////////////////////////////////////////////////////////////
  91. #pragma mark - Private
  92. - (NSString *)representedElementKind {
  93. return self.elementKind;
  94. }
  95. - (BOOL)isDecorationView {
  96. return self.representedElementCategory == PSTCollectionViewItemTypeDecorationView;
  97. }
  98. - (BOOL)isSupplementaryView {
  99. return self.representedElementCategory == PSTCollectionViewItemTypeSupplementaryView;
  100. }
  101. - (BOOL)isCell {
  102. return self.representedElementCategory == PSTCollectionViewItemTypeCell;
  103. }
  104. - (void) updateFrame {
  105. _frame = (CGRect){{_center.x - _size.width / 2, _center.y - _size.height / 2}, _size};
  106. }
  107. - (void)setSize:(CGSize)size {
  108. _size = size;
  109. [self updateFrame];
  110. }
  111. - (void)setCenter:(CGPoint)center {
  112. _center = center;
  113. [self updateFrame];
  114. }
  115. - (void)setFrame:(CGRect)frame {
  116. _frame = frame;
  117. _size = _frame.size;
  118. _center = (CGPoint){CGRectGetMidX(_frame), CGRectGetMidY(_frame)};
  119. }
  120. ///////////////////////////////////////////////////////////////////////////////////////////
  121. #pragma mark - NSCopying
  122. - (id)copyWithZone:(NSZone *)zone {
  123. PSTCollectionViewLayoutAttributes *layoutAttributes = [self.class new];
  124. layoutAttributes.indexPath = self.indexPath;
  125. layoutAttributes.elementKind = self.elementKind;
  126. layoutAttributes.elementCategory = self.elementCategory;
  127. layoutAttributes.frame = self.frame;
  128. layoutAttributes.center = self.center;
  129. layoutAttributes.size = self.size;
  130. layoutAttributes.transform3D = self.transform3D;
  131. layoutAttributes.alpha = self.alpha;
  132. layoutAttributes.zIndex = self.zIndex;
  133. layoutAttributes.hidden = self.isHidden;
  134. return layoutAttributes;
  135. }
  136. ///////////////////////////////////////////////////////////////////////////////////////////
  137. #pragma mark - PSTCollection/UICollection interoperability
  138. - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
  139. NSMethodSignature *signature = [super methodSignatureForSelector:selector];
  140. if (!signature) {
  141. NSString *selString = NSStringFromSelector(selector);
  142. if ([selString hasPrefix:@"_"]) {
  143. SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]);
  144. signature = [super methodSignatureForSelector:cleanedSelector];
  145. }
  146. }
  147. return signature;
  148. }
  149. - (void)forwardInvocation:(NSInvocation *)invocation {
  150. NSString *selString = NSStringFromSelector([invocation selector]);
  151. if ([selString hasPrefix:@"_"]) {
  152. SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]);
  153. if ([self respondsToSelector:cleanedSelector]) {
  154. invocation.selector = cleanedSelector;
  155. [invocation invokeWithTarget:self];
  156. }
  157. }else {
  158. [super forwardInvocation:invocation];
  159. }
  160. }
  161. @end
  162. @interface PSTCollectionViewLayout () {
  163. __unsafe_unretained PSTCollectionView *_collectionView;
  164. CGSize _collectionViewBoundsSize;
  165. NSMutableDictionary *_initialAnimationLayoutAttributesDict;
  166. NSMutableDictionary *_finalAnimationLayoutAttributesDict;
  167. NSMutableIndexSet *_deletedSectionsSet;
  168. NSMutableIndexSet *_insertedSectionsSet;
  169. NSMutableDictionary *_decorationViewClassDict;
  170. NSMutableDictionary *_decorationViewNibDict;
  171. NSMutableDictionary *_decorationViewExternalObjectsTables;
  172. char filler[200]; // [HACK] Our class needs to be larger than Apple's class for the superclass change to work.
  173. }
  174. @property (nonatomic, unsafe_unretained) PSTCollectionView *collectionView;
  175. @property (nonatomic, copy, readonly) NSDictionary *decorationViewClassDict;
  176. @property (nonatomic, copy, readonly) NSDictionary *decorationViewNibDict;
  177. @property (nonatomic, copy, readonly) NSDictionary *decorationViewExternalObjectsTables;
  178. @end
  179. @implementation PSTCollectionViewLayout
  180. ///////////////////////////////////////////////////////////////////////////////////////////
  181. #pragma mark - NSObject
  182. - (id)init {
  183. if ((self = [super init])) {
  184. _decorationViewClassDict = [NSMutableDictionary new];
  185. _decorationViewNibDict = [NSMutableDictionary new];
  186. _decorationViewExternalObjectsTables = [NSMutableDictionary new];
  187. _initialAnimationLayoutAttributesDict = [NSMutableDictionary new];
  188. _finalAnimationLayoutAttributesDict = [NSMutableDictionary new];
  189. _insertedSectionsSet = [NSMutableIndexSet new];
  190. _deletedSectionsSet = [NSMutableIndexSet new];
  191. }
  192. return self;
  193. }
  194. - (void)awakeFromNib {
  195. [super awakeFromNib];
  196. }
  197. - (void)setCollectionView:(PSTCollectionView *)collectionView {
  198. if (collectionView != _collectionView) {
  199. _collectionView = collectionView;
  200. }
  201. }
  202. ///////////////////////////////////////////////////////////////////////////////////////////
  203. #pragma mark - Invalidating the Layout
  204. - (void)invalidateLayout {
  205. [[_collectionView collectionViewData] invalidate];
  206. [_collectionView setNeedsLayout];
  207. }
  208. - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
  209. // not sure about his..
  210. if ((self.collectionView.bounds.size.width != newBounds.size.width) || (self.collectionView.bounds.size.height != newBounds.size.height)) {
  211. return YES;
  212. }
  213. return NO;
  214. }
  215. ///////////////////////////////////////////////////////////////////////////////////////////
  216. #pragma mark - Providing Layout Attributes
  217. + (Class)layoutAttributesClass {
  218. return PSTCollectionViewLayoutAttributes.class;
  219. }
  220. - (void)prepareLayout {
  221. }
  222. - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
  223. return nil;
  224. }
  225. - (PSTCollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
  226. return nil;
  227. }
  228. - (PSTCollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
  229. return nil;
  230. }
  231. - (PSTCollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
  232. return nil;
  233. }
  234. // return a point at which to rest after scrolling - for layouts that want snap-to-point scrolling behavior
  235. - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
  236. return proposedContentOffset;
  237. }
  238. - (CGSize)collectionViewContentSize {
  239. return CGSizeZero;
  240. }
  241. ///////////////////////////////////////////////////////////////////////////////////////////
  242. #pragma mark - Responding to Collection View Updates
  243. - (void)prepareForCollectionViewUpdates:(NSArray *)updateItems {
  244. NSDictionary *update = [_collectionView currentUpdate];
  245. for (PSTCollectionReusableView *view in [[_collectionView visibleViewsDict] objectEnumerator]) {
  246. PSTCollectionViewLayoutAttributes *attr = [view.layoutAttributes copy];
  247. if (attr) {
  248. if (attr.isCell) {
  249. NSInteger index = [update[@"oldModel"] globalIndexForItemAtIndexPath:[attr indexPath]];
  250. if (index != NSNotFound) {
  251. [attr setIndexPath:[attr indexPath]];
  252. }
  253. }
  254. _initialAnimationLayoutAttributesDict[[PSTCollectionViewItemKey collectionItemKeyForLayoutAttributes:attr]] = attr;
  255. }
  256. }
  257. PSTCollectionViewData *collectionViewData = [_collectionView collectionViewData];
  258. CGRect bounds = [_collectionView visibleBoundRects];
  259. for (PSTCollectionViewLayoutAttributes *attr in [collectionViewData layoutAttributesForElementsInRect:bounds]) {
  260. if (attr.isCell) {
  261. NSInteger index = [collectionViewData globalIndexForItemAtIndexPath:attr.indexPath];
  262. index = [update[@"newToOldIndexMap"][index] intValue];
  263. if (index != NSNotFound) {
  264. PSTCollectionViewLayoutAttributes *finalAttrs = [attr copy];
  265. [finalAttrs setIndexPath:[update[@"oldModel"] indexPathForItemAtGlobalIndex:index]];
  266. [finalAttrs setAlpha:0];
  267. _finalAnimationLayoutAttributesDict[[PSTCollectionViewItemKey collectionItemKeyForLayoutAttributes:finalAttrs]] = finalAttrs;
  268. }
  269. }
  270. }
  271. for (PSTCollectionViewUpdateItem *updateItem in updateItems) {
  272. PSTCollectionUpdateAction action = updateItem.updateAction;
  273. if ([updateItem isSectionOperation]) {
  274. if (action == PSTCollectionUpdateActionReload) {
  275. [_deletedSectionsSet addIndex:[[updateItem indexPathBeforeUpdate] section]];
  276. [_insertedSectionsSet addIndex:[updateItem indexPathAfterUpdate].section];
  277. }
  278. else {
  279. NSMutableIndexSet *indexSet = action == PSTCollectionUpdateActionInsert ? _insertedSectionsSet : _deletedSectionsSet;
  280. [indexSet addIndex:[updateItem indexPath].section];
  281. }
  282. }
  283. else {
  284. if (action == PSTCollectionUpdateActionDelete) {
  285. PSTCollectionViewItemKey *key = [PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:
  286. [updateItem indexPathBeforeUpdate]];
  287. PSTCollectionViewLayoutAttributes *attrs = [_finalAnimationLayoutAttributesDict[key] copy];
  288. if (attrs) {
  289. [attrs setAlpha:0];
  290. _finalAnimationLayoutAttributesDict[key] = attrs;
  291. }
  292. }
  293. else if (action == PSTCollectionUpdateActionReload || action == PSTCollectionUpdateActionInsert) {
  294. PSTCollectionViewItemKey *key = [PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:
  295. [updateItem indexPathAfterUpdate]];
  296. PSTCollectionViewLayoutAttributes *attrs = [_initialAnimationLayoutAttributesDict[key] copy];
  297. if (attrs) {
  298. [attrs setAlpha:0];
  299. _initialAnimationLayoutAttributesDict[key] = attrs;
  300. }
  301. }
  302. }
  303. }
  304. }
  305. - (PSTCollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {
  306. PSTCollectionViewLayoutAttributes *attrs = _initialAnimationLayoutAttributesDict[[PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:itemIndexPath]];
  307. if ([_insertedSectionsSet containsIndex:[itemIndexPath section]]) {
  308. attrs = [attrs copy];
  309. [attrs setAlpha:0];
  310. }
  311. return attrs;
  312. }
  313. - (PSTCollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {
  314. PSTCollectionViewLayoutAttributes *attrs = _finalAnimationLayoutAttributesDict[[PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:itemIndexPath]];
  315. if ([_deletedSectionsSet containsIndex:[itemIndexPath section]]) {
  316. attrs = [attrs copy];
  317. [attrs setAlpha:0];
  318. }
  319. return attrs;
  320. }
  321. - (PSTCollectionViewLayoutAttributes *)initialLayoutAttributesForInsertedSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath {
  322. PSTCollectionViewLayoutAttributes *attrs = _initialAnimationLayoutAttributesDict[[PSTCollectionViewItemKey collectionItemKeyForCellWithIndexPath:elementIndexPath]];
  323. if ([_insertedSectionsSet containsIndex:[elementIndexPath section]]) {
  324. attrs = [attrs copy];
  325. [attrs setAlpha:0];
  326. }
  327. return attrs;
  328. }
  329. - (PSTCollectionViewLayoutAttributes *)finalLayoutAttributesForDeletedSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath {
  330. return nil;
  331. }
  332. - (void)finalizeCollectionViewUpdates {
  333. [_initialAnimationLayoutAttributesDict removeAllObjects];
  334. [_finalAnimationLayoutAttributesDict removeAllObjects];
  335. [_deletedSectionsSet removeAllIndexes];
  336. [_insertedSectionsSet removeAllIndexes];
  337. }
  338. ///////////////////////////////////////////////////////////////////////////////////////////
  339. #pragma mark - Registering Decoration Views
  340. - (void)registerClass:(Class)viewClass forDecorationViewOfKind:(NSString *)kind {
  341. _decorationViewClassDict[kind] = viewClass;
  342. }
  343. - (void)registerNib:(UINib *)nib forDecorationViewOfKind:(NSString *)kind {
  344. _decorationViewNibDict[kind] = nib;
  345. }
  346. ///////////////////////////////////////////////////////////////////////////////////////////
  347. #pragma mark - Private
  348. - (void)setCollectionViewBoundsSize:(CGSize)size {
  349. _collectionViewBoundsSize = size;
  350. }
  351. ///////////////////////////////////////////////////////////////////////////////////////////
  352. #pragma mark - NSCoding
  353. - (id)initWithCoder:(NSCoder *)coder {
  354. if ((self = [self init])) {
  355. }
  356. return self;
  357. }
  358. - (void)encodeWithCoder:(NSCoder *)coder {}
  359. ///////////////////////////////////////////////////////////////////////////////////////////
  360. #pragma mark - PSTCollection/UICollection interoperability
  361. #ifdef kPSUIInteroperabilityEnabled
  362. #import <objc/runtime.h>
  363. #import <objc/message.h>
  364. - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
  365. NSMethodSignature *sig = [super methodSignatureForSelector:selector];
  366. if(!sig) {
  367. NSString *selString = NSStringFromSelector(selector);
  368. if ([selString hasPrefix:@"_"]) {
  369. SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]);
  370. sig = [super methodSignatureForSelector:cleanedSelector];
  371. }
  372. }
  373. return sig;
  374. }
  375. - (void)forwardInvocation:(NSInvocation *)inv {
  376. NSString *selString = NSStringFromSelector([inv selector]);
  377. if ([selString hasPrefix:@"_"]) {
  378. SEL cleanedSelector = NSSelectorFromString([selString substringFromIndex:1]);
  379. if ([self respondsToSelector:cleanedSelector]) {
  380. // dynamically add method for faster resolving
  381. Method newMethod = class_getInstanceMethod(self.class, [inv selector]);
  382. IMP underscoreIMP = imp_implementationWithBlock(^(id _self) {
  383. return objc_msgSend(_self, cleanedSelector);
  384. });
  385. class_addMethod(self.class, [inv selector], underscoreIMP, method_getTypeEncoding(newMethod));
  386. // invoke now
  387. inv.selector = cleanedSelector;
  388. [inv invokeWithTarget:self];
  389. }
  390. }else {
  391. [super forwardInvocation:inv];
  392. }
  393. }
  394. #endif
  395. @end