PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/UI7Kit/UI7TableView.m

https://gitlab.com/lisit1003/UI7Kit
Objective C | 471 lines | 334 code | 79 blank | 58 comment | 70 complexity | df5eb2326a474375e5a19a907fe4f16b MD5 | raw file
  1. //
  2. // UI7TableView.m
  3. // UI7Kit
  4. //
  5. // Created by Jeong YunWon on 13. 6. 12..
  6. // Copyright (c) 2013 youknowone.org. All rights reserved.
  7. //
  8. #import "UI7KitPrivate.h"
  9. #import "UI7Font.h"
  10. #import "UI7Color.h"
  11. #import "UI7TableView.h"
  12. CGFloat UI7TableViewGroupedTableSectionSeperatorHeight = 28.0f;
  13. @interface UITableViewCell (Accessor)
  14. @property(nonatomic,readonly) UITableView *tableView;
  15. @property(nonatomic,readonly) NSIndexPath *indexPath;
  16. @end
  17. @interface UITableView (Private)
  18. - (void)_updateVisibleCellsNow:(BOOL)flag;
  19. @end
  20. @implementation UITableView (Patch)
  21. UIColor *UI7TableViewGroupedViewPatternColor = nil;
  22. - (id)__initWithCoder:(NSCoder *)aDecoder { assert(NO); return nil; }
  23. - (id)__initWithFrame:(CGRect)frame { assert(NO); return nil; }
  24. - (id)__initWithFrame:(CGRect)frame style:(UITableViewStyle)style { assert(NO); return nil; }
  25. - (void)__setDelegate:(id<UITableViewDelegate>)delegate { assert(NO); return; }
  26. - (void)__setDataSource:(id<UITableViewDataSource>)dataSource { assert(NO); return; }
  27. - (UITableViewStyle)__style { assert(NO); return 0; }
  28. - (void)__updateVisibleCellsNow:(BOOL)flag { assert(NO); }
  29. - (void)_tableViewInit {
  30. }
  31. - (void)_tableViewInitGrouped {
  32. if (UI7TableViewGroupedViewPatternColor == nil) {
  33. UI7TableViewGroupedViewPatternColor = [[[UITableView alloc] __initWithFrame:CGRectZero style:UITableViewStyleGrouped] autorelease].backgroundColor;
  34. }
  35. if (![NSStringFromClass([self class]) hasPrefix:@"AB"]) {
  36. self.backgroundView = nil;
  37. }
  38. if (self.separatorStyle == UITableViewCellSeparatorStyleSingleLineEtched) {
  39. self.separatorStyle = UITableViewCellSeparatorStyleNone;
  40. }
  41. }
  42. - (void)awakeFromNib { }
  43. - (id)__dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath {
  44. return [self dequeueReusableCellWithIdentifier:identifier];
  45. }
  46. @end
  47. //@implementation NSCoder (UI7TableView)
  48. //
  49. //- (NSInteger)__decodeIntegerForKey:(NSString *)key { assert(NO); }
  50. //
  51. //- (NSInteger)_UI7TableView_decodeIntegerForKey:(NSString *)key {
  52. // if ([key isEqualToString:@"UIStyle"]) {
  53. // return (NSInteger)UITableViewStylePlain;
  54. // }
  55. // return [self __decodeIntegerForKey:key];
  56. //}
  57. //
  58. //@end
  59. @protocol UI7TableViewDelegate
  60. - (UIView *)__tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
  61. - (UIView *)__tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;
  62. - (CGFloat)__tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
  63. - (CGFloat)__tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
  64. @end
  65. @implementation UI7TableView
  66. + (void)initialize {
  67. if (self == [UI7TableView class]) {
  68. Class target = [UITableView class];
  69. [target copyToSelector:@selector(__initWithCoder:) fromSelector:@selector(initWithCoder:)];
  70. [target copyToSelector:@selector(__initWithFrame:) fromSelector:@selector(initWithFrame:)];
  71. [target copyToSelector:@selector(__initWithFrame:style:) fromSelector:@selector(initWithFrame:style:)];
  72. [target copyToSelector:@selector(__setDelegate:) fromSelector:@selector(setDelegate:)];
  73. [target copyToSelector:@selector(__setDataSource:) fromSelector:@selector(setDataSource:)];
  74. [target copyToSelector:@selector(__style) fromSelector:@selector(style)];
  75. [target copyToSelector:@selector(__updateVisibleCellsNow:) fromSelector:@selector(_updateVisibleCellsNow:)];
  76. }
  77. }
  78. + (void)patch {
  79. Class target = [UITableView class];
  80. [self exportSelector:@selector(initWithCoder:) toClass:target];
  81. [self exportSelector:@selector(initWithFrame:) toClass:target];
  82. [self exportSelector:@selector(initWithFrame:style:) toClass:target];
  83. [self exportSelector:@selector(awakeFromNib) toClass:target];
  84. [self exportSelector:@selector(setDelegate:) toClass:target];
  85. [self exportSelector:@selector(setDataSource:) toClass:target];
  86. [self exportSelector:@selector(style) toClass:target];
  87. [self exportSelector:@selector(_updateVisibleCellsNow:) toClass:target];
  88. if (![target methodObjectForSelector:@selector(dequeueReusableCellWithIdentifier:forIndexPath:)]) {
  89. [target addMethodForSelector:@selector(dequeueReusableCellWithIdentifier:forIndexPath:) fromMethod:[self methodObjectForSelector:@selector(__dequeueReusableCellWithIdentifier:forIndexPath:)]];
  90. }
  91. }
  92. - (id)initWithCoder:(NSCoder *)aDecoder {
  93. // UITableViewStyle style = UITableViewStylePlain;
  94. // if ([aDecoder containsValueForKey:@"UIStyle"]) {
  95. // style = [aDecoder decodeIntegerForKey:@"UIStyle"];
  96. // if (style == UITableViewStyleGrouped) {
  97. // NSAMethod *decode = [aDecoder.class methodObjectForSelector:@selector(decodeIntegerForKey:)];
  98. // [aDecoder.class methodObjectForSelector:@selector(__decodeIntegerForKey:)].implementation = decode.implementation;
  99. // decode.implementation = [aDecoder.class methodObjectForSelector:@selector(_UI7TableView_decodeIntegerForKey:)].implementation;
  100. // }
  101. // }
  102. self = [self __initWithCoder:aDecoder];
  103. // if (style == UITableViewStyleGrouped) {
  104. // NSAMethod *decode = [aDecoder.class methodObjectForSelector:@selector(decodeIntegerForKey:)];
  105. // decode.implementation = [aDecoder.class methodImplementationForSelector:@selector(__decodeIntegerForKey:)];
  106. // if (self) {
  107. // [UI7TableViewStyleIsGrouped setObject:@(YES) forKey:self.pointerString];
  108. // }
  109. // }
  110. if (self) {
  111. if (self.__style == UITableViewStyleGrouped) {
  112. [self _tableViewInitGrouped];
  113. UIColor *color = [aDecoder decodeObjectForKey:@"UIBackgroundColor"];
  114. if (color == UI7TableViewGroupedViewPatternColor) {
  115. if (![NSStringFromClass([self class]) hasPrefix:@"AB"]) {
  116. self.backgroundColor = [UI7Color groupedTableViewSectionBackgroundColor];
  117. }
  118. }
  119. }
  120. [self _tableViewInit];
  121. }
  122. return self;
  123. }
  124. - (id)initWithFrame:(CGRect)frame {
  125. self = [self __initWithFrame:frame];
  126. if (self) {
  127. [self _tableViewInit];
  128. }
  129. return self;
  130. }
  131. - (id)initWithFrame:(CGRect)frame style:(UITableViewStyle)style {
  132. self = [self __initWithFrame:frame style:style];
  133. if (self) {
  134. self.backgroundColor = [UI7Color whiteColor];
  135. if (style == UITableViewStyleGrouped) {
  136. self.backgroundColor = [UI7Color groupTableViewBackgroundColor];
  137. [self _tableViewInitGrouped];
  138. }
  139. [self _tableViewInit];
  140. }
  141. return self;
  142. }
  143. - (void)awakeFromNib {
  144. if (self.__style == UITableViewStyleGrouped && self.superview == nil && [self.backgroundColor isEqual:[UIColor clearColor]]) {
  145. self.backgroundColor = [UI7Color groupTableViewBackgroundColor];
  146. }
  147. }
  148. - (UITableViewStyle)style {
  149. return UITableViewStylePlain;
  150. }
  151. CGFloat _UI7TableViewDelegateNoHeightForHeaderFooterInSection(id self, SEL _cmd, UITableView *tableView, NSUInteger section) {
  152. return -1.0f;
  153. }
  154. CGFloat _UI7TableViewDelegateHeightForHeaderInSection(id self, SEL _cmd, UITableView *tableView, NSUInteger section) {
  155. CGFloat height = [self __tableView:tableView heightForHeaderInSection:section];
  156. if (height != -1.0f) {
  157. if (tableView.__style == UITableViewStyleGrouped) {
  158. height += UI7TableViewGroupedTableSectionSeperatorHeight;
  159. }
  160. return height;
  161. }
  162. height = .0f;
  163. NSString *title = nil;
  164. if ([tableView.dataSource respondsToSelector:@selector(tableView:titleForHeaderInSection:)]) {
  165. title = [tableView.dataSource tableView:tableView titleForHeaderInSection:section];
  166. }
  167. if (tableView.__style == UITableViewStyleGrouped) {
  168. UIFont *font = [UI7Font systemFontOfSize:14.0 attribute:UI7FontAttributeNone];
  169. CGSize size = [title sizeWithFont:font constrainedToSize:CGSizeMake(tableView.frame.size.width, INFINITY)];
  170. if (size.height > 0) {
  171. height = UI7TableViewGroupedTableSectionSeperatorHeight + ceilf(size.height) + 2.0f;
  172. } else {
  173. height = UI7TableViewGroupedTableSectionSeperatorHeight;
  174. }
  175. } else {
  176. if (title.length > 0) {
  177. height = tableView.sectionHeaderHeight;
  178. }
  179. }
  180. return height;
  181. }
  182. CGFloat _UI7TableViewDelegateHeightForFooterInSection(id self, SEL _cmd, UITableView *tableView, NSUInteger section) {
  183. CGFloat height = [self __tableView:tableView heightForFooterInSection:section];
  184. if (height != -1.0f) {
  185. return height;
  186. }
  187. NSString *title = nil;
  188. if ([tableView.dataSource respondsToSelector:@selector(tableView:titleForFooterInSection:)]) {
  189. title = [tableView.dataSource tableView:tableView titleForFooterInSection:section];
  190. }
  191. if (tableView.__style == UITableViewStyleGrouped) {
  192. UIFont *font = [UI7Font systemFontOfSize:14.0 attribute:UI7FontAttributeNone];
  193. CGSize size = [title sizeWithFont:font constrainedToSize:CGSizeMake(tableView.frame.size.width, INFINITY)];
  194. if (size.height > 0) {
  195. return ceilf(size.height) + 7.0f;
  196. } else {
  197. return .0f;
  198. }
  199. }
  200. if (title.length > 0) {
  201. return tableView.sectionFooterHeight;
  202. }
  203. return .0;
  204. }
  205. UIView *_UI7TableViewDelegateNilViewForHeaderFooterInSection(id self, SEL _cmd, UITableView *tableView, NSUInteger section) {
  206. return nil;
  207. }
  208. UIView *_UI7TableViewDelegateViewForHeaderInSection(id self, SEL _cmd, UITableView *tableView, NSUInteger section) {
  209. UIView *view = [self __tableView:tableView viewForHeaderInSection:section];
  210. if (view) {
  211. return view;
  212. }
  213. if ([tableView associatedObjectForKey:@"recursiveViewForHeader"]) {
  214. return nil;
  215. }
  216. BOOL grouped = tableView.__style == UITableViewStyleGrouped;
  217. [tableView setAssociatedObject:@(YES) forKey:@"recursiveViewForHeader"];
  218. CGFloat height = [tableView.delegate tableView:tableView heightForHeaderInSection:section];
  219. [tableView setAssociatedObject:nil forKey:@"recursiveViewForHeader"];
  220. NSString *title = nil;
  221. if ([tableView.dataSource respondsToSelector:@selector(tableView:titleForHeaderInSection:)]) {
  222. title = [tableView.dataSource tableView:tableView titleForHeaderInSection:section];
  223. }
  224. if (title == nil) {
  225. if (grouped) {
  226. UIView *header = [[[UIView alloc] initWithFrame:CGRectMake(.0, .0, tableView.frame.size.width - 12.0f, UI7TableViewGroupedTableSectionSeperatorHeight)] autorelease];
  227. header.backgroundColor = [UI7Color groupedTableViewSectionBackgroundColor];
  228. return header;
  229. } else {
  230. return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
  231. }
  232. }
  233. CGFloat groupHeight = grouped ? UI7TableViewGroupedTableSectionSeperatorHeight : .0f;
  234. if (grouped) {
  235. UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(12.0f, groupHeight, tableView.frame.size.width - 12.0f, height - groupHeight)] autorelease];
  236. label.numberOfLines = 100;
  237. label.text = [title uppercaseString];
  238. label.font = [UI7Font systemFontOfSize:14.0 attribute:UI7FontAttributeNone];
  239. label.textColor = [UIColor colorWith8bitWhite:77 alpha:255];
  240. label.backgroundColor = [UIColor clearColor];
  241. view = [[[UIView alloc] initWithFrame:CGRectMake(.0, .0, tableView.frame.size.width, height)] autorelease];
  242. [view addSubview:label];
  243. view.backgroundColor = [UI7Color groupedTableViewSectionBackgroundColor];
  244. } else {
  245. UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(.0, groupHeight, tableView.frame.size.width, height - groupHeight)] autorelease];
  246. label.text = [@" " stringByAppendingString:title];
  247. label.font = [UI7Font systemFontOfSize:14.0 attribute:UI7FontAttributeMedium];
  248. label.backgroundColor = [UIColor colorWith8bitRed:248 green:248 blue:248 alpha:255];
  249. view = label;
  250. }
  251. return view;
  252. }
  253. UIView *_UI7TableViewDelegateViewForFooterInSection(id self, SEL _cmd, UITableView *tableView, NSUInteger section) {
  254. UIView *view = [self __tableView:tableView viewForFooterInSection:section];
  255. if (view) {
  256. return view;
  257. }
  258. if ([tableView associatedObjectForKey:@"recursiveViewForFooter"]) {
  259. return nil;
  260. }
  261. [tableView setAssociatedObject:@(YES) forKey:@"recursiveViewForFooter"];
  262. CGFloat height = [tableView.delegate tableView:tableView heightForFooterInSection:section];
  263. [tableView setAssociatedObject:nil forKey:@"recursiveViewForFooter"];
  264. NSString *title = nil;
  265. if ([tableView.dataSource respondsToSelector:@selector(tableView:titleForFooterInSection:)]) {
  266. title = [tableView.dataSource tableView:tableView titleForFooterInSection:section];
  267. }
  268. if (title == nil) {
  269. return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
  270. }
  271. if (tableView.__style == UITableViewStyleGrouped) {
  272. UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(12.0f, .0f, tableView.frame.size.width - 12.0f, height)] autorelease];
  273. label.numberOfLines = 100;
  274. label.text = title;
  275. label.font = [UI7Font systemFontOfSize:15.0 attribute:UI7FontAttributeNone];
  276. label.textColor = [UIColor colorWith8bitWhite:77 alpha:255];
  277. label.backgroundColor = [UIColor clearColor];
  278. view = [[[UIView alloc] initWithFrame:CGRectMake(.0, .0, tableView.frame.size.width, height)] autorelease];
  279. [view addSubview:label];
  280. view.backgroundColor = [UI7Color groupedTableViewSectionBackgroundColor];
  281. } else {
  282. UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(.0, .0, tableView.frame.size.width, height)] autorelease];
  283. label.text = [@" " stringByAppendingString:title]; // TODO: do this pretty later
  284. label.font = [UI7Font systemFontOfSize:14.0 attribute:UI7FontAttributeMedium];
  285. label.backgroundColor = [UIColor colorWith8bitRed:248 green:248 blue:248 alpha:255];
  286. view = label;
  287. }
  288. return view;
  289. }
  290. - (void)setDataSource:(id<UITableViewDataSource>)dataSource {
  291. [self __setDataSource:dataSource];
  292. if (self.delegate) {
  293. id delegate = self.delegate;
  294. [self __setDelegate:nil];
  295. self.delegate = delegate;
  296. }
  297. }
  298. - (void)setDelegate:(id<UITableViewDelegate>)delegate {
  299. if (self.delegate) {
  300. // Class delegateClass = [(NSObject *)self.delegate class];
  301. // if ([delegateClass methodImplementationForSelector:@selector(tableView:viewForHeaderInSection:)] == (IMP)UI7TableViewDelegateViewForHeaderInSection) {
  302. // // TODO: probably we should remove this methods.
  303. // // class_removeMethods(, )
  304. // }
  305. }
  306. if (delegate && ![(NSObject *)[delegate class] associatedObjectForKey:@"UI7KitPatched"]) {
  307. Class delegateClass = [(NSObject *)delegate class];
  308. // fill the empty impl if not implemented
  309. if (![delegate respondsToSelector:@selector(tableView:heightForHeaderInSection:)]) {
  310. [delegateClass addMethodForSelector:@selector(tableView:heightForHeaderInSection:) implementation:(IMP)_UI7TableViewDelegateNoHeightForHeaderFooterInSection types:@"f16@0:4@8i12"];
  311. }
  312. if (![delegate respondsToSelector:@selector(tableView:viewForHeaderInSection:)]) {
  313. [delegateClass addMethodForSelector:@selector(tableView:viewForHeaderInSection:) implementation:(IMP)_UI7TableViewDelegateNilViewForHeaderFooterInSection types:@"@16@0:4@8i12"];
  314. }
  315. if (![delegate respondsToSelector:@selector(tableView:heightForFooterInSection:)]) {
  316. [delegateClass addMethodForSelector:@selector(tableView:heightForFooterInSection:) implementation:(IMP)_UI7TableViewDelegateNoHeightForHeaderFooterInSection types:@"f16@0:4@8i12"];
  317. }
  318. if (![delegate respondsToSelector:@selector(tableView:viewForFooterInSection:)]) {
  319. [delegateClass addMethodForSelector:@selector(tableView:viewForFooterInSection:) implementation:(IMP)_UI7TableViewDelegateNilViewForHeaderFooterInSection types:@"@16@0:4@8i12"];
  320. }
  321. // copy existing impl
  322. {
  323. SEL fromSelector = [delegate respondsToSelector:@selector(__tableView:heightForHeaderInSection:)] ? @selector(__tableView:heightForHeaderInSection:) : @selector(tableView:heightForHeaderInSection:);
  324. [delegateClass addMethodForSelector:@selector(__tableView:heightForHeaderInSection:) fromMethod:[delegateClass methodObjectForSelector:fromSelector]];
  325. }
  326. {
  327. SEL fromSelector = [delegate respondsToSelector:@selector(__tableView:viewForHeaderInSection:)] ? @selector(__tableView:viewForHeaderInSection:) : @selector(tableView:viewForHeaderInSection:);
  328. [delegateClass addMethodForSelector:@selector(__tableView:viewForHeaderInSection:) fromMethod:[delegateClass methodObjectForSelector:fromSelector]];
  329. }
  330. {
  331. SEL fromSelector = [delegate respondsToSelector:@selector(__tableView:heightForFooterInSection:)] ? @selector(__tableView:heightForFooterInSection:) : @selector(tableView:heightForFooterInSection:);
  332. [delegateClass addMethodForSelector:@selector(__tableView:heightForFooterInSection:) fromMethod:[delegateClass methodObjectForSelector:fromSelector]];
  333. }
  334. {
  335. SEL fromSelector = [delegate respondsToSelector:@selector(__tableView:viewForFooterInSection:)] ? @selector(__tableView:viewForFooterInSection:) : @selector(tableView:viewForFooterInSection:);
  336. [delegateClass addMethodForSelector:@selector(__tableView:viewForFooterInSection:) fromMethod:[delegateClass methodObjectForSelector:fromSelector]];
  337. }
  338. // subclass-safe patches
  339. [delegateClass addMethodForSelector:@selector(tableView:heightForHeaderInSection:) implementation:(IMP)_UI7TableViewDelegateHeightForHeaderInSection types:@"@16@0:4@8i12"];
  340. [delegateClass methodObjectForSelector:@selector(tableView:heightForHeaderInSection:)].implementation = (IMP)_UI7TableViewDelegateHeightForHeaderInSection;
  341. [delegateClass addMethodForSelector:@selector(tableView:viewForHeaderInSection:) implementation:(IMP)_UI7TableViewDelegateViewForHeaderInSection types:@"@16@0:4@8i12"];
  342. [delegateClass methodObjectForSelector:@selector(tableView:viewForHeaderInSection:)].implementation = (IMP)_UI7TableViewDelegateViewForHeaderInSection;
  343. [delegateClass addMethodForSelector:@selector(tableView:heightForFooterInSection:) implementation:(IMP)_UI7TableViewDelegateHeightForFooterInSection types:@"@16@0:4@8i12"];
  344. [delegateClass methodObjectForSelector:@selector(tableView:heightForFooterInSection:)].implementation = (IMP)_UI7TableViewDelegateHeightForFooterInSection;
  345. [delegateClass addMethodForSelector:@selector(tableView:viewForFooterInSection:) implementation:(IMP)_UI7TableViewDelegateViewForFooterInSection types:@"@16@0:4@8i12"];
  346. [delegateClass methodObjectForSelector:@selector(tableView:viewForFooterInSection:)].implementation = (IMP)_UI7TableViewDelegateViewForFooterInSection;
  347. [(NSObject *)[delegate class] setAssociatedObject:@(YES) forKey:@"UI7KitPatched"];
  348. }
  349. [self __setDelegate:delegate];
  350. }
  351. - (void)_updateVisibleCellsNow:(BOOL)flag {
  352. // NOTE: Workaround for indexPathsForVisibleRows overriding, especially for Sensible table view.
  353. if ([self associatedObjectForKey:@"UI7TableViewCellUpdating"]) {
  354. return;
  355. }
  356. [self setAssociatedObject:@(YES) forKey:@"UI7TableViewCellUpdating"];
  357. [self __updateVisibleCellsNow:flag];
  358. for (NSIndexPath *path in self.indexPathsForVisibleRows) {
  359. UITableViewCell *cell = [self cellForRowAtIndexPath:path];
  360. [cell _tintColorUpdated];
  361. }
  362. [self setAssociatedObject:nil forKey:@"UI7TableViewCellUpdating"];
  363. }
  364. // TODO: ok.. do this next time.
  365. //- (BOOL)_delegateWantsHeaderViewForSection:(NSUInteger)section {
  366. // return YES;
  367. //}
  368. //
  369. //- (BOOL)_delegateWantsHeaderTitleForSection:(NSUInteger)section {
  370. // return YES;
  371. //}
  372. //
  373. //- (UITableViewHeaderFooterView *)headerViewForSection:(NSInteger)section {
  374. // UITableViewHeaderFooterView *view = [super headerViewForSection:section];
  375. //
  376. // return view;
  377. //}
  378. @end
  379. @implementation UI7TableViewController
  380. - (id)initWithCoder:(NSCoder *)aDecoder {
  381. self = [super initWithCoder:aDecoder];
  382. return self;
  383. }
  384. - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
  385. CGFloat height = [super tableView:tableView heightForHeaderInSection:section];
  386. return height;
  387. }
  388. - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
  389. UIView *view = [super tableView:tableView viewForHeaderInSection:section];
  390. return view;
  391. }
  392. @end