省钱达人

UITableView+SDAutoTableViewCellHeight.m 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. //
  2. // UITableView+SDAutoTableViewCellHeight.m
  3. // SDAutoLayout 测试 Demo
  4. //
  5. // Created by aier on 15/11/1.
  6. // Copyright © 2015年 gsd. All rights reserved.
  7. //
  8. /*
  9. *********************************************************************************
  10. * *
  11. * 在您使用此自动布局库的过程中如果出现bug请及时以以下任意一种方式联系我们,我们会及时修复bug并 *
  12. * 帮您解决问题。 *
  13. * QQ : 2689718696(gsdios) *
  14. * Email : gsdios@126.com *
  15. * GitHub: https://github.com/gsdios *
  16. * 新浪微博:GSD_iOS *
  17. * *
  18. *********************************************************************************
  19. */
  20. #import "UITableView+SDAutoTableViewCellHeight.h"
  21. #import "UIView+SDAutoLayout.h"
  22. #import <objc/runtime.h>
  23. @implementation SDCellAutoHeightManager
  24. {
  25. NSMutableDictionary *_cacheDictionary;
  26. UITableView *_modelTableview;
  27. }
  28. - (instancetype)init
  29. {
  30. if (self = [super init]) {
  31. _modelTableview = [UITableView new];
  32. _cacheDictionary = [NSMutableDictionary new];
  33. }
  34. return self;
  35. }
  36. - (instancetype)initWithCellClass:(Class)cellClass
  37. {
  38. if (self = [super init]) {
  39. _modelTableview = [UITableView new];
  40. [self registerCellWithCellClass:cellClass];
  41. _cacheDictionary = [NSMutableDictionary new];
  42. }
  43. return self;
  44. }
  45. - (instancetype)initWithCellClasses:(NSArray *)cellClassArray
  46. {
  47. if (self = [super init]) {
  48. _modelTableview = [UITableView new];
  49. [cellClassArray enumerateObjectsUsingBlock:^(Class obj, NSUInteger idx, BOOL *stop) {
  50. [self registerCellWithCellClass:obj];
  51. }];
  52. _cacheDictionary = [NSMutableDictionary new];
  53. }
  54. return self;
  55. }
  56. - (void)registerCellWithCellClass:(Class)cellClass
  57. {
  58. [_modelTableview registerClass:cellClass forCellReuseIdentifier:NSStringFromClass(cellClass)];
  59. self.modelCell = [_modelTableview dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass)];
  60. if (!self.modelCell.contentView.subviews.count) {
  61. self.modelCell = nil;
  62. [_modelTableview registerNib:[UINib nibWithNibName:NSStringFromClass(cellClass) bundle:nil] forCellReuseIdentifier:NSStringFromClass(cellClass)];
  63. self.modelCell = [_modelTableview dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass)];
  64. }
  65. }
  66. + (instancetype)managerWithCellClass:(Class)cellClass
  67. {
  68. SDCellAutoHeightManager *manager = [[self alloc] initWithCellClass:cellClass];
  69. return manager;
  70. }
  71. - (UITableViewCell *)modelCell
  72. {
  73. if (_modelCell.tag != kSDModelCellTag) {
  74. _modelCell.contentView.tag = kSDModelCellTag;
  75. }
  76. return _modelCell;
  77. }
  78. - (void)clearHeightCache
  79. {
  80. [_cacheDictionary removeAllObjects];
  81. }
  82. - (void)clearHeightCacheOfIndexPaths:(NSArray *)indexPaths
  83. {
  84. [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
  85. NSString *cacheKey = [NSString stringWithFormat:@"%ld%ld", (long)indexPath.section, (long)indexPath.row];
  86. [_cacheDictionary removeObjectForKey:cacheKey];
  87. }];
  88. }
  89. - (NSNumber *)heightCacheForIndexPath:(NSIndexPath *)indexPath
  90. {
  91. NSString *cacheKey = [NSString stringWithFormat:@"%ld%ld", (long)indexPath.section, (long)indexPath.row];
  92. return (NSNumber *)[_cacheDictionary objectForKey:cacheKey];
  93. }
  94. - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath
  95. {
  96. NSNumber *cacheHeight = [self heightCacheForIndexPath:indexPath];
  97. if (cacheHeight) {
  98. return [cacheHeight floatValue];
  99. } else {
  100. if (!self.modelCell) {
  101. return 0;
  102. }
  103. if (model && keyPath) {
  104. [self.modelCell setValue:model forKey:keyPath];
  105. }
  106. #ifdef SDDebugWithAssert
  107. /*
  108. 如果程序卡在了这里说明你的cell还没有调用“setupAutoHeightWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin”方法或者你传递的bottomView为nil,请检查并修改。例:
  109. //注意:bottomView不能为nil
  110. [cell setupAutoHeightWithBottomView:bottomView bottomMargin:bottomMargin];
  111. */
  112. NSAssert(self.modelCell.sd_bottomViewsArray.count, @">>>>>> 你的cell还没有调用“setupAutoHeightWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin”方法或者你传递的bottomView为nil,请检查并修改");
  113. #endif
  114. [self.modelCell.contentView layoutSubviews];
  115. NSString *cacheKey = [NSString stringWithFormat:@"%ld%ld", (long)indexPath.section, (long)indexPath.row];
  116. [_cacheDictionary setObject:@(self.modelCell.autoHeight) forKey:cacheKey];
  117. return self.modelCell.autoHeight;
  118. }
  119. }
  120. - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath cellClass:(Class)cellClass
  121. {
  122. if (![self.modelCell isKindOfClass:cellClass]) {
  123. self.modelCell = nil;
  124. self.modelCell = [_modelTableview dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass)];
  125. if (!self.modelCell) {
  126. [self registerCellWithCellClass:cellClass];
  127. }
  128. _modelCell.contentView.tag = kSDModelCellTag;
  129. }
  130. if (self.modelCell.contentView.width != self.contentViewWidth) {
  131. _modelCell.contentView.width = self.contentViewWidth;
  132. }
  133. return [self cellHeightForIndexPath:indexPath model:model keyPath:keyPath];
  134. }
  135. - (void)setContentViewWidth:(CGFloat)contentViewWidth
  136. {
  137. if (_contentViewWidth == contentViewWidth) return;
  138. [self clearHeightCache];
  139. _contentViewWidth = contentViewWidth;
  140. self.modelCell.contentView.width = self.contentViewWidth;
  141. }
  142. @end
  143. @implementation UITableView (SDAutoTableViewCellHeight)
  144. + (void)load {
  145. static dispatch_once_t onceToken;
  146. dispatch_once(&onceToken, ^{
  147. NSArray *selStringsArray = @[@"reloadData", @"reloadRowsAtIndexPaths:withRowAnimation:"];
  148. [selStringsArray enumerateObjectsUsingBlock:^(NSString *selString, NSUInteger idx, BOOL *stop) {
  149. NSString *mySelString = [@"sd_" stringByAppendingString:selString];
  150. Method originalMethod = class_getInstanceMethod(self, NSSelectorFromString(selString));
  151. Method myMethod = class_getInstanceMethod(self, NSSelectorFromString(mySelString));
  152. method_exchangeImplementations(originalMethod, myMethod);
  153. }];
  154. });
  155. }
  156. - (void)sd_reloadData
  157. {
  158. [self.cellAutoHeightManager clearHeightCache];
  159. [self sd_reloadData];
  160. }
  161. - (void)sd_reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
  162. {
  163. [self.cellAutoHeightManager clearHeightCacheOfIndexPaths:indexPaths];
  164. [self sd_reloadRowsAtIndexPaths:indexPaths withRowAnimation:animation];
  165. }
  166. /*
  167. * 下一步即将实现的功能
  168. - (void)sd_insertRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
  169. {
  170. [self sd_insertRowsAtIndexPaths:indexPaths withRowAnimation:animation];
  171. }
  172. - (void)sd_deleteRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
  173. {
  174. [self sd_deleteRowsAtIndexPaths:indexPaths withRowAnimation:animation];
  175. }
  176. - (void)sd_moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath
  177. {
  178. [self sd_moveRowAtIndexPath:indexPath toIndexPath:newIndexPath];
  179. }
  180. */
  181. - (void)startAutoCellHeightWithCellClass:(Class)cellClass contentViewWidth:(CGFloat)contentViewWidth NS_DEPRECATED(10_0, 10_4, 6_0, 6_0)
  182. {
  183. if (!self.cellAutoHeightManager) {
  184. self.cellAutoHeightManager = [SDCellAutoHeightManager managerWithCellClass:cellClass];
  185. }
  186. self.cellAutoHeightManager.contentViewWidth = contentViewWidth;
  187. }
  188. - (void)startAutoCellHeightWithCellClasses:(NSArray *)cellClassArray contentViewWidth:(CGFloat)contentViewWidth NS_DEPRECATED(10_0, 10_4, 6_0, 6_0)
  189. {
  190. if (!self.cellAutoHeightManager) {
  191. self.cellAutoHeightManager = [[SDCellAutoHeightManager alloc] initWithCellClasses:cellClassArray];
  192. }
  193. self.cellAutoHeightManager.contentViewWidth = contentViewWidth;
  194. }
  195. - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath NS_DEPRECATED(10_0, 10_4, 6_0, 6_0)
  196. {
  197. return [self.cellAutoHeightManager cellHeightForIndexPath:indexPath model:model keyPath:keyPath];
  198. }
  199. - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath cellClass:(Class)cellClass NS_DEPRECATED(10_0, 10_4, 6_0, 6_0)
  200. {
  201. return [self.cellAutoHeightManager cellHeightForIndexPath:indexPath model:model keyPath:keyPath cellClass:cellClass];
  202. }
  203. - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath cellClass:(Class)cellClass contentViewWidth:(CGFloat)contentViewWidth
  204. {
  205. if (!self.cellAutoHeightManager) {
  206. self.cellAutoHeightManager = [[SDCellAutoHeightManager alloc] init];
  207. }
  208. self.cellAutoHeightManager.contentViewWidth = contentViewWidth;
  209. return [self.cellAutoHeightManager cellHeightForIndexPath:indexPath model:model keyPath:keyPath cellClass:cellClass];
  210. }
  211. - (SDCellAutoHeightManager *)cellAutoHeightManager
  212. {
  213. return objc_getAssociatedObject(self, _cmd);
  214. }
  215. - (void)setCellAutoHeightManager:(SDCellAutoHeightManager *)cellAutoHeightManager
  216. {
  217. objc_setAssociatedObject(self, @selector(cellAutoHeightManager), cellAutoHeightManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  218. }
  219. @end
  220. @implementation UITableViewController (SDTableViewControllerAutoCellHeight)
  221. - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellContentViewWidth:(CGFloat)width
  222. {
  223. return [self cellHeightForIndexPath:indexPath cellContentViewWidth:width tableView:self.tableView];
  224. }
  225. @end
  226. @implementation NSObject (SDAnyObjectAutoCellHeight)
  227. - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellContentViewWidth:(CGFloat)width tableView:(UITableView *)tableView
  228. {
  229. if (!tableView.cellAutoHeightManager) {
  230. tableView.cellAutoHeightManager = [[SDCellAutoHeightManager alloc] init];
  231. }
  232. if (tableView.cellAutoHeightManager.contentViewWidth != width) {
  233. tableView.cellAutoHeightManager.contentViewWidth = width;
  234. [tableView.cellAutoHeightManager clearHeightCache];
  235. }
  236. if ([tableView.cellAutoHeightManager heightCacheForIndexPath:indexPath]) {
  237. return [[tableView.cellAutoHeightManager heightCacheForIndexPath:indexPath] floatValue];
  238. }
  239. UITableViewCell *cell = [tableView.dataSource tableView:tableView cellForRowAtIndexPath:indexPath];
  240. tableView.cellAutoHeightManager.modelCell = cell;
  241. if (cell.contentView.width != width) {
  242. cell.contentView.width = width;
  243. }
  244. return [[tableView cellAutoHeightManager] cellHeightForIndexPath:indexPath model:nil keyPath:nil];
  245. }
  246. @end
  247. // 版权属于原作者
  248. // http://code4app.com (cn) http://code4app.net (en)
  249. // 发布代码于最专业的源码分享网站: Code4App.com