CHD_ListView_Structure.m 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. //
  2. // UITableView+Structure.m
  3. //
  4. //
  5. // Created by chd on 2017/8/24.
  6. // Copyright © 2017年 chd. All rights reserved.
  7. // https://github.com/donggelaile/CHD_ListView_Structure
  8. #import "CHD_ListView_Structure.h"
  9. #import <objc/runtime.h>
  10. //Switch
  11. @interface CHD_SwitchView : UIButton
  12. @end
  13. //HookHelper
  14. @interface CHD_HookHelper : NSObject
  15. @property (nonatomic, assign) BOOL is_open_chdTable;
  16. @property (nonatomic, assign) BOOL is_open_chdCollection;
  17. @property (nonatomic, retain) NSMapTable *weakListViewDic;
  18. + (instancetype)shareInstance;
  19. - (void)hookSelectors:(NSArray *)selArr orginalObj:(id)oriObj swizzedObj:(id)newObj;
  20. - (void)resetCHD_HoverView;
  21. @end
  22. //MustrHelper
  23. @interface CHD_MustrHelper : NSObject
  24. @end
  25. //Hover
  26. @interface CHD_HoverLabel : UILabel
  27. @property (nonatomic, retain)UIColor *borderColor;
  28. @end
  29. @interface UIView (CHD_HoverView)
  30. @end
  31. //UITableView
  32. @interface UITableViewHDStructure:NSObject
  33. @end
  34. @interface CHD_TableHelper : NSObject
  35. @end
  36. //UICollectionView
  37. @interface UICollectionViewHDStructure:NSObject
  38. @end
  39. @interface CHD_CollectionHelper : NSObject
  40. @end
  41. #define chd_table_head_view_color [UIColor magentaColor]
  42. #define chd_table_cell_color [UIColor redColor]
  43. #define chd_table_header_color [UIColor blueColor]
  44. #define chd_table_footer_color [UIColor greenColor]
  45. #define chd_text_bg_alpha 0.7
  46. #define chd_table_text_color [UIColor whiteColor]
  47. #define chd_table_footer_view_color [UIColor blackColor]
  48. #define chd_collection_cell_color [UIColor orangeColor]
  49. #define chd_collection_header_color [UIColor purpleColor]
  50. #define chd_collection_footer_color [UIColor cyanColor]
  51. #define chd_collection_decoration_color [UIColor blackColor]
  52. #define chd_collection_bg_alpha 1
  53. #define chd_collection_text_color [UIColor whiteColor]
  54. static NSString *const CHD_MapTable_Obj = @"CHD_MapTable_Obj";
  55. BOOL __CHD_Instance_Transition_Swizzle(Class originalClass,SEL originalSelector, Class swizzledClass, SEL swizzledSelector){
  56. #ifdef DEBUG
  57. Method originalMethod = class_getInstanceMethod(originalClass, originalSelector);
  58. Method swizzledMethod = class_getInstanceMethod(swizzledClass, swizzledSelector);
  59. if (!originalMethod) {
  60. //如果原对象原方法未实现,查看交换类是否帮其实现了原类方法
  61. Method tempM = class_getInstanceMethod(swizzledClass, originalSelector);
  62. if (tempM) {
  63. //给原对象增加原方法
  64. class_addMethod(originalClass, originalSelector, method_getImplementation(tempM), method_getTypeEncoding(tempM));
  65. //更新原对象实现
  66. originalMethod = class_getInstanceMethod(originalClass, originalSelector);
  67. }
  68. }
  69. if (!originalMethod || !swizzledMethod) {
  70. return NO;
  71. }
  72. IMP originalIMP = method_getImplementation(originalMethod);
  73. IMP swizzledIMP = method_getImplementation(swizzledMethod);
  74. const char *originalType = method_getTypeEncoding(originalMethod);
  75. const char *swizzledType = method_getTypeEncoding(swizzledMethod);
  76. //给原对象增加swizzledSelector方法,实现为originalIMP
  77. class_replaceMethod(originalClass,swizzledSelector,originalIMP,originalType);
  78. //替换originalSelector的实现为swizzledIMP
  79. class_replaceMethod(originalClass,originalSelector,swizzledIMP,swizzledType);
  80. return YES;
  81. #else
  82. return NO;
  83. #endif
  84. }
  85. @implementation CHD_SwitchView
  86. - (instancetype)initWithFrame:(CGRect)frame
  87. {
  88. if ([super initWithFrame:frame]) {
  89. UIPanGestureRecognizer* pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(handelPan:)];
  90. [self addGestureRecognizer:pan];
  91. self.alpha = 1;
  92. }
  93. return self;
  94. }
  95. - (void)handelPan:(UIPanGestureRecognizer*)gestureRecognizer
  96. {
  97. if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
  98. [UIView animateWithDuration:0.3 animations:^{
  99. gestureRecognizer.view.alpha = 1;
  100. }];
  101. }
  102. if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
  103. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  104. [UIView animateWithDuration:1 animations:^{
  105. gestureRecognizer.view.alpha = 0.5;
  106. }];
  107. });
  108. }
  109. CGPoint center = [gestureRecognizer locationInView:self.superview];
  110. CGFloat minX = CGRectGetWidth(self.frame)/2.0;
  111. CGFloat maxX = [UIScreen mainScreen].bounds.size.width - minX;
  112. CGFloat minY = CGRectGetHeight(self.frame)/2.0;
  113. CGFloat maxY = [UIScreen mainScreen].bounds.size.height - minY;
  114. if (center.x<minX) {
  115. center = CGPointMake(minX, center.y);
  116. }
  117. if (center.y<minY) {
  118. center = CGPointMake(center.x, minY);
  119. }
  120. if (center.x>maxX) {
  121. center = CGPointMake(maxX, center.y);
  122. }
  123. if (center.y>maxY) {
  124. center = CGPointMake(center.x, maxY);
  125. }
  126. self.center = center;
  127. }
  128. @end
  129. #pragma mark - CHD_ListView_Structure
  130. @implementation CHD_ListView_Structure
  131. +(void)openStructureShow_TableV:(BOOL)isOpenT collectionV:(BOOL)isOpenC
  132. {
  133. #ifdef DEBUG
  134. static dispatch_once_t onceToken;
  135. dispatch_once(&onceToken, ^{
  136. [CHD_HookHelper shareInstance].is_open_chdTable = isOpenT;
  137. [CHD_HookHelper shareInstance].is_open_chdCollection = isOpenC;
  138. [CHD_ListView_Structure hookTable];
  139. [CHD_ListView_Structure hookCollection];
  140. [CHD_ListView_Structure addToggleView];
  141. });
  142. #endif
  143. }
  144. + (void)addToggleView
  145. {
  146. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  147. UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
  148. CGFloat btnW = 50.0f;
  149. CHD_SwitchView *btn = [[CHD_SwitchView alloc] initWithFrame:CGRectMake(0, 50, btnW, btnW)];
  150. btn.alpha = 0.5;
  151. [btn setTitle:@"Toggle" forState:UIControlStateNormal];
  152. btn.layer.cornerRadius = btnW/2.0f;
  153. btn.backgroundColor = [UIColor orangeColor];
  154. btn.titleLabel.font = [UIFont systemFontOfSize:14.0f];
  155. UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapGesture)];
  156. [btn addGestureRecognizer:tap];
  157. [window addSubview:btn];
  158. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  159. [window bringSubviewToFront:btn];
  160. });
  161. });
  162. }
  163. + (void)hookTable
  164. {
  165. #pragma clang diagnostic push
  166. #pragma clang diagnostic ignored "-Wundeclared-selector"
  167. __CHD_Instance_Transition_Swizzle([UITableView class], @selector(setDelegate:), [UITableViewHDStructure class],@selector(CHD_setDelegate:));
  168. __CHD_Instance_Transition_Swizzle([UITableView class], @selector(setDataSource:), [UITableViewHDStructure class],@selector(CHD_setDataSource:));
  169. NSArray *selArr = @[@"setTableFooterView:",@"setTableHeaderView:"];
  170. [[CHD_HookHelper shareInstance] hookSelectors:selArr orginalObj:[UITableView new] swizzedObj:[CHD_TableHelper class]];
  171. #pragma clang diagnostic pop
  172. }
  173. + (void)hookCollection
  174. {
  175. #pragma clang diagnostic push
  176. #pragma clang diagnostic ignored "-Wundeclared-selector"
  177. __CHD_Instance_Transition_Swizzle([UICollectionView class], @selector(setDelegate:), [UICollectionViewHDStructure class], @selector(CHD_setDelegate:));
  178. __CHD_Instance_Transition_Swizzle([UICollectionView class], @selector(setDataSource:), [UICollectionViewHDStructure class], @selector(CHD_setDataSource:));
  179. #pragma clang diagnostic pop
  180. }
  181. + (void)tapGesture
  182. {
  183. [CHD_HookHelper shareInstance].is_open_chdTable = ![CHD_HookHelper shareInstance].is_open_chdTable;
  184. [CHD_HookHelper shareInstance].is_open_chdCollection = ![CHD_HookHelper shareInstance].is_open_chdCollection;
  185. [[CHD_HookHelper shareInstance] resetCHD_HoverView];
  186. }
  187. @end
  188. #pragma mark - CHD_HookHelper
  189. static CHD_HookHelper *helper;
  190. @implementation CHD_HookHelper
  191. {
  192. NSMutableDictionary *swizzedData;
  193. }
  194. + (instancetype)shareInstance
  195. {
  196. UIApplication *app = [UIApplication sharedApplication];
  197. helper = objc_getAssociatedObject(app, (__bridge const void * _Nonnull)(@(123)));
  198. if (!helper) {
  199. helper = [[self alloc] init];
  200. objc_setAssociatedObject(app, (__bridge const void * _Nonnull)(@(123)), helper, OBJC_ASSOCIATION_RETAIN);
  201. }
  202. return helper;
  203. }
  204. - (instancetype)init
  205. {
  206. if (self = [super init]) {
  207. swizzedData = @{}.mutableCopy;
  208. self.weakListViewDic = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsWeakMemory valueOptions:NSPointerFunctionsCopyIn];
  209. self.is_open_chdTable = NO;
  210. self.is_open_chdCollection = NO;
  211. }
  212. return self;
  213. }
  214. - (BOOL)chenckIsSwizzedOrgObj:(id)oriObj sel:(NSString*)sel
  215. {
  216. if (!oriObj ||!sel) {
  217. return YES;
  218. }
  219. BOOL isFatherChanged = NO;//查找是否有父类或同类已经交换过
  220. for (NSString *keys in [swizzedData allKeys]) {
  221. NSString *saveClass = [[keys componentsSeparatedByString:@"_chd_hook_"] firstObject];
  222. if ([oriObj isKindOfClass:NSClassFromString(saveClass)] && [swizzedData[[self getUniqueStr:saveClass sel:sel]] boolValue]) {
  223. isFatherChanged = YES;
  224. break;
  225. }
  226. }
  227. if (isFatherChanged) {
  228. /*
  229. 1、父类已经交换过
  230. 2、这里未对子类再进行交换,原因是如果子类重载了方法并且调用了[super someMethod]将会递归循环
  231. 3、目前可以判断子类是否重载了某个函数,但无法判断子类内部是否调用了[super someMethod],所以目前先不对子类做处理
  232. 4、未对子类进行处理的情况下,如果子类调用了[super someMethod]或未重载父类方法将会正常显示,否则子类的页面将无法显示结构
  233. */
  234. //综上有两种建议:1、不使用继承实现delegate和dataSource的方法 2、使用了继承在子类重载的话要调用[super someMethod]
  235. return isFatherChanged;
  236. }
  237. return [swizzedData[[self getUniqueStr:NSStringFromClass([oriObj class]) sel:sel]] boolValue];
  238. }
  239. - (void)hookSelectors:(NSArray *)selArr orginalObj:(id)oriObj swizzedObj:(id)newObj
  240. {
  241. for (NSString *selStr in selArr) {
  242. SEL sel = NSSelectorFromString(selStr);
  243. SEL newSel = NSSelectorFromString([@"CHD_" stringByAppendingString:selStr]);
  244. if (![self chenckIsSwizzedOrgObj:oriObj sel:selStr]) {
  245. BOOL isSuccess = __CHD_Instance_Transition_Swizzle([oriObj class], sel, [newObj class], newSel);
  246. if (isSuccess) {
  247. swizzedData[[self getUniqueStr:NSStringFromClass([oriObj class]) sel:selStr]] = @(YES);
  248. }
  249. }
  250. // [oriObj aspect_hookSelector:sel withOptions:AspectPositionInstead usingBlock:^(id<AspectInfo> aspectInfo) {
  251. //
  252. //
  253. // } error:nil];
  254. }
  255. }
  256. - (nullable NSString *)getUniqueStr:(NSString*)oriObjClass sel:(NSString*)sel
  257. {
  258. if (!oriObjClass||!sel) {
  259. return nil;
  260. }
  261. return [NSString stringWithFormat:@"%@_chd_hook_%@",oriObjClass,sel];
  262. }
  263. - (void)resetCHD_HoverView
  264. {
  265. NSArray *WeakListViewArr = [[[CHD_HookHelper shareInstance].weakListViewDic keyEnumerator] allObjects];
  266. NSLog(@"当前listView个数:%@",@(WeakListViewArr.count));
  267. for (UIView *listView in WeakListViewArr) {
  268. if ([listView isKindOfClass:[UITableView class]] || [listView isKindOfClass:[UICollectionView class]]) {
  269. //刷新当前listView
  270. [listView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
  271. //刷新tableHederView、tableFooterView
  272. if ([listView isKindOfClass:[UITableView class]]) {
  273. UIView *tabelHeader = [(UITableView *)listView tableHeaderView];
  274. if (tabelHeader) {
  275. [(UITableView *)listView setTableHeaderView:tabelHeader];
  276. }
  277. UIView *tableFooter = [(UITableView *)listView tableFooterView];
  278. if (tableFooter) {
  279. [(UITableView *)listView setTableFooterView:tableFooter];
  280. }
  281. }
  282. }
  283. }
  284. }
  285. @end
  286. #pragma mark - CHD_MustrHelper
  287. @implementation CHD_MustrHelper
  288. + (NSMutableAttributedString *)getMustr:(NSString*)str textColor:(UIColor *)textColor backGroundColor:(UIColor *)backColor
  289. {
  290. NSMutableAttributedString *Mstr = [[NSMutableAttributedString alloc] initWithString:str];
  291. [Mstr addAttribute:NSBackgroundColorAttributeName value:backColor range:NSMakeRange(0, str.length)];
  292. [Mstr addAttribute:NSForegroundColorAttributeName value:textColor range:NSMakeRange(0, str.length)];
  293. return Mstr;
  294. }
  295. @end
  296. #pragma mark - UIView(CHD_HoverView)
  297. static const void * CHDHOVERLABELKEY = "CHDHOVERLABELKEY";
  298. @implementation UIView(CHD_HoverView)
  299. - (UILabel *)hoverView:(UIColor*)borderColor
  300. {
  301. CHD_HoverLabel *hover = objc_getAssociatedObject(self, CHDHOVERLABELKEY);
  302. if (!hover) {
  303. hover = [[CHD_HoverLabel alloc] initWithFrame:self.bounds];
  304. hover.backgroundColor = [UIColor clearColor];
  305. hover.textAlignment = NSTextAlignmentCenter;
  306. hover.adjustsFontSizeToFitWidth = YES;
  307. [self addSubview:hover];
  308. hover.translatesAutoresizingMaskIntoConstraints = YES;
  309. hover.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  310. hover.borderColor = borderColor;
  311. objc_setAssociatedObject(self, CHDHOVERLABELKEY, hover, OBJC_ASSOCIATION_RETAIN);
  312. return hover;
  313. }else{
  314. [self bringSubviewToFront:hover];
  315. hover.borderColor = borderColor;
  316. return hover;
  317. }
  318. }
  319. @end
  320. @implementation CHD_HoverLabel
  321. +(Class)layerClass
  322. {
  323. return [CAShapeLayer class];
  324. }
  325. - (void)layoutSubviews
  326. {
  327. [super layoutSubviews];
  328. CAShapeLayer *layer = (CAShapeLayer *)self.layer;
  329. layer.frame = self.bounds;
  330. layer.path = [UIBezierPath bezierPathWithRect:CGRectInset(self.bounds, 1, 1)].CGPath;//增加一个小的间隙,这样多个cell的边缘不会重合
  331. layer.fillColor = [UIColor clearColor].CGColor;
  332. layer.strokeColor = self.borderColor.CGColor;
  333. layer.lineWidth = 1;
  334. }
  335. @end
  336. #pragma mark - UITableView (CHD_Structure)
  337. @implementation UITableViewHDStructure
  338. - (void)CHD_setDelegate:(id)delegate
  339. {
  340. if (delegate) {
  341. NSMutableArray *selArr = @[@"tableView:willDisplayFooterView:forSection:",@"tableView:willDisplayHeaderView:forSection:"].mutableCopy;
  342. [[CHD_HookHelper shareInstance] hookSelectors:selArr orginalObj:delegate swizzedObj:[CHD_TableHelper class]];
  343. [[CHD_HookHelper shareInstance].weakListViewDic setObject:CHD_MapTable_Obj forKey:self];
  344. }
  345. [self CHD_setDelegate:delegate];
  346. }
  347. - (void)CHD_setDataSource:(id)dataSource
  348. {
  349. if (dataSource) {
  350. NSArray *selArr = @[@"tableView:cellForRowAtIndexPath:"];
  351. [[CHD_HookHelper shareInstance] hookSelectors:selArr orginalObj:dataSource swizzedObj:[CHD_TableHelper class]];
  352. [[CHD_HookHelper shareInstance].weakListViewDic setObject:CHD_MapTable_Obj forKey:self];
  353. }
  354. [self CHD_setDataSource:dataSource];
  355. }
  356. @end
  357. @implementation CHD_TableHelper
  358. - (void)CHD_setTableHeaderView:(UIView *)tableHeaderView
  359. {
  360. UILabel *headerHover = [tableHeaderView hoverView:chd_table_head_view_color];
  361. headerHover.attributedText = [CHD_MustrHelper getMustr:[NSString stringWithFormat:@"HeaderView--%@",NSStringFromClass([tableHeaderView class])] textColor:chd_table_text_color backGroundColor:chd_table_head_view_color];
  362. [self CHD_setTableHeaderView:tableHeaderView];
  363. headerHover.hidden = ![CHD_HookHelper shareInstance].is_open_chdTable;
  364. }
  365. - (void)CHD_setTableFooterView:(UIView *)tableFooterView
  366. {
  367. UILabel *footerHover = [tableFooterView hoverView:chd_table_footer_view_color];
  368. footerHover.attributedText = [CHD_MustrHelper getMustr:[NSString stringWithFormat:@"FooterView--%@",NSStringFromClass([tableFooterView class])] textColor:chd_table_text_color backGroundColor:chd_table_footer_view_color];
  369. [self CHD_setTableFooterView:tableFooterView];
  370. footerHover.hidden = ![CHD_HookHelper shareInstance].is_open_chdTable;
  371. }
  372. -(UITableViewCell *)CHD_tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  373. {
  374. UITableViewCell *cell = [self CHD_tableView:tableView cellForRowAtIndexPath:indexPath];
  375. UILabel *hover = [cell hoverView:chd_table_cell_color];
  376. hover.attributedText = [CHD_MustrHelper getMustr:[NSString stringWithFormat:@"%@--%@--%@",NSStringFromClass([cell class]),@(indexPath.section),@(indexPath.row)] textColor:chd_table_text_color backGroundColor:[chd_table_cell_color colorWithAlphaComponent:chd_text_bg_alpha]];
  377. hover.hidden = ![CHD_HookHelper shareInstance].is_open_chdTable;
  378. return cell;
  379. }
  380. //原代理未实现的话,主动添加一个空实现用来交换。实现了则直接交换
  381. - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(nonnull UIView *)view forSection:(NSInteger)section
  382. {
  383. }
  384. - (void)tableView:(UITableView *)tableView willDisplayFooterView:(nonnull UIView *)view forSection:(NSInteger)section
  385. {
  386. }
  387. - (void)CHD_tableView:(UITableView *)tableView willDisplayHeaderView:(nonnull UIView *)view forSection:(NSInteger)section
  388. {
  389. [self CHD_tableView:tableView willDisplayHeaderView:view forSection:section];
  390. if ([view isKindOfClass:[UILabel class]]) {
  391. [view layoutIfNeeded];
  392. }
  393. UILabel *hover = [view hoverView:chd_table_header_color];
  394. hover.attributedText = [CHD_MustrHelper getMustr:[NSString stringWithFormat:@"Header--%@--%@",NSStringFromClass([view class]),@(section)] textColor:chd_table_text_color backGroundColor:[chd_table_header_color colorWithAlphaComponent:chd_text_bg_alpha]];
  395. hover.hidden = ![CHD_HookHelper shareInstance].is_open_chdTable;
  396. }
  397. - (void)CHD_tableView:(UITableView *)tableView willDisplayFooterView:(nonnull UIView *)view forSection:(NSInteger)section
  398. {
  399. [self CHD_tableView:tableView willDisplayFooterView:view forSection:section];
  400. if ([view isKindOfClass:[UILabel class]]) {
  401. [view layoutIfNeeded];
  402. }
  403. UILabel *hover = [view hoverView:chd_table_footer_color];
  404. hover.attributedText = [CHD_MustrHelper getMustr:[NSString stringWithFormat:@"Footer--%@--%@",NSStringFromClass([view class]),@(section)] textColor:chd_table_text_color backGroundColor:[chd_table_footer_color colorWithAlphaComponent:chd_text_bg_alpha]];
  405. hover.hidden = ![CHD_HookHelper shareInstance].is_open_chdTable;
  406. }
  407. @end
  408. //CollectionView
  409. #pragma mark - UICollectionView (CHD_Structure)
  410. @implementation UICollectionViewHDStructure
  411. - (void)CHD_setDelegate:(id)delegate
  412. {
  413. if (delegate) {
  414. NSArray *selArr;
  415. if ([UIDevice currentDevice].systemVersion.floatValue>=8.0) {
  416. selArr = @[@"collectionView:willDisplaySupplementaryView:forElementKind:atIndexPath:"];
  417. }else{
  418. selArr = @[@"collectionView:didEndDisplayingSupplementaryView:forElementOfKind:atIndexPath:"];
  419. }
  420. [[CHD_HookHelper shareInstance] hookSelectors:selArr orginalObj:delegate swizzedObj:[CHD_CollectionHelper class]];
  421. [[CHD_HookHelper shareInstance].weakListViewDic setObject:CHD_MapTable_Obj forKey:self];
  422. }
  423. [self CHD_setDelegate:delegate];
  424. }
  425. - (void)CHD_setDataSource:(id)dataSource
  426. {
  427. if (dataSource) {
  428. NSArray *selArr = @[@"collectionView:cellForItemAtIndexPath:"];
  429. [[CHD_HookHelper shareInstance] hookSelectors:selArr orginalObj:dataSource swizzedObj:[CHD_CollectionHelper class]];
  430. [[CHD_HookHelper shareInstance].weakListViewDic setObject:CHD_MapTable_Obj forKey:self];
  431. }
  432. [self CHD_setDataSource:dataSource];
  433. }
  434. @end
  435. @implementation CHD_CollectionHelper
  436. + (NSAttributedString*)hoverAtt:(NSIndexPath*)indexPath cell:(UICollectionViewCell*)cell cacheToObj:(NSObject*)target
  437. {
  438. static char *HDListViewHoverTextCacheKey;
  439. NSMutableDictionary *hoverCache = objc_getAssociatedObject(target, &HDListViewHoverTextCacheKey);
  440. if (!hoverCache) {
  441. hoverCache = @{}.mutableCopy;
  442. objc_setAssociatedObject(target, &HDListViewHoverTextCacheKey, hoverCache, OBJC_ASSOCIATION_RETAIN);
  443. }
  444. NSString *key = [NSString stringWithFormat:@"%zd-%zd",indexPath.section,indexPath.item];
  445. NSAttributedString *result = hoverCache[key];
  446. if (!result) {
  447. result = [CHD_MustrHelper getMustr:[NSString stringWithFormat:@"%@++%@++%@",NSStringFromClass([cell class]),@(indexPath.section),@(indexPath.item)] textColor:chd_collection_text_color backGroundColor:[chd_collection_cell_color colorWithAlphaComponent:chd_collection_bg_alpha]];
  448. hoverCache[key] = result;
  449. }
  450. return result;
  451. }
  452. - (void)someMthond
  453. {
  454. }
  455. - (__kindof UICollectionViewCell *)CHD_collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
  456. {
  457. static BOOL isSHowTime = NO;
  458. __block UICollectionViewCell *cell = nil;
  459. if (isSHowTime) {
  460. //dispatch_benchmark 为系统私有API,不建议线上使用
  461. // //方法交换后需要注意一个问题,此处的代码中的self代表的是 UICollectionView的delegate
  462. // //此处的self不是CHD_CollectionHelper。因此 此处调用[self someMthond]; 编译不报错,运行时会报找不到方法
  463. // uint64_t dispatch_benchmark(size_t count, void (^block)(void));
  464. // uint64_t ns = dispatch_benchmark(1, ^{
  465. // cell = [self CHD_collectionView:collectionView cellForItemAtIndexPath:indexPath];
  466. // });
  467. //
  468. // double currentTime = ns/(pow(10, 6));
  469. //#ifdef DEBUG
  470. // printf("cellForItemAtIndexPath----本次时间%lf \n",currentTime);
  471. //#endif
  472. //
  473. // static char *HDListViewCountKey;
  474. // static char *HDListViewScrollTotalTimeKey;
  475. //
  476. // NSNumber *numCount = objc_getAssociatedObject(self, &HDListViewCountKey);
  477. // NSInteger count = 1;
  478. // if (numCount) {
  479. // count = numCount.integerValue;
  480. // }
  481. // double totalTime = 0;
  482. // NSNumber *numTotal = objc_getAssociatedObject(self, &HDListViewScrollTotalTimeKey);
  483. // if (numCount) {
  484. // totalTime = numTotal.doubleValue;
  485. // }
  486. // totalTime += currentTime;
  487. // double eveTime = (totalTime)/count;
  488. //#ifdef DEBUG
  489. // printf("cellForItemAtIndexPath----平均时间%lf \n",eveTime);
  490. //#endif
  491. // count++;
  492. //
  493. // objc_setAssociatedObject(self, &HDListViewCountKey, @(count), OBJC_ASSOCIATION_RETAIN);
  494. // objc_setAssociatedObject(self, &HDListViewScrollTotalTimeKey, @(totalTime), OBJC_ASSOCIATION_RETAIN);
  495. }else{
  496. cell = [self CHD_collectionView:collectionView cellForItemAtIndexPath:indexPath];
  497. }
  498. UILabel *hover = [cell hoverView:chd_collection_cell_color];
  499. hover.attributedText = [CHD_CollectionHelper hoverAtt:indexPath cell:cell cacheToObj:self];
  500. hover.hidden = ![CHD_HookHelper shareInstance].is_open_chdCollection;
  501. return cell;
  502. }
  503. //如果原代理未实现如下方法会主动添加一个空实现
  504. //iOS8以上
  505. - (void)collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
  506. {
  507. }
  508. //iOS8以下
  509. - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(UICollectionReusableView *)view forElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
  510. {
  511. }
  512. - (void)CHD_collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
  513. {
  514. [self CHD_collectionView:collectionView willDisplaySupplementaryView:view forElementKind:elementKind atIndexPath:indexPath];
  515. UIColor *sectionViewColor = chd_collection_header_color;
  516. NSString *Kind = @"Header";
  517. if ([elementKind isEqualToString:UICollectionElementKindSectionFooter]) {
  518. sectionViewColor = chd_collection_footer_color;
  519. Kind = @"Footer";
  520. }else if ([elementKind isEqualToString:@"HDDecorationViewKind"]){
  521. Kind = @"Decoration(装饰)";
  522. sectionViewColor = chd_collection_decoration_color;
  523. }
  524. UILabel *hover = [view hoverView:sectionViewColor];
  525. hover.attributedText = [CHD_MustrHelper getMustr:[NSString stringWithFormat:@"%@++%@++%@",Kind,NSStringFromClass([view class]),@(indexPath.section)] textColor:chd_collection_text_color backGroundColor:[sectionViewColor colorWithAlphaComponent:chd_collection_bg_alpha]];
  526. hover.hidden = ![CHD_HookHelper shareInstance].is_open_chdCollection;
  527. }
  528. - (void)CHD_collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(UICollectionReusableView *)view forElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
  529. {
  530. [self CHD_collectionView:collectionView didEndDisplayingSupplementaryView:view forElementOfKind:elementKind atIndexPath:indexPath];
  531. UIColor *sectionViewColor = chd_collection_header_color;
  532. NSString *Kind = @"Header";
  533. if ([elementKind isEqualToString:UICollectionElementKindSectionFooter]) {
  534. sectionViewColor = chd_collection_footer_color;
  535. Kind = @"Footer";
  536. }else if ([elementKind isEqualToString:@"HDDecorationViewKind"]){
  537. Kind = @"Decoration(装饰)";
  538. sectionViewColor = chd_collection_decoration_color;
  539. }
  540. UILabel *hover = [view hoverView:sectionViewColor];
  541. hover.attributedText = [CHD_MustrHelper getMustr:[NSString stringWithFormat:@"%@++%@++%@",Kind,NSStringFromClass([view class]),@(indexPath.section)] textColor:chd_collection_text_color backGroundColor:[sectionViewColor colorWithAlphaComponent:chd_collection_bg_alpha]];
  542. hover.hidden = ![CHD_HookHelper shareInstance].is_open_chdCollection;
  543. }
  544. @end