├── LightweightUITableViewDemo ├── LightweightUITableViewDemo │ ├── Resources │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ ├── 4.jpg │ │ ├── 5.jpg │ │ ├── 6.jpg │ │ ├── 7.jpg │ │ ├── 8.jpg │ │ ├── 9.jpg │ │ ├── 10.jpg │ │ ├── cmjLogo120.png │ │ ├── AutoHeightCell.gif │ │ └── Persons.plist │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── cmjLogo120.png │ │ │ ├── cmjLogo180.png │ │ │ └── Contents.json │ ├── Controllers │ │ ├── KCMainViewController.h │ │ ├── KCAutoHeightTableViewController2.h │ │ ├── KCAutoHeightTableViewController1.h │ │ ├── KCAutoHeightTableViewController1.m │ │ ├── KCAutoHeightTableViewController2.m │ │ └── KCMainViewController.m │ ├── Services │ │ ├── KCPersonService.h │ │ └── KCPersonService.m │ ├── Other │ │ ├── AppDelegate.h │ │ ├── main.m │ │ └── AppDelegate.m │ ├── Views │ │ ├── KCCardTableViewCell1.h │ │ ├── KCCardTableViewCell2.h │ │ ├── KCCardTableViewCell2.m │ │ ├── KCCardTableViewCell1.m │ │ └── KCCardTableViewCell2.xib │ ├── Models │ │ ├── KCPerson.m │ │ └── KCPerson.h │ ├── Info.plist │ └── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.xib ├── LightweightUITableViewDemo.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── project.pbxproj ├── LightweightUITableView │ ├── KCTableViewArrayDataSourceWithCommitEditingStyle.h │ ├── KCLightweightUITableView.h │ ├── KCTableViewArrayDataSourceWithCommitEditingStyle.m │ ├── KCTableViewController.h │ ├── UIView+KC.h │ ├── KCTableViewCell.h │ ├── KCTableViewController.m │ ├── UITableViewCell+KC.h │ ├── UITableView+KC.h │ ├── UIView+KC.m │ ├── UITableViewCell+KC.m │ ├── KCTableViewCell.m │ ├── KCTableViewArrayDataSource.h │ ├── KCTableViewArrayDataSource.m │ ├── KCTableViewDelegate.h │ ├── KCTableViewDelegate.m │ └── UITableView+KC.m └── LightweightUITableViewDemoTests │ ├── Info.plist │ └── LightweightUITableViewDemoTests.m ├── .gitignore ├── LICENSE └── README.md /LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/1.jpg -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/2.jpg -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/3.jpg -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/4.jpg -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/5.jpg -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/6.jpg -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/7.jpg -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/8.jpg -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/9.jpg -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/10.jpg -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/cmjLogo120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/cmjLogo120.png -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/AutoHeightCell.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/AutoHeightCell.gif -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Images.xcassets/AppIcon.appiconset/cmjLogo120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Images.xcassets/AppIcon.appiconset/cmjLogo120.png -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Images.xcassets/AppIcon.appiconset/cmjLogo180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenshincui/LightweightUITableView/HEAD/LightweightUITableViewDemo/LightweightUITableViewDemo/Images.xcassets/AppIcon.appiconset/cmjLogo180.png -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Controllers/KCMainViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/17. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 通过数据源和代理对象给控制器瘦身 8 | 9 | #import 10 | 11 | @interface KCMainViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Services/KCPersonService.h: -------------------------------------------------------------------------------- 1 | // 2 | // KCPersonService.h 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/18. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface KCPersonService : NSObject 12 | 13 | +(NSArray *)requestPersons; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Controllers/KCAutoHeightTableViewController2.h: -------------------------------------------------------------------------------- 1 | // 2 | // KCAutoHeightTableViewController2.h 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/18. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import "KCTableViewController.h" 10 | 11 | @interface KCAutoHeightTableViewController2 : KCTableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Other/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/17. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Controllers/KCAutoHeightTableViewController1.h: -------------------------------------------------------------------------------- 1 | // 2 | // KCAutHeightTableViewController.h 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/17. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 自动计算Cell行高(使用frame计算) 8 | 9 | #import 10 | #import "KCTableViewController.h" 11 | 12 | @interface KCAutoHeightTableViewController1 : KCTableViewController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Other/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/17. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/KCTableViewArrayDataSourceWithCommitEditingStyle.h: -------------------------------------------------------------------------------- 1 | // 2 | // KCTableViewArrayDataSourceWithCommitEditingStyle.h 3 | // CMJStudio 4 | // 5 | // Created by KenshinCui on 15/5/25. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import "KCTableViewArrayDataSource.h" 10 | 11 | /** 12 | * 带有编辑功能的数据源(支持自带编辑) 13 | */ 14 | @interface KCTableViewArrayDataSourceWithCommitEditingStyle : KCTableViewArrayDataSource 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Views/KCCardTableViewCell1.h: -------------------------------------------------------------------------------- 1 | // 2 | // KCStatusTableViewCell.h 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/17. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 使用frame手动控制cell高度的情况示例 8 | 9 | #import "KCTableViewCell.h" 10 | #import "KCPerson.h" 11 | 12 | @interface KCCardTableViewCell1 : KCTableViewCell 13 | 14 | /** 15 | * 数据模型,用以填充控件数据 16 | */ 17 | @property (strong,nonatomic) KCPerson *person; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Views/KCCardTableViewCell2.h: -------------------------------------------------------------------------------- 1 | // 2 | // KCCardTableViewCell2.h 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/18. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 使用AutoLayout控制cell高度的情况示例(并且使用了Xib) 8 | 9 | #import 10 | #import "KCPerson.h" 11 | 12 | @interface KCCardTableViewCell2 : UITableViewCell 13 | 14 | /** 15 | * 数据模型,用以填充控件数据 16 | */ 17 | @property (strong,nonatomic) KCPerson *person; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | #Pods/ 27 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Models/KCPerson.m: -------------------------------------------------------------------------------- 1 | // 2 | // KCPerson.m 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/18. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import "KCPerson.h" 10 | 11 | @implementation KCPerson 12 | #pragma mark - 生命周期及其基类方法 13 | - (instancetype)initWithName:(NSString *)name avatarUrl:(NSString *)avatarUrl introduction:(NSString *)introduction { 14 | if (self = [super init]) { 15 | self.name = name; 16 | self.avatarUrl = avatarUrl; 17 | self.introduction = introduction; 18 | } 19 | return self; 20 | } 21 | @end 22 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Models/KCPerson.h: -------------------------------------------------------------------------------- 1 | // 2 | // KCPerson.h 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/18. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface KCPerson : NSObject 12 | #pragma mark - 生命周期及其基类方法 13 | - (instancetype)initWithName:(NSString *)name avatarUrl:(NSString *)avatarUrl introduction:(NSString *)introduction; 14 | 15 | #pragma mark - 属性 16 | @property(copy, nonatomic) NSString *name; 17 | 18 | @property(copy, nonatomic) NSString *avatarUrl; 19 | 20 | @property(copy, nonatomic) NSString *introduction; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/KCLightweightUITableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LightweightUITableView.h 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/18. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #ifndef LightweightUITableViewDemo_LightweightUITableView_h 10 | #define LightweightUITableViewDemo_LightweightUITableView_h 11 | 12 | #import "UIView+KC.h" 13 | #import "UITableViewCell+KC.h" 14 | #import "UITableView+KC.h" 15 | #import "KCTableViewCell.h" 16 | #import "KCTableViewArrayDataSource.h" 17 | #import "KCTableViewArrayDataSourceWithCommitEditingStyle.h" 18 | #import "KCTableViewDelegate.h" 19 | #import "KCTableViewController.h" 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/KCTableViewArrayDataSourceWithCommitEditingStyle.m: -------------------------------------------------------------------------------- 1 | // 2 | // KCTableViewArrayDataSourceWithCommitEditingStyle.m 3 | // CMJStudio 4 | // 5 | // Created by KenshinCui on 15/5/25. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import "KCTableViewArrayDataSourceWithCommitEditingStyle.h" 10 | 11 | @implementation KCTableViewArrayDataSourceWithCommitEditingStyle 12 | 13 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 14 | if (self.commitEditingStyleBlock) { 15 | self.commitEditingStyleBlock(tableView, editingStyle, indexPath); 16 | } 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "size" : "60x60", 25 | "idiom" : "iphone", 26 | "filename" : "cmjLogo120.png", 27 | "scale" : "2x" 28 | }, 29 | { 30 | "size" : "60x60", 31 | "idiom" : "iphone", 32 | "filename" : "cmjLogo180.png", 33 | "scale" : "3x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | } 40 | } -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Services/KCPersonService.m: -------------------------------------------------------------------------------- 1 | // 2 | // KCPersonService.m 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/18. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import "KCPersonService.h" 10 | #import "KCPerson.h" 11 | 12 | @implementation KCPersonService 13 | 14 | +(NSArray *)requestPersons{ 15 | //这里手动构造数据,实际开发中通常是从服务器端情况数据 16 | NSMutableArray *arrayM = [NSMutableArray array]; 17 | NSString *filePath= [[NSBundle mainBundle] pathForResource:@"Persons.plist" ofType:nil]; 18 | NSArray *array = [NSArray arrayWithContentsOfFile:filePath]; 19 | [array enumerateObjectsUsingBlock:^(NSDictionary *dic, NSUInteger idx, BOOL *stop) { 20 | KCPerson *person = [[KCPerson alloc]initWithName:dic[@"name"] avatarUrl:dic[@"avatarUrl"] introduction:dic[@"introduction"]]; 21 | [arrayM addObject:person]; 22 | }]; 23 | return [arrayM copy]; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Kenshin Cui 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/KCTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // KCTableViewController.h 3 | // KCFramework 4 | // 5 | // Created by KenshinCui on 15/4/15. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "KCTableViewArrayDataSource.h" 11 | #import "KCTableViewDelegate.h" 12 | 13 | /** 14 | * 表格视图控制器 15 | */ 16 | @interface KCTableViewController : UIViewController 17 | #pragma mark - 属性 18 | /** 19 | * 主界面表格 20 | */ 21 | @property(strong, nonatomic) UITableView *tableView; 22 | /** 23 | * UITableView数据源对象 24 | */ 25 | @property(strong, nonatomic) KCTableViewArrayDataSource *dataSource; 26 | /** 27 | * UITableView数据源代理 28 | */ 29 | @property(strong, nonatomic) KCTableViewDelegate *delegate; 30 | /** 31 | * 数据表数据 32 | * 33 | * 注意:对于动态数据,可以直接调用self.data来添加记录,如果是静态数据或者说是已经计算好的数据可以直接给self.data赋值 34 | */ 35 | @property(strong, nonatomic) NSMutableArray *data; 36 | 37 | /** 38 | * UITableView风格 39 | * 40 | * 注意:如果要设置表格样式必须在viewDidLoad之前(推荐放到init方法中),否则必须重新创建UITableView 41 | */ 42 | @property(assign, nonatomic) UITableViewStyle tableStyle; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemoTests/LightweightUITableViewDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // LightweightUITableViewDemoTests.m 3 | // LightweightUITableViewDemoTests 4 | // 5 | // Created by KenshinCui on 15/9/17. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface LightweightUITableViewDemoTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation LightweightUITableViewDemoTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/UIView+KC.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+KC.h 3 | // KCFramework 4 | // 5 | // Created by Kenshin Cui on 15/1/20. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | /** 14 | * UIView分类扩展 15 | */ 16 | @interface UIView (KC) 17 | 18 | #pragma mark 尺寸 19 | /** 20 | * 控件尺寸 21 | */ 22 | @property(assign, nonatomic) CGSize size; 23 | /** 24 | * 控件宽度 25 | */ 26 | @property(assign, nonatomic) CGFloat width; 27 | /** 28 | * 控件高度 29 | */ 30 | @property(assign, nonatomic) CGFloat height; 31 | /** 32 | * 控件坐标 33 | */ 34 | @property(assign, nonatomic) CGPoint origin; 35 | /** 36 | * 控件x坐标 37 | */ 38 | @property(assign, nonatomic) CGFloat x; 39 | /** 40 | * 控件y坐标 41 | */ 42 | @property(assign, nonatomic) CGFloat y; 43 | 44 | /** 45 | * 中心点x坐标 46 | */ 47 | @property(assign, nonatomic) CGFloat centerX; 48 | 49 | /** 50 | * 中心点y坐标 51 | */ 52 | @property(assign, nonatomic) CGFloat centerY; 53 | /** 54 | * x方向最大值(控件不超出右侧边界为前提) 55 | */ 56 | @property(assign, nonatomic) CGFloat maxX; 57 | /** 58 | * y方向最大值(控件不超出下编辑为前提) 59 | */ 60 | @property(assign, nonatomic) CGFloat maxY; 61 | 62 | @end 63 | 64 | 65 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/KCTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // KCTableViewCell.h 3 | // CMJStudio 4 | // 5 | // Created by KenshinCui on 15/4/1. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import 10 | /** 11 | * UITableViewCell扩展类,实现Cell间距设置、背景设置等功能 12 | * 13 | * 注意: 14 | * 1.使用此类时所有子控件需要添加到containerView中而不要添加到contentView中 15 | * 2.子控件添加时必须按照自上而下的顺序添加(因为高度计算依靠最后一个控件) 16 | * 3.子类在模型设置中可以获取containerView的宽度,但是无法获取高度,只有在layoutSubViews中可以获得其高度 17 | * 4.如果需要指定边框底部内间距,需要创建对象之后立即设置(必须发生在模型设置之前) 18 | * 5.外部必须调用一次height方法(事实上不调用height,此类也没有太多意义了) 19 | */ 20 | @interface KCTableViewCell : UITableViewCell 21 | 22 | #pragma mark - 公共方法 23 | 24 | 25 | #pragma mark - 属性 26 | /** 27 | * Cell外边距(margin) 28 | */ 29 | @property(assign, nonatomic) UIEdgeInsets containerInset; 30 | /** 31 | * Cell内下边距(padding-bottom) 32 | */ 33 | @property(assign, nonatomic) CGFloat containerPaddingBottom; 34 | /** 35 | * 边框宽度 36 | */ 37 | @property(assign, nonatomic) CGFloat borderWidth; 38 | /** 39 | * 边框颜色 40 | */ 41 | @property(strong, nonatomic) UIColor *borderColor; 42 | /** 43 | * Cell容器视图 44 | */ 45 | @property(strong, nonatomic) UIView *containerView; 46 | /** 47 | * Cell最终高度 48 | */ 49 | @property(assign, nonatomic) CGFloat height; 50 | @end 51 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Controllers/KCAutoHeightTableViewController1.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // KCAutHeightTableViewController.m 4 | // LightweightUITableViewDemo 5 | // 6 | // Created by KenshinCui on 15/9/17. 7 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 8 | // 自动计算Cell行高(使用frame计算) 9 | 10 | #import "KCAutoHeightTableViewController1.h" 11 | #import "KCPersonService.h" 12 | #import "KCCardTableViewCell1.h" 13 | #import "KCLightweightUITableView.h" 14 | 15 | @interface KCAutoHeightTableViewController1 () 16 | 17 | @end 18 | 19 | @implementation KCAutoHeightTableViewController1 20 | #pragma mark - 生命周期及其基类方法 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | 24 | [self initializer]; 25 | } 26 | 27 | #pragma mark - 私有方法 28 | - (void)initializer { 29 | self.title = @"自动计算行高"; 30 | //如果使用KCTableViewDelegate只需要配置UITableView的autoCellHeight属性为YES即可(当然在定义Cell中需要实现height方法) 31 | self.tableView.estimatedRowHeight = 300.0; 32 | self.tableView.autoCellHeight = YES; 33 | self.dataSource.cellClass = [KCCardTableViewCell1 class]; 34 | self.data = [[KCPersonService requestPersons] mutableCopy]; 35 | [self.dataSource setCellBlock:^(KCCardTableViewCell1 *cell, id dataItem, NSIndexPath *indexPath) { 36 | cell.person = dataItem; 37 | }]; 38 | [self.delegate setWillDisplayCellBlock:^(UITableViewCell *cell, NSIndexPath *indexPath) { 39 | cell.seperatorPinToSupperviewMargins = YES;//分割线两端对齐 40 | }]; 41 | } 42 | @end 43 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Controllers/KCAutoHeightTableViewController2.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // KCAutoHeightTableViewController2.m 4 | // LightweightUITableViewDemo 5 | // 6 | // Created by KenshinCui on 15/9/18. 7 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 8 | // 9 | 10 | #import "KCAutoHeightTableViewController2.h" 11 | #import "KCPersonService.h" 12 | #import "KCCardTableViewCell2.h" 13 | #import "KCLightweightUITableView.h" 14 | 15 | static NSString *const cellIdentifier = @"KCCardTableViewCell2"; 16 | @implementation KCAutoHeightTableViewController2 17 | #pragma mark - 生命周期及其基类方法 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | 21 | [self initializer]; 22 | } 23 | 24 | #pragma mark - 私有方法 25 | - (void)initializer { 26 | self.title = @"自动计算行高"; 27 | //如果使用KCTableViewDelegate只需要配置UITableView的autoCellHeight属性为YES即可(当然在定义Cell中需要实现height方法) 28 | self.tableView.estimatedRowHeight = 300.0; 29 | self.tableView.autoCellHeight = YES; 30 | //注册Nib 31 | [self.dataSource registerNibName:cellIdentifier reuseIdentifier:cellIdentifier forCellWithTableView:self.tableView]; 32 | self.data = [[KCPersonService requestPersons] mutableCopy]; 33 | [self.dataSource setCellBlock:^(KCCardTableViewCell2 *cell, id dataItem, NSIndexPath *indexPath) { 34 | cell.person = dataItem; 35 | }]; 36 | [self.delegate setWillDisplayCellBlock:^(UITableViewCell *cell, NSIndexPath *indexPath) { 37 | cell.seperatorPinToSupperviewMargins = YES;//分割线两端对齐 38 | }]; 39 | } 40 | @end 41 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Views/KCCardTableViewCell2.m: -------------------------------------------------------------------------------- 1 | // 2 | // KCCardTableViewCell2.m 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/18. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 使用AutoLayout控制cell高度的情况示例(并且使用了Xib) 8 | 9 | #import "KCCardTableViewCell2.h" 10 | #import "KCLightweightUITableView.h" 11 | 12 | static const CGFloat kAvatarWidth = 100.0; 13 | static const CGFloat kCommonSpace = 8.0; 14 | 15 | @interface KCCardTableViewCell2 () 16 | 17 | @property (weak, nonatomic) IBOutlet UIImageView *avatarImageView; 18 | @property (weak, nonatomic) IBOutlet UILabel *nameLabel; 19 | @property (weak, nonatomic) IBOutlet UILabel *introductionLabel; 20 | 21 | @end 22 | 23 | @implementation KCCardTableViewCell2 24 | 25 | #pragma mark - 生命周期及其基类方法 26 | - (void)awakeFromNib { 27 | //注意使用AutoLayout在这里需要制定宽度才能换行 28 | [self.introductionLabel setPreferredMaxLayoutWidth:[UIScreen mainScreen].bounds.size.width - kAvatarWidth - 3 * kCommonSpace]; 29 | } 30 | 31 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 32 | } 33 | 34 | //注意这里仍然需要返回height,不过可以利用AutoLayout来计算高度 35 | -(CGFloat)height{ 36 | return [self systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; 37 | } 38 | 39 | #pragma mark - 属性 40 | - (void)setPerson:(KCPerson *)person { 41 | _person = person; 42 | 43 | //设置数据并更改布局 44 | self.avatarImageView.image = [UIImage imageNamed:person.avatarUrl]; //注意这里使用了本地图片用以模拟 45 | self.nameLabel.text = person.name; 46 | self.introductionLabel.text = person.introduction; 47 | } 48 | @end 49 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/KCTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // KCTableViewController.m 3 | // KCFramework 4 | // 5 | // Created by KenshinCui on 15/4/15. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import "KCTableViewController.h" 10 | #import 11 | 12 | @interface KCTableViewController () 13 | 14 | @end 15 | 16 | @implementation KCTableViewController 17 | 18 | #pragma mark - 生命周期及其基类方法 19 | - (instancetype)init { 20 | if (self = [super init]) { 21 | self.tableStyle = UITableViewStylePlain; 22 | } 23 | return self; 24 | } 25 | 26 | #pragma mark - 覆盖方法 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | [self addTableViewToController]; 30 | } 31 | 32 | - (void)viewWillAppear:(BOOL)animated { 33 | [super viewWillAppear:animated]; 34 | 35 | //设置数据源和代理 36 | self.tableView.dataSource = self.dataSource; 37 | self.tableView.delegate = self.delegate; 38 | } 39 | 40 | - (void)viewWillLayoutSubviews { 41 | [super viewWillLayoutSubviews]; 42 | } 43 | 44 | #pragma mark - 属性 45 | - (void)setData:(NSMutableArray *)data { 46 | _data = data; 47 | self.dataSource.data = _data; 48 | } 49 | 50 | #pragma mark - 私有方法 51 | - (void)addTableViewToController { 52 | self.tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:self.tableStyle]; 53 | [self.view addSubview:self.tableView]; 54 | 55 | self.dataSource = [[KCTableViewArrayDataSource alloc] init]; 56 | self.data = [NSMutableArray array]; 57 | self.delegate = [[KCTableViewDelegate alloc] init]; 58 | } 59 | 60 | - (void)dealloc { 61 | self.tableView.delegate = nil; //避免滚动过程中返回造成crash问题 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/UITableViewCell+KC.h: -------------------------------------------------------------------------------- 1 | // 2 | // UITableViewCell+KC.h 3 | // KCFramework 4 | // 5 | // Created by Kenshin Cui on 15/1/16. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * UITableViewCell扩展方法 13 | */ 14 | @interface UITableViewCell (KC) 15 | #pragma mark - 公共方法 16 | /** 17 | * 快速创建一个可重用Cell 18 | * 19 | * @param tableView 当前UITableView(从此缓存池中获取可重用Cell) 20 | * 21 | * @return 可重用Cell 22 | */ 23 | + (UITableViewCell *)cellWithTableView:(UITableView *)tableView; 24 | 25 | /** 26 | * 创建xib 27 | * 28 | * @param name xib的名字 29 | * @param tableView tableview 30 | * @param identifier cell重用标示符 31 | * 32 | * @return 返回自定义的cell 33 | */ 34 | + (UITableViewCell *)loadCellWithName:(NSString *)name tableView:(UITableView *)tableView reusableIdentifier:(NSString *)identifier; 35 | 36 | /** 37 | * 自定义cell选中显示的视图 38 | * 39 | * @param color 选中视图的颜色 40 | */ 41 | + (UIView *)selectedBackgroundViewWithColor:(UIColor *)color; 42 | 43 | /** 44 | * 用于设置tableview上cell底部的线条两端无间隔显示完全 45 | * 46 | * tableview需要设置 47 | * -tableView:willDisplayCell:forRowAtIndexPath:调用传入cell 48 | * 49 | * @param view 为tableview 或 tableViewCell 50 | */ 51 | + (void)setEdgeInsetsZeroForTableViewCell:(id)view; 52 | 53 | /** 54 | * 55 | * @param insets 距离cell上下左右的距离 56 | * @param view 为tableview 和tableViewCell 57 | */ 58 | + (void)setEdgeInsets:(UIEdgeInsets)insets forTableViewCell:(id)view; 59 | 60 | 61 | #pragma mark - 属性 62 | /** 63 | * 取得Cell所在的TableView 64 | */ 65 | @property (strong,nonatomic) UITableView *tableView; 66 | /** 67 | * 分割线是否延伸到两端 68 | */ 69 | @property (assign,nonatomic) BOOL seperatorPinToSupperviewMargins; 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/UITableView+KC.h: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView+KC.h 3 | // CMJStudio 4 | // 5 | // Created by KenshinCui on 15/4/29. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * UITableView分类扩展,添加高度缓存,解决动态行高问题 13 | * 14 | * 使用: 15 | * 1.设置autoCellHeight=YES 16 | * 2.在tableView:heightForRowAtIndexPath:代理方法中调用heightWithIndexPath:返回高度(注意不要在次方中调用tableView:cellForRowAtIndexPath:,因为里面可能从缓存池取数据造成缓存池增大,也不要使用带有reuseIdentifier的构造方法创建cell以免在计算完高度后无法立即释放,建议使用无参构造方法创建cell并且指定模型返回高度) 17 | * 3.为了更有效的预缓存高度建议使用之前设置UITableView的estimatedRowHeight属性 18 | * 4.如果UITableView的代理为KCTableViewDelegate并且实现了cellConfigHandler(单Cell种类情况)则可以省略第2步 19 | * 注意: 20 | * 1.cell必须实现height方法才能正确计算高度,推荐使用方式: 21 | * a.如果仅仅支持iOS8可以直接设置estimatedRowHeight配合AutoLayout即可实现自动高度,不用使用此类 22 | * b.如果是仅仅支持iOS7或者iOS8并且使用AutoLayout不闪烁可以使用systemLayoutSizeFittingSize:方法在cell的height中返回正确的高度 23 | * c.如果是想支持iOS6以下并且使用AutoLayout布局可以使用systemLayoutSizeFittingSize:方法在cell的height中返回正确的高度 24 | * d.如果不使用AutoLayout则直接使用frame计算高度 25 | * 2.如果需要预加载缓存必须设置estimatedRowHeight属性,否则会先计算所有所有高度才会显示Cell,此时预加载没有意义 26 | * 3.此类依赖于KCTableViewArrayDataSource 27 | * 4.如果配合了KCTableViewDelegate使用只需要设置autoCellHeight=YES即可 28 | */ 29 | @interface UITableView (KC) 30 | #pragma mark - 公共方法 31 | /** 32 | * 是否启用自动高度计算,默认为NO不会自动计算 33 | */ 34 | @property(assign, nonatomic) BOOL autoCellHeight; 35 | /** 36 | * 取得行高 37 | * 38 | * 注意:自定义cell必须实现height方法 39 | * 40 | * @param indexPath 当前分组和行 41 | * 42 | * @return 行高 43 | */ 44 | - (CGFloat)heightWithIndexPath:(NSIndexPath *)indexPath; 45 | 46 | #pragma mark - 私有方法 47 | //高度缓存集合,注意只有使用heightWithIndexPath:方法时才会创建存储 48 | @property(strong, nonatomic) NSMutableArray *heightStore; 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Other/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/17. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/UIView+KC.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+KC.m 3 | // KCFramework 4 | // 5 | // Created by Kenshin Cui on 15/1/20. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import "UIView+KC.h" 10 | 11 | @implementation UIView (KC) 12 | #pragma mark 控件尺寸 13 | - (void)setSize:(CGSize)size { 14 | CGRect frame = self.frame; 15 | frame.size = size; 16 | self.frame = frame; 17 | } 18 | - (CGSize)size { 19 | return self.frame.size; 20 | } 21 | - (void)setWidth:(CGFloat)width { 22 | CGRect frame = self.frame; 23 | frame.size.width = width; 24 | self.frame = frame; 25 | } 26 | - (CGFloat)width { 27 | return self.frame.size.width; 28 | } 29 | - (void)setHeight:(CGFloat)height { 30 | CGRect frame = self.frame; 31 | frame.size.height = height; 32 | self.frame = frame; 33 | } 34 | - (CGFloat)height { 35 | return self.frame.size.height; 36 | } 37 | - (void)setOrigin:(CGPoint)origin { 38 | CGRect frame = self.frame; 39 | frame.origin = origin; 40 | self.frame = frame; 41 | } 42 | - (CGPoint)origin { 43 | return self.frame.origin; 44 | } 45 | - (void)setX:(CGFloat)x { 46 | CGRect frame = self.frame; 47 | frame.origin.x = x; 48 | self.frame = frame; 49 | } 50 | - (CGFloat)x { 51 | return self.frame.origin.x; 52 | } 53 | - (void)setY:(CGFloat)y { 54 | CGRect frame = self.frame; 55 | frame.origin.y = y; 56 | self.frame = frame; 57 | } 58 | - (CGFloat)y { 59 | return self.frame.origin.y; 60 | } 61 | 62 | - (CGFloat)centerX { 63 | return self.center.x; 64 | } 65 | - (void)setCenterX:(CGFloat)centerX { 66 | CGPoint center = self.center; 67 | center.x = centerX; 68 | self.center = center; 69 | } 70 | - (CGFloat)centerY { 71 | return self.center.y; 72 | } 73 | - (void)setCenterY:(CGFloat)centerY { 74 | CGPoint center = self.center; 75 | center.y = centerY; 76 | self.center = center; 77 | } 78 | 79 | - (CGFloat)maxX { 80 | return CGRectGetMaxX(self.frame); 81 | } 82 | - (void)setMaxX:(CGFloat)maxX { 83 | self.x = maxX - self.width; 84 | } 85 | - (CGFloat)maxY { 86 | return CGRectGetMaxX(self.frame); 87 | } 88 | - (void)setMaxY:(CGFloat)maxY { 89 | self.y = maxY - self.height; 90 | } 91 | #pragma mark 截屏 92 | - (UIImage *)captureScreen { 93 | //1.开启一个图像上下文 94 | UIGraphicsBeginImageContext(self.bounds.size); 95 | 96 | //2.渲染当前控件图层内容到上下文 97 | 98 | //取得当前上下文,注意此时获得的不是窗口上下文而是图像上下文 99 | CGContextRef context = UIGraphicsGetCurrentContext(); 100 | //渲染图层到上下文 101 | [self.layer renderInContext:context]; 102 | 103 | //3.从当前上下方获得图片 104 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 105 | 106 | //4.关闭图像上下文 107 | UIGraphicsEndImageContext(); 108 | 109 | return image; 110 | } 111 | @end -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Controllers/KCMainViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/17. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 通过数据源和代理对象给控制器瘦身 8 | 9 | #import "KCMainViewController.h" 10 | #import "KCAutoHeightTableViewController1.h" 11 | #import "KCAutoHeightTableViewController2.h" 12 | #import "KCLightweightUITableView.h" 13 | 14 | @interface KCMainViewController () 15 | 16 | @property(strong, nonatomic) UITableView *tableView; 17 | /** 18 | * 数据源定义 19 | */ 20 | @property(strong, nonatomic) KCTableViewArrayDataSource *dataSource; 21 | /** 22 | * 代理定义 23 | */ 24 | @property(strong, nonatomic) KCTableViewDelegate *delegate; 25 | /** 26 | * 存储数据,数组中可以存放任何对象类型 27 | */ 28 | @property(strong, nonatomic) NSMutableArray *data; 29 | 30 | @end 31 | 32 | @implementation KCMainViewController 33 | #pragma mark - 生命周期及其基类方法 34 | - (void)viewDidLoad { 35 | [super viewDidLoad]; 36 | 37 | self.title = @"轻量级UITableView解决方案"; 38 | [self.view addSubview:self.tableView]; 39 | 40 | [self.tableView reloadData]; 41 | } 42 | 43 | #pragma mark - 属性 44 | - (UITableView *)tableView { 45 | if (!_tableView) { 46 | CGRect screenBounds = [UIScreen mainScreen].bounds; 47 | _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0, 64.0, screenBounds.size.width, screenBounds.size.height)]; 48 | _tableView.dataSource = self.dataSource; 49 | _tableView.delegate = self.delegate; 50 | } 51 | return _tableView; 52 | } 53 | 54 | - (KCTableViewArrayDataSource *)dataSource { 55 | if (!_dataSource) { 56 | //数据源方法通过block实现 57 | _dataSource = [[KCTableViewArrayDataSource alloc] initWithData:self.data 58 | cellBlock:^(UITableViewCell *cell, NSString *dataItem, NSIndexPath *indexPath) { 59 | cell.textLabel.text = dataItem; 60 | }]; 61 | //更多数据源配置 62 | // [_dataSource setNumberOfRowsInSectionBlock:^NSUInteger(NSArray * data, NSInteger section) { 63 | // 64 | // }]; 65 | } 66 | return _dataSource; 67 | } 68 | 69 | - (KCTableViewDelegate *)delegate { 70 | if (!_delegate) { 71 | _delegate = [[KCTableViewDelegate alloc] init]; 72 | __weak typeof(self) weakSelf = self; 73 | //代理方法通过block实现 74 | [_delegate setSelectRowAtIndexPathBlock:^(id cell, NSIndexPath *indexPath) { 75 | NSString *controllerName = [NSString stringWithFormat:@"KCAutoHeightTableViewController%ld",indexPath.row + 1]; 76 | UIViewController *autoHeightController = [NSClassFromString(controllerName) new]; 77 | [weakSelf.navigationController pushViewController:autoHeightController animated:YES]; 78 | }]; 79 | //更多代理配置 80 | // [_delegate setHeightForRowAtIndexPathBlock:^CGFloat(NSIndexPath *indexPath) { 81 | // 82 | // }]; 83 | } 84 | return _delegate; 85 | } 86 | 87 | - (NSMutableArray *)data { 88 | if (!_data) { 89 | _data = [NSMutableArray arrayWithObjects:@"自动计算行高1(frame布局)", @"自动计算行高2(AutoLayout布局)", nil]; 90 | } 91 | return _data; 92 | } 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/UITableViewCell+KC.m: -------------------------------------------------------------------------------- 1 | // 2 | // UITableViewCell+KC.m 3 | // KCFramework 4 | // 5 | // Created by Kenshin Cui on 15/1/16. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import "UITableViewCell+KC.h" 10 | 11 | @implementation UITableViewCell (KC) 12 | 13 | + (UITableViewCell *)cellWithTableView:(UITableView *)tableView { 14 | static NSString *identtityKey = @"KCFramework_TableViewCellIdentityKey1"; 15 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identtityKey]; 16 | if (cell == nil) { 17 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identtityKey]; 18 | } 19 | return cell; 20 | } 21 | 22 | #pragma mark - 加载xib 23 | + (UITableViewCell *)loadCellWithName:(NSString *)name tableView:(UITableView *)tableView reusableIdentifier:(NSString *)identifier { 24 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 25 | if (cell == nil) { 26 | cell = [[NSBundle mainBundle] loadNibNamed:name owner:nil options:nil][0]; 27 | } 28 | return cell; 29 | } 30 | 31 | + (UIView *)selectedBackgroundViewWithColor:(UIColor *)color { 32 | UIView *view = [[UIView alloc] init]; 33 | view.backgroundColor = color; 34 | return view; 35 | } 36 | 37 | + (void)setEdgeInsetsZeroForTableViewCell:(id)view { 38 | [self setEdgeInsets:UIEdgeInsetsZero forTableViewCell:view]; 39 | } 40 | 41 | + (void)setEdgeInsets:(UIEdgeInsets)insets forTableViewCell:(id)view { 42 | if ([view isKindOfClass:[UITableView class]]) { 43 | 44 | UITableView *tableView = (UITableView *)view; 45 | 46 | if ([tableView respondsToSelector:@selector(setSeparatorInset:)]) { 47 | tableView.separatorInset = insets; 48 | } 49 | if ([tableView respondsToSelector:@selector(setLayoutMargins:)]) { 50 | tableView.layoutMargins = insets; 51 | } 52 | } 53 | if ([view isKindOfClass:[UITableViewCell class]]) { 54 | 55 | UITableView *tableViewCell = (UITableView *)view; 56 | 57 | if ([tableViewCell respondsToSelector:@selector(setSeparatorInset:)]) { 58 | tableViewCell.separatorInset = insets; 59 | } 60 | if ([tableViewCell respondsToSelector:@selector(setLayoutMargins:)]) { 61 | tableViewCell.layoutMargins = insets; 62 | } 63 | } 64 | } 65 | 66 | #pragma mark - 属性 67 | - (UITableView *)tableView { 68 | UIView *aView = self.superview; 69 | while (aView != nil) { 70 | if ([aView isKindOfClass:[UITableView class]]) { 71 | return (UITableView *)aView; 72 | } 73 | aView = aView.superview; 74 | } 75 | return nil; 76 | } 77 | - (void)setTableView:(UITableView *)tableView { 78 | } 79 | 80 | - (BOOL)seperatorPinToSupperviewMargins { 81 | return NO; 82 | } 83 | - (void)setSeperatorPinToSupperviewMargins:(BOOL)seperatorPinToSupperviewMargins { 84 | if (seperatorPinToSupperviewMargins) { 85 | UITableView *tableView=self.tableView; 86 | if ([tableView respondsToSelector:@selector(setSeparatorInset:)]) { 87 | [tableView setSeparatorInset:UIEdgeInsetsZero]; 88 | } 89 | 90 | if ([tableView respondsToSelector:@selector(setLayoutMargins:)]) { 91 | [tableView setLayoutMargins:UIEdgeInsetsZero]; 92 | } 93 | 94 | if ([self respondsToSelector:@selector(setLayoutMargins:)]) { 95 | [self setLayoutMargins:UIEdgeInsetsZero]; 96 | } 97 | } 98 | } 99 | @end 100 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/KCTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // KCTableViewCell.m 3 | // CMJStudio 4 | // 5 | // Created by KenshinCui on 15/4/1. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import "KCTableViewCell.h" 10 | #import "UIView+KC.h" 11 | 12 | @interface KCTableViewCell () 13 | 14 | //容器背景(注意不是Cell背景视图) 15 | @property(strong, nonatomic) UIView *containerBackgroundView; 16 | 17 | @end 18 | 19 | @implementation KCTableViewCell 20 | 21 | #pragma mark - 覆盖方法 22 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 23 | if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 24 | [self buildContainer]; 25 | } 26 | return self; 27 | } 28 | 29 | - (void)layoutSubviews { 30 | [super layoutSubviews]; 31 | 32 | //重新设置背景视图和容器视图的大小 33 | UIView *lastView = [self.containerView.subviews lastObject]; 34 | CGFloat lastViewY = CGRectGetMaxY(lastView.frame); 35 | CGFloat height=self.borderWidth * 2 + self.containerPaddingBottom + lastViewY; 36 | self.containerBackgroundView.height = height; 37 | self.containerView.height = self.containerPaddingBottom + lastViewY; 38 | } 39 | 40 | - (void)awakeFromNib { 41 | // Initialization code 42 | } 43 | 44 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 45 | [super setSelected:selected animated:animated]; 46 | 47 | // Configure the view for the selected state 48 | } 49 | 50 | #pragma mark - 公共方法 51 | 52 | #pragma mark - 属性 53 | -(void)setBorderWidth:(CGFloat)borderWidth{ 54 | _borderWidth=borderWidth; 55 | [self layoutContainer]; 56 | } 57 | 58 | -(void)setContainerPaddingBottom:(CGFloat)containerPaddingBottom{ 59 | _containerPaddingBottom=containerPaddingBottom; 60 | [self layoutContainer]; 61 | } 62 | 63 | -(void)setBorderColor:(UIColor *)borderColor{ 64 | _borderColor=borderColor; 65 | self.containerBackgroundView.backgroundColor=_borderColor; 66 | } 67 | 68 | - (CGFloat)height { 69 | // return CGRectGetMaxY(self.containerBackgroundView.frame); 70 | //重新设置背景视图和容器视图的大小 71 | UIView *lastView = [self.containerView.subviews lastObject]; 72 | CGFloat lastViewY = CGRectGetMaxY(lastView.frame); 73 | CGFloat height=self.borderWidth * 2 + self.containerPaddingBottom+self.containerInset.top+self.containerInset.bottom + lastViewY; 74 | return height; 75 | } 76 | 77 | #pragma mark - 私有方法 78 | - (void)buildContainer { 79 | //容器背景视图 80 | self.containerBackgroundView = [[UIView alloc] init]; 81 | [self.contentView addSubview:self.containerBackgroundView]; 82 | 83 | //容器视图 84 | self.containerView = [[UIView alloc] init]; 85 | self.containerView.backgroundColor=[UIColor whiteColor];//默认容器为白色 86 | [self.containerBackgroundView addSubview:self.containerView]; 87 | 88 | //设置默认的边框颜色 89 | self.borderColor=[UIColor grayColor]; 90 | } 91 | 92 | -(void)layoutContainer{ 93 | //重置布局 94 | self.containerBackgroundView.x = self.containerInset.left; 95 | self.containerBackgroundView.y = self.containerInset.top; 96 | self.containerBackgroundView.width = [UIScreen mainScreen].bounds.size.width - self.containerInset.left - self.containerInset.right; 97 | 98 | self.containerView.x = self.borderWidth; 99 | self.containerView.y = self.borderWidth; 100 | self.containerView.width = self.containerBackgroundView.width - 2 * self.borderWidth; 101 | 102 | } 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Views/KCCardTableViewCell1.m: -------------------------------------------------------------------------------- 1 | // 2 | // KCStatusTableViewCell.m 3 | // LightweightUITableViewDemo 4 | // 5 | // Created by KenshinCui on 15/9/17. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 使用frame手动控制cell高度的情况示例 8 | 9 | #import "KCCardTableViewCell1.h" 10 | #import "KCLightweightUITableView.h" 11 | 12 | static const CGFloat kAvatarWidth = 100.0; 13 | static const CGFloat kCommonSpace = 8.0; 14 | 15 | @interface KCCardTableViewCell1 () 16 | 17 | @property(strong, nonatomic) UIImageView *avatarImageView; 18 | @property(strong, nonatomic) UILabel *nameLabel; 19 | @property(strong, nonatomic) UILabel *introductionLabel; 20 | 21 | @end 22 | 23 | @implementation KCCardTableViewCell1 24 | 25 | #pragma mark - 生命周期及其基类方法 26 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 27 | if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 28 | [self initializer]; 29 | } 30 | return self; 31 | } 32 | 33 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 34 | } 35 | 36 | //注意:继承自KCTableViewCell可以不用自己返回height,非特殊情况下不用重新height的getter方法 37 | //-(CGFloat)height{ 38 | // return [super height]; 39 | //} 40 | 41 | #pragma mark - 私有方法 42 | - (void)initializer { 43 | //设置cell布局、背景等 44 | // self.containerInset = UIEdgeInsetsMake(kCommonSpace, kCommonSpace, kCommonSpace, kCommonSpace); //控件内容外边距 45 | self.containerPaddingBottom = kCommonSpace; //控件内容下边距 46 | // self.borderColor = [UIColor darkGrayColor]; //分割线颜色 47 | // self.borderWidth = 1.0; //分割线宽度 48 | 49 | //添加子控件 50 | [self.containerView addSubview:self.avatarImageView]; 51 | [self.containerView addSubview:self.nameLabel]; 52 | [self.containerView addSubview:self.introductionLabel]; 53 | } 54 | 55 | #pragma mark - 属性 56 | - (void)setPerson:(KCPerson *)person { 57 | _person = person; 58 | 59 | //设置数据并更改布局 60 | self.avatarImageView.image = [UIImage imageNamed:person.avatarUrl]; //注意这里使用了本地图片用以模拟 61 | self.nameLabel.text = person.name; 62 | self.introductionLabel.text = person.introduction; 63 | self.introductionLabel.width = [UIScreen mainScreen].bounds.size.width - kAvatarWidth - 3 * kCommonSpace; 64 | [self.introductionLabel sizeToFit]; 65 | } 66 | 67 | /** 68 | * 头像 69 | */ 70 | - (UIImageView *)avatarImageView { 71 | if (!_avatarImageView) { 72 | _avatarImageView = [[UIImageView alloc] initWithFrame:CGRectMake(kCommonSpace, kCommonSpace, kAvatarWidth, kAvatarWidth)]; 73 | } 74 | return _avatarImageView; 75 | } 76 | 77 | /** 78 | * 姓名 79 | */ 80 | - (UILabel *)nameLabel { 81 | if (!_nameLabel) { 82 | _nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.avatarImageView.frame) + kCommonSpace, kCommonSpace, 200.0, 18.0)]; 83 | _nameLabel.font = [UIFont systemFontOfSize:17.0]; 84 | _nameLabel.textColor = [UIColor colorWithRed:243.0 / 255.0 green:115.0 / 255.0 blue:45.0 / 255.0 alpha:1.0]; 85 | } 86 | return _nameLabel; 87 | } 88 | 89 | /** 90 | * 简介,高度不固定 91 | */ 92 | - (UILabel *)introductionLabel { 93 | if (!_introductionLabel) { 94 | _introductionLabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMinX(self.nameLabel.frame), CGRectGetMaxY(self.nameLabel.frame) + kCommonSpace, [UIScreen mainScreen].bounds.size.width - kAvatarWidth - 3 * kCommonSpace, 18.0)]; 95 | _introductionLabel.font = [UIFont systemFontOfSize:16.0]; 96 | _introductionLabel.numberOfLines = 0; 97 | } 98 | return _introductionLabel; 99 | } 100 | @end 101 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LightweightUITableView 2 | ![](https://github.com/kenshincui/LightweightUITableView/blob/master/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/cmjLogo120.png?raw=true) 3 | 4 | LightweightUITalbeView项目是一个简化UITableView开发的轻量级类库,使用它你可以不用再编写繁杂的数据源和代理方法,可以不用再手动维护可变高度的Cell行高,所有的这一切均有类库自动实现,让开发者只需要关注具体的业务。 5 | ## 目录 6 | LightweightUITalbeView 包含整个轻量级UITableview所需要的内容,可以直接copy到项目中使用; 7 | LightweightUITalbeViewDemo 用于演示LightweightUITalbeView库的使用; 8 | ##说明 9 | * KCTableViewArrayDataSource和KCTableViewDelegate用于给UIViewController中的UITableView的dataSource和delegate瘦身,也是LightweightUITalbeView的核心,二者将数据源和代理方法从控制器中解放出来,并提供了一些便捷方法用于快速配置数据; 10 | * UITableView+KC 用于实现自动行高扩展处理,理论上来说和KCTableViewArrayDataSource、KCTableViewDelegate可以分开使用,但是为了设置更加方便建议配合使用; 11 | * KCTableViewArrayDataSourceWithCommitEditingStyle用于处理可编辑Cell,KCTableViewArrayDataSource会根据属性设置动态调用,外界无需直接调用; 12 | * UITableViewCell+KC是对于UITableViewCell的扩展,仅用于辅助操作; 13 | * KCTableViewCell是对UITableViewCell的简单封装,方便配置Cell背景和设置间距,一般用于frame控制行高的情况,和当前库没有直接联系,仅用于辅助; 14 | * KCTableViewController是对于KCTableViewArrayDataSource、KCTableViewDelegate、UITableView+KC使用的简单控制器封装,用于辅助开发者快速创建使用LightweightUITalbeView的表格控制器; 15 | * UIView+KC是对UIView属性的简单扩展,和当前库没有直接联系,仅用于辅助; 16 | 17 | 总之,KCTableViewArrayDataSource、KCTableViewDelegate、UITableView+KC三个类是给UITableView瘦身的核心,理论上其他辅助类如果不需要均可以去掉(需要开发者简单修改使用的辅助方法,但是可行)。 18 | ##示例 19 | ### 1. 控制器瘦身 20 | 借助于KCTableViewArrayDataSource和KCTableViewDelegate对象代理控制器视图成为数据源和代理,避免冗余的数据源和代理方法,开发人员只需要关注属配置和必要的代理实现,并且二者均使用block实现,避免同一类方法分散到各处造成维护困扰。并且二者在命名方式上完全和原来的数据源方法、代理方法相对应,开发起来几乎零学习成本。另外为了便于开发,这里除了对应方法的block还提供了很多可以简化开发人员的方法,例如对于"- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath "这个数据源方法,则除了提供对应的“cellForRowAtIndexPathBlock”这个block之外,通常情况下如果只有一组数据、一种cell样式还可以直接使用"cellBlock"来简化数据配置,这个方法除了提供cell对象参数还提供了与之对应的数据项避免开发人员自己去数组中取出对应的模型(更多配置可以参考代码和具体的注释说明)。 21 | 如下示例中,由于在KCTableViewArrayDataSource中默认实现了返回分组数和行数的实现,如果仅仅包含一组数据可以不用实现分组数据源方法,而行数的实现KCTableViewArrayDataSource默认会返回配置的数组的个数,因此开发人员仅仅需要配置"cellForRowAtIndexPathBlock"来配置数据展示(事实上下面的代码中直接使用了默认的构造方法来完成了这个block的配置,代码更加简化)。同样的道理,KCTableViewDelegate则使用block来代理代理方法。 22 | 23 | ** 配置数据源 ** 24 | 25 | ```objc 26 | //数据源方法通过block实现 27 | _dataSource = [[KCTableViewArrayDataSource alloc] initWithData:self.data 28 | cellBlock:^(UITableViewCell *cell, NSString *dataItem, NSIndexPath *indexPath) { 29 | cell.textLabel.text = dataItem; 30 | }]; 31 | //更多数据源配置 32 | //[_dataSource setNumberOfRowsInSectionBlock:^NSUInteger(NSArray * data, NSInteger section) { 33 | // 34 | //}]; 35 | ``` 36 | 37 | ** 配置代理 ** 38 | 39 | ```objc 40 | //代理方法通过block实现 41 | [_delegate setSelectRowAtIndexPathBlock:^(id cell, NSIndexPath *indexPath) { 42 | NSString *controllerName = [NSString stringWithFormat:@"KCAutoHeightTableViewController%ld",indexPath.row + 1]; 43 | UIViewController *autoHeightController = [NSClassFromString(controllerName) new]; 44 | [weakSelf.navigationController pushViewController:autoHeightController animated:YES]; 45 | }]; 46 | //更多代理配置 47 | //[_delegate setHeightForRowAtIndexPathBlock:^CGFloat(NSIndexPath *indexPath) { 48 | // 49 | //}]; 50 | ``` 51 | 52 | ### 2. 自动计算Cell高度 53 | 从iOS 8开发人员才能利用"self-sizing cell"自动计算行高,但是这种方式似乎并没有iOS 7那么流畅,因为它会多次计算Cell高度,效率似乎并没有那么高。另外,目前不支持iOS 7还是不太现实的,或者说你还想要兼容更低版本。LightweightUITableView提供了一种更加通用和高效的解决方案。使用UITableView+KC 会让Cell行高计算更加方便(无论你是使用frame还是AutoLayout布局),再配合上KCTableViewDelegate这种实现则更加简洁,使用是直接配置UITableView的autoCellHeight为YES即可(当然建议配置estimatedRowHeight)。UITableView+KC内部会自动在空闲时间预计算Cell高度,并且自动维护行高不会多次计算行高。 54 | 在下面的实例中,仅仅通过几行代码即实现了Cell行高的计算。 55 | ```objc 56 | //如果使用KCTableViewDelegate只需要配置UITableView的autoCellHeight属性为YES即可(当然在定义Cell中需要实现height方法) 57 | self.tableView.estimatedRowHeight = 300.0; 58 | self.tableView.autoCellHeight = YES; 59 | self.dataSource.cellClass = [KCCardTableViewCell1 class]; 60 | self.data = [[KCPersonService requestPersons] mutableCopy]; 61 | [self.dataSource setCellBlock:^(KCCardTableViewCell1 *cell, id dataItem, NSIndexPath *indexPath) { 62 | cell.person = dataItem; 63 | }]; 64 | [self.delegate setWillDisplayCellBlock:^(UITableViewCell *cell, NSIndexPath *indexPath) { 65 | cell.seperatorPinToSupperviewMargins = YES;//分割线两端对齐 66 | }]; 67 | ``` 68 | ## 演示 69 | 70 | ![](https://github.com/kenshincui/LightweightUITableView/blob/master/LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/AutoHeightCell.gif?raw=true) 71 | 72 | 73 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/KCTableViewArrayDataSource.h: -------------------------------------------------------------------------------- 1 | // 2 | // KCTableViewArrayDataSource.h 3 | // KCFramework 4 | // 5 | // Created by Kenshin Cui on 15/2/2. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | /** 13 | * UITableView数据源对象,简化UITableView的使用,注意此对象创建时必须强引用 14 | * 15 | * 注意: 16 | * 1.对于多个不同cell类型的表格请自行实现cellForRowAtIndexPathBlock并自己控制重用,不用指定identifier、cellBlock等 17 | * 2.data如果需要动态修改建议传递NSMutableArray直接引用(不要传递copy或者mutableCopy)在外部修改data(增删数据而不是直接赋值为另一个对象)引用而不用直接赋值 18 | * 3.对于分组表格,需要重写组数、行数回调方法 19 | * 4.如果Cell使用xib,则必须提前注册并且需要指定reuseIdentifier(但是cellClass可以不指定),推荐直接使用“-(void)registerNibName:(NSString *)nibName reuseIdentifier:(NSString *)reuseInditifier forTableView:(UITableView *)tableView或者“- (void)registerClass:(Class)cls reuseIdentifier:(NSString *)reuseInditifier forTableView:(UITableView *)tableView”方法来注册 20 | */ 21 | @interface KCTableViewArrayDataSource : NSObject 22 | 23 | #pragma mark - 属性 24 | /** 25 | * UITableViewCell类型 26 | */ 27 | @property(assign, nonatomic) Class cellClass; 28 | 29 | /** 30 | * 和上面的cellClass互斥,仅仅用于autoCellHeight为YES时动态创建cell并计算高度使用,通常情况下使用不到 31 | */ 32 | @property (copy,nonatomic) NSString *nibName; 33 | 34 | @property(assign, nonatomic) UITableViewCellStyle cellStyle; 35 | 36 | /** 37 | * UITableViewCell重用标识 38 | * 39 | * 注意在外部注册的自定义Cell必须指定此标识并同注册时指定的标示相同 40 | */ 41 | @property(copy, nonatomic) NSString *reuseIdentifier; 42 | 43 | /** 44 | * 分组数,默认为1 45 | */ 46 | @property(assign, nonatomic) NSInteger sectionCount; 47 | 48 | /** 49 | * UITableView数据存储对象 50 | */ 51 | @property(strong, nonatomic) NSArray *data; 52 | 53 | @property(copy, nonatomic) void (^cellBlock)(id cell, id dataItem, NSIndexPath *indexPath); 54 | 55 | 56 | /** 57 | * 分组头部标题回调 58 | */ 59 | @property(copy, nonatomic) NSString * (^titleForHeaderInSectionBlock)(NSInteger section) ; 60 | 61 | /** 62 | * 分组尾部标题回调 63 | */ 64 | @property(copy, nonatomic) NSString * (^titleForFooterInSectionBlock)(NSInteger section) ; 65 | 66 | /** 67 | * 分组数计算回调 68 | */ 69 | @property(copy, nonatomic) NSUInteger (^numberOfSectionsInTableViewBlock)(NSArray *data) ; 70 | 71 | /** 72 | * 行数计算回调 73 | */ 74 | @property(copy, nonatomic) NSUInteger (^numberOfRowsInSectionBlock)(NSArray *data, NSInteger section) ; 75 | /** 76 | * 单元格创建回调 77 | */ 78 | @property(copy, nonatomic) UITableViewCell * (^cellForRowAtIndexPathBlock)(UITableView *tableView, NSIndexPath *indexPath) ; 79 | 80 | /** 81 | * 编辑提交回调 82 | */ 83 | @property (copy,nonatomic) void (^commitEditingStyleBlock)(UITableView *tableView, UITableViewCellEditingStyle editingStyle, NSIndexPath *indexPath) ; 84 | 85 | #pragma mark - 方法 86 | /** 87 | * 注册Xib类型 88 | * 89 | * @param nibName Xib名称 90 | * @param reuseInditifier 重用标识 91 | * @param tableView 表格 92 | */ 93 | - (void)registerNibName:(NSString *)nibName reuseIdentifier:(NSString *)reuseInditifier forCellWithTableView:(UITableView *)tableView; 94 | /** 95 | * 注册Cell类型 96 | * 97 | * @param cls 类型 98 | * @param reuseInditifier 重用标识 99 | * @param tableView 表格 100 | */ 101 | -(void)registerClass:(Class)cls reuseIdentifier:(NSString *)reuseInditifier forCellWithTableView:(UITableView *)tableView; 102 | 103 | /** 104 | * 初始化一个表格数据源对象 105 | * 106 | * 注意:如果要自定义Cell请使用“-(instancetype)initWithData: cellClass: cellBlock:”方法 107 | * 108 | * @param data 数据对象数组 109 | * @param cellBlock 单元格操作回调函数 110 | * 111 | * @return 表格数据源对象 112 | */ 113 | - (instancetype)initWithData:(NSArray *)data cellBlock:(void (^)(id cell, id dataItem, NSIndexPath *indexPath))cellBlock; 114 | 115 | /** 116 | * 初始化一个表格数据源对象并指定自定义Cell类型 117 | * 118 | * @param data 数据对象数组 119 | * @param cellClass Cell类型 120 | * @param cellBlock 单元格操作回调函数 121 | * 122 | * @return 表格数据源对象 123 | */ 124 | - (instancetype)initWithData:(NSArray *)data cellClass:(Class)cellClass cellBlock:(void (^)(id cell, id dataItem, NSIndexPath *indexPath))cellBlock; 125 | 126 | /** 127 | * 获取指定所以的数据对象 128 | * 129 | * @param indexPath 所以路径 130 | * 131 | * @return 数据对象 132 | */ 133 | - (id)itemAtIndex:(NSIndexPath *)indexPath; 134 | 135 | /** 136 | * 初始化一个表格数据源对象 137 | * 138 | * @param data 数据对象数组 139 | * @param cellBlock 单元格操作回调函数 140 | * 141 | * @return 表格数据源对象 142 | */ 143 | + (instancetype)dataSourceWithData:(NSArray *)data cellBlock:(void (^)(id cell, id dataItem, NSIndexPath *indexPath))cellBlock; 144 | 145 | /** 146 | * 初始化一个表格数据源对象 147 | * 148 | * @param data 数据对象数组 149 | * @param cellClass Cell类型 150 | * @param cellBlock 单元格操作回调函数 151 | * 152 | * @return 表格数据源对象 153 | */ 154 | + (instancetype)dataSourceWithData:(NSArray *)data cellClass:(Class)cellClass cellBlock:(void (^)(id cell, id dataItem, NSIndexPath *indexPath))cellBlock; 155 | @end 156 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/KCTableViewArrayDataSource.m: -------------------------------------------------------------------------------- 1 | // 2 | // KCTableViewArrayDataSource.m 3 | // KCFramework 4 | // 5 | // Created by Kenshin Cui on 15/2/2. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import "KCTableViewArrayDataSource.h" 10 | #import "KCTableViewArrayDataSourceWithCommitEditingStyle.h" 11 | @import ObjectiveC; 12 | 13 | @interface KCTableViewArrayDataSource () 14 | 15 | @end 16 | 17 | @implementation KCTableViewArrayDataSource 18 | 19 | - (instancetype)init { 20 | if (self = [super init]) { 21 | self.sectionCount = 1; 22 | self.cellStyle = UITableViewCellStyleDefault; 23 | } 24 | return self; 25 | } 26 | 27 | #pragma mark - 公开方法 28 | - (void)registerNibName:(NSString *)nibName reuseIdentifier:(NSString *)reuseInditifier forCellWithTableView:(UITableView *)tableView { 29 | self.nibName = nibName; 30 | self.reuseIdentifier = reuseInditifier; 31 | [tableView registerNib:[UINib nibWithNibName:nibName bundle:nil] forCellReuseIdentifier:reuseInditifier]; 32 | } 33 | -(void)registerClass:(Class)cls reuseIdentifier:(NSString *)reuseInditifier forCellWithTableView:(UITableView *)tableView{ 34 | self.reuseIdentifier = reuseInditifier; 35 | self.cellClass = cls; 36 | [tableView registerClass:cls forCellReuseIdentifier:reuseInditifier]; 37 | } 38 | 39 | - (instancetype)initWithData:(NSArray *)data cellBlock:(void (^)(id, id, NSIndexPath *))cellBlock { 40 | if (self = [self init]) { 41 | self.data = data; 42 | self.cellBlock = cellBlock; 43 | } 44 | return self; 45 | } 46 | 47 | - (instancetype)initWithData:(NSArray *)data cellClass:(Class)cellClass cellBlock:(void (^)(id, id, NSIndexPath *))cellBlock { 48 | if (self = [self initWithData:data cellBlock:cellBlock]) { 49 | self.cellClass = cellClass; 50 | } 51 | return self; 52 | } 53 | 54 | - (id)itemAtIndex:(NSIndexPath *)indexPath { 55 | return self.data[indexPath.row]; 56 | } 57 | 58 | + (instancetype)dataSourceWithData:(NSArray *)data cellBlock:(void (^)(id, id, NSIndexPath *))cellBlock { 59 | id obj = [[self alloc] initWithData:data cellBlock:cellBlock]; 60 | return obj; 61 | } 62 | 63 | + (instancetype)dataSourceWithData:(NSArray *)data cellClass:(Class)cellClass cellBlock:(void (^)(id, id, NSIndexPath *))cellBlock { 64 | return [[self alloc] initWithData:data cellClass:cellClass cellBlock:cellBlock]; 65 | } 66 | 67 | #pragma mark - UITableView数据源方法 68 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 69 | if (self.numberOfSectionsInTableViewBlock) { 70 | self.sectionCount = self.numberOfSectionsInTableViewBlock(self.data); 71 | } 72 | return self.sectionCount; 73 | } 74 | 75 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 76 | if (self.numberOfRowsInSectionBlock) { 77 | return self.numberOfRowsInSectionBlock(self.data, section); 78 | } 79 | return self.data.count; 80 | } 81 | 82 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 83 | if (self.cellForRowAtIndexPathBlock) { 84 | return self.cellForRowAtIndexPathBlock(tableView, indexPath); 85 | } 86 | 87 | static NSString *identtityKey = @"myTableViewCellIdentityKey1"; 88 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.reuseIdentifier ? self.reuseIdentifier : identtityKey]; 89 | if (cell == nil) { 90 | if (self.cellClass) { 91 | cell = [[self.cellClass alloc] initWithStyle:self.cellStyle reuseIdentifier:identtityKey]; 92 | } else { 93 | cell = [[UITableViewCell alloc] initWithStyle:self.cellStyle reuseIdentifier:identtityKey]; 94 | } 95 | } 96 | id dataItem; 97 | if (self.data && self.data.count > 0) { 98 | if (self.sectionCount == 1&&self.data.count>indexPath.row) { 99 | dataItem = [self itemAtIndex:indexPath]; 100 | } else if(self.sectionCount>1&&[self.data[indexPath.section] isKindOfClass:[NSArray class]]){ 101 | dataItem = self.data[indexPath.section][indexPath.row]; 102 | } 103 | } 104 | if (self.cellBlock) { 105 | self.cellBlock(cell, dataItem, indexPath); 106 | } 107 | return cell; 108 | } 109 | 110 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 111 | if (self.titleForHeaderInSectionBlock) { 112 | return self.titleForHeaderInSectionBlock(section); 113 | } 114 | return nil; 115 | } 116 | 117 | - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { 118 | if (self.titleForFooterInSectionBlock) { 119 | return self.titleForFooterInSectionBlock(section); 120 | } 121 | return nil; 122 | } 123 | 124 | #pragma mark - 属性 125 | -(void)setCommitEditingStyleBlock:(void (^)(UITableView *, UITableViewCellEditingStyle, NSIndexPath *))commitEditingStyleBlock{ 126 | _commitEditingStyleBlock = commitEditingStyleBlock; 127 | if(commitEditingStyleBlock){ 128 | object_setClass(self, [KCTableViewArrayDataSourceWithCommitEditingStyle class]); 129 | } 130 | } 131 | @end 132 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/KCTableViewDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // KCTableViewDelegate.h 3 | // CMJStudio 4 | // 5 | // Created by KenshinCui on 15/3/17. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | /** 13 | * UITableView代理对象,用于创建轻量级UIViewController或UITableViewController 14 | * 15 | * 注意: 16 | * 1.对于过个不同的分组头、尾视图,必须自己实现viewForHeaderInSectionBlock、viewForFooterInSectionBlock 17 | * 而不能直接使用headerViewBlock、footerViewBlock配置 18 | * 2.如果UITableView设置了autoCellHeight=YES没有特殊行高计算的情况下可以省略heightForRowAtIndexPathBlock设置 19 | */ 20 | @interface KCTableViewDelegate : NSObject 21 | /** 22 | * 注册头、尾部视图类型 23 | * 24 | * @param nibName Xib名称 25 | * @param reuseInditifier 重用标识 26 | * @param tableView 表格 27 | */ 28 | - (void)registerNibName:(NSString *)nibName reuseIdentifier:(NSString *)reuseInditifier forHeaderWithTableView:(UITableView *)tableView; 29 | /** 30 | * 注册头部视图类型 31 | * 32 | * @param cls 类型 33 | * @param reuseInditifier 重用标识 34 | * @param tableView 表格 35 | */ 36 | - (void)registerClass:(Class)cls reuseIdentifier:(NSString *)reuseInditifier forHeaderWithTableView:(UITableView *)tableView; 37 | /** 38 | * 注册尾部视图类型 39 | * 40 | * @param cls Xib名称 41 | * @param reuseInditifier 重用标识 42 | * @param tableView 表格 43 | */ 44 | - (void)registerNibName:(NSString *)nibName reuseIdentifier:(NSString *)reuseInditifier forFooterWithTableView:(UITableView *)tableView; 45 | /** 46 | * 注册尾部视图类型 47 | * 48 | * @param cls 类型 49 | * @param reuseInditifier 重用标识 50 | * @param tableView 表格 51 | */ 52 | - (void)registerClass:(Class)cls reuseIdentifier:(NSString *)reuseInditifier forFooterWithTableView:(UITableView *)tableView; 53 | 54 | #pragma mark - UITableView相关代理实现属性 55 | /** 56 | * Header类型 57 | * 58 | * 注意:必须继承于UITableViewHeaderFooterView并且只有自定义分组头时才需要指定 59 | */ 60 | @property(strong, nonatomic) Class headerClass; 61 | 62 | /** 63 | * Footer类型,注意必须继承于UITableViewHeaderFooterView 64 | */ 65 | @property(strong, nonatomic) Class footerClass; 66 | 67 | /** 68 | * Header重用标识 69 | */ 70 | @property(copy, nonatomic) NSString *headerIdentifier; 71 | 72 | /** 73 | * Footer重用标识 74 | */ 75 | @property(copy, nonatomic) NSString *footerIdentifier; 76 | 77 | /** 78 | * 选中某行回调 79 | */ 80 | @property(copy, nonatomic) void (^selectRowAtIndexPathBlock)(id cell, NSIndexPath *indexPath); 81 | 82 | /** 83 | * 取消选中某行回调 84 | */ 85 | @property(copy, nonatomic) void (^deselectRowAtIndexPathBlock)(id cell, NSIndexPath *indexPath); 86 | 87 | /** 88 | * 将要显示单元格时回调 89 | */ 90 | @property(copy, nonatomic) void (^willDisplayCellBlock)(id cell, NSIndexPath *indexPath); 91 | 92 | /** 93 | * 将要结束显示单元格时的回调 94 | */ 95 | @property(copy, nonatomic) void (^endDisplayingCellBlock)(id cell, NSIndexPath *indexPath); 96 | 97 | /** 98 | * 将要结束显示头部视图时的回调 99 | */ 100 | @property(copy, nonatomic) void (^endDisplayingHeaderBlock)(UIView *header, NSInteger section); 101 | 102 | /** 103 | * 将要结束显示尾部视图时的回调 104 | */ 105 | @property(copy, nonatomic) void (^endDisplayingFooterBlock)(UIView *footer, NSInteger section); 106 | 107 | /** 108 | * 高度计算回调 109 | */ 110 | @property(copy, nonatomic) CGFloat (^heightForRowAtIndexPathBlock)(NSIndexPath *indexPath); 111 | 112 | /** 113 | * 分组头部高度回调 114 | */ 115 | @property(copy, nonatomic) CGFloat (^heightForHeaderInSectionBlock)(NSInteger section); 116 | 117 | /** 118 | * 分组尾部高度回调 119 | */ 120 | @property(copy, nonatomic) CGFloat (^heightForFooterInSectionBlock)(NSInteger section); 121 | 122 | /** 123 | * 分组标题视图配置,必须自己实现头部缓存,支持多个不同section视图 124 | */ 125 | @property(copy, nonatomic) UIView * (^viewForHeaderInSectionBlock)(UITableView *tableView, NSInteger section); 126 | /** 127 | * 分组标题视图配置 128 | */ 129 | @property(copy, nonatomic) void (^headerViewBlock)(id headerView, NSInteger section); 130 | 131 | /** 132 | * 分组尾部标题视图回调 133 | */ 134 | @property(copy, nonatomic) UIView * (^viewForFooterInSectionBlock)(UITableView *tableView, NSInteger section); 135 | /** 136 | * 分组尾部标题视图回调 137 | */ 138 | @property(copy, nonatomic) void (^footerViewBlock)(id footerView, NSInteger section); 139 | 140 | #pragma mark - UIScrollView相关代理实现属性 141 | /** 142 | * 开始滚动回调 143 | */ 144 | @property(copy, nonatomic) void (^scrollViewDidScrollBlock)(UIScrollView *scrollView); 145 | 146 | /** 147 | * 即将停止滚动回调 148 | */ 149 | @property(copy, nonatomic) void (^scrollViewWillBeginDeceleratingBlock)(UIScrollView *scrollView); 150 | 151 | /** 152 | * 停止滚动回调 153 | */ 154 | @property(copy, nonatomic) void (^scrollViewDidEndDeceleratingBlock)(UIScrollView *scrollView); 155 | 156 | /** 157 | * 即将停止拖拽回调 158 | */ 159 | @property(copy, nonatomic) void (^scrollViewWillEndDraggingBlock)(UIScrollView *scrollView, CGPoint velocity, CGPoint *targetContentOffset); 160 | 161 | /** 162 | * 拖拽停止回调 163 | */ 164 | @property(copy, nonatomic) void (^scrollViewDidEndDraggingBlock)(UIScrollView *scrollView, BOOL decelerate); 165 | 166 | /** 167 | * 滚动动画结束回调(注意只用调用程序滚动才会调用此方法[例如:scrollToRowAtIndexPath:indexPath atScrollPosition: animated:],手动滚动不会调用) 168 | */ 169 | @property(copy, nonatomic) void (^scrollViewDidEndScrollingAnimationBlock)(UIScrollView *scrollView); 170 | 171 | @end 172 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Resources/Persons.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | name 7 | Miaoer 8 | avatarUrl 9 | 1.jpg 10 | introduction 11 | Years of software design and development experience, familiar with server-side and client-side development, especially those with deep accumulation in iOS development. IOS has led the development of a number of projects and products, with rich experience in product development and project combat experience. Today's headlines Deals currently serves as iOS client technology division manager responsible Deals client architecture, design and core development work. 12 | 13 | 14 | name 15 | Kaoru 16 | avatarUrl 17 | 2.jpg 18 | introduction 19 | Master UESTC computer science engineering, Changhong system architects, ten years of experience in Java project development, proficient in Java, Python, GoLang, Scala, Node.js, and other programming languages, proficient in Java EE, Spring, workflow, Web Crawler , rules engine, the development of full-text retrieval technology, the main research directions for Web development, distributed computing, clustering technology, Docker technology, NoSQL technology. 20 | 21 | 22 | name 23 | Tom Xu 24 | avatarUrl 25 | 3.jpg 26 | introduction 27 | CSDN blog expert, for many years mainly engaged in the development and research of media streaming, network communications, p2p and other technologies. There are no related products, the product is expected to be available in August. 28 | 29 | 30 | name 31 | Jerry Lee 32 | avatarUrl 33 | 4.jpg 34 | introduction 35 | Programmers interested in algorithm research, he is super popular CSDN algorithm column blogger (blog), but also "algorithm fun," a book author. 2005 graduated from Huazhong University of Science and Technology, currently at RD center in Shanghai ZTE optical access network communications equipment development, as EPON (Ethernet Passive Optical Network) business software development manager, participate in the development of PON equipment in the global deployment of billions of dollars line . 36 | 37 | 38 | name 39 | Stephon Lee 40 | avatarUrl 41 | 5.jpg 42 | introduction 43 | IOS has led the development of a number of projects and products, with rich experience in product development and project combat experience. 44 | 45 | 46 | name 47 | Rose 48 | avatarUrl 49 | 6.jpg 50 | introduction 51 | He graduated from the University of Science and Technology of China, csdn blog expert, 2014 Top Ten blog star. Android engineer, worked in Tencent, innovative workshops and Baidu in the Android development work, currently involved in the development of mobile guards Baidu Baidu's work. 52 | 53 | 54 | name 55 | Jake 56 | avatarUrl 57 | 7.jpg 58 | introduction 59 | Hujiang network software engineer. Love to share, love geeks programming monster, Coding road is bound to be painful, and ultimately, the collapse of BUG, but so what, even if it can not perform, but also series of beautiful, I am eclipse_xu, I speak for myself, for the program was born, died as demand for Debug and struggle for life! 60 | 61 | 62 | name 63 | Berry 64 | avatarUrl 65 | 8.jpg 66 | introduction 67 | UMLChina chief expert. In 1999, or a programmer, in his spare time he created UMLChina, painstaking research needs and design skills. 2002 provide external demand and design UML technical guidance and training services, customers covering all areas of business leaders. 68 | 69 | 70 | name 71 | Apple 72 | avatarUrl 73 | 9.jpg 74 | introduction 75 | Years of software design and development experience, familiar with server-side and client-side development, especially those with deep accumulation in iOS development. IOS has led the development of a number of projects and products, with rich experience in product development and project combat experience. Today's headlines Deals currently serves as iOS client technology division manager responsible Deals client architecture, design and core development work. 76 | 77 | 78 | name 79 | Binger 80 | avatarUrl 81 | 10.jpg 82 | introduction 83 | July 2009, graduated from Hainan University Communication Engineering bachelor's degree in engineering. April 2012, graduated from Nanjing University of Posts and Computer Application Technology, a master's degree in engineering. May 2012 to date, ZTE R D center in Chongqing in software development. 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableViewDemo/Views/KCCardTableViewCell2.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 35 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/KCTableViewDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // KCTableViewDelegate.m 3 | // CMJStudio 4 | // 5 | // Created by KenshinCui on 15/3/17. 6 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 7 | // 8 | 9 | #import "KCTableViewDelegate.h" 10 | #import "UITableView+KC.h" 11 | 12 | #define KCOSVersionLessThan(version) ([[[UIDevice currentDevice] systemVersion] compare:version options:NSNumericSearch] == NSOrderedAscending) 13 | 14 | @interface KCTableViewDelegate () 15 | 16 | /** 17 | * Cell是否正在被点击,避免连续点击 18 | */ 19 | @property(assign, nonatomic) BOOL isCellSelecting; 20 | 21 | @end 22 | 23 | @implementation KCTableViewDelegate 24 | 25 | - (void)registerNibName:(NSString *)nibName reuseIdentifier:(NSString *)reuseInditifier forHeaderWithTableView:(UITableView *)tableView { 26 | self.headerIdentifier = reuseInditifier; 27 | [tableView registerNib:[UINib nibWithNibName:nibName bundle:nil] forHeaderFooterViewReuseIdentifier:reuseInditifier]; 28 | } 29 | - (void)registerClass:(Class)cls reuseIdentifier:(NSString *)reuseInditifier forHeaderWithTableView:(UITableView *)tableView { 30 | self.headerIdentifier = reuseInditifier; 31 | [tableView registerClass:cls forHeaderFooterViewReuseIdentifier:reuseInditifier]; 32 | } 33 | - (void)registerNibName:(NSString *)nibName reuseIdentifier:(NSString *)reuseInditifier forFooterWithTableView:(UITableView *)tableView { 34 | self.footerIdentifier = reuseInditifier; 35 | [tableView registerNib:[UINib nibWithNibName:nibName bundle:nil] forHeaderFooterViewReuseIdentifier:reuseInditifier]; 36 | } 37 | - (void)registerClass:(Class)cls reuseIdentifier:(NSString *)reuseInditifier forFooterWithTableView:(UITableView *)tableView { 38 | self.footerIdentifier = reuseInditifier; 39 | [tableView registerClass:cls forHeaderFooterViewReuseIdentifier:reuseInditifier]; 40 | } 41 | 42 | #pragma mark UITableView代理方法 43 | 44 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 45 | UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 46 | if (self.selectRowAtIndexPathBlock) { 47 | if (self.isCellSelecting) { 48 | return; 49 | } 50 | self.isCellSelecting = YES; 51 | self.selectRowAtIndexPathBlock(cell, indexPath); 52 | self.isCellSelecting = NO; 53 | } 54 | } 55 | - (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath { 56 | UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 57 | if (self.deselectRowAtIndexPathBlock) { 58 | self.deselectRowAtIndexPathBlock(cell, indexPath); 59 | } 60 | } 61 | 62 | - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { 63 | if (self.willDisplayCellBlock) { 64 | self.willDisplayCellBlock(cell, indexPath); 65 | } 66 | } 67 | 68 | - (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { 69 | if (self.endDisplayingCellBlock) { 70 | self.endDisplayingCellBlock(cell, indexPath); 71 | } 72 | } 73 | 74 | - (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section { 75 | if (self.endDisplayingHeaderBlock) { 76 | self.endDisplayingHeaderBlock(view, section); 77 | } 78 | } 79 | 80 | - (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section { 81 | if (self.endDisplayingFooterBlock) { 82 | self.endDisplayingFooterBlock(view, section); 83 | } 84 | } 85 | 86 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 87 | if (tableView.autoCellHeight) { 88 | return [tableView heightWithIndexPath:indexPath]; 89 | } 90 | if (self.heightForRowAtIndexPathBlock) { 91 | return self.heightForRowAtIndexPathBlock(indexPath); 92 | } 93 | 94 | return tableView.rowHeight; 95 | } 96 | 97 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 98 | if (self.heightForHeaderInSectionBlock) { 99 | return self.heightForHeaderInSectionBlock(section); 100 | } 101 | if (KCOSVersionLessThan(@"8") && (tableView.sectionHeaderHeight == 17.5 || tableView.sectionHeaderHeight == 23.0)) { //避免iOS7不指定头部高度出现空白头部 102 | return CGFLOAT_MIN; 103 | } 104 | return tableView.sectionHeaderHeight; 105 | } 106 | 107 | - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { 108 | if (self.heightForFooterInSectionBlock) { 109 | return self.heightForFooterInSectionBlock(section); 110 | } 111 | if (KCOSVersionLessThan(@"8") && (tableView.sectionFooterHeight == 17.5 || tableView.sectionFooterHeight == 23.0)) { //避免iOS7不指定尾部高度出现空白尾部 112 | return CGFLOAT_MIN; 113 | } 114 | return tableView.sectionFooterHeight; 115 | } 116 | 117 | - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 118 | if (self.viewForHeaderInSectionBlock) { 119 | return self.viewForHeaderInSectionBlock(tableView, section); 120 | } 121 | static NSString *identtityKey = @"myTableViewHeaderIdentityKey1"; 122 | UITableViewHeaderFooterView *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:self.headerIdentifier ? self.headerIdentifier : identtityKey]; 123 | if (!header) { 124 | if (self.headerClass) { 125 | header = [[self.headerClass alloc] initWithReuseIdentifier:identtityKey]; 126 | 127 | } else { 128 | header = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:identtityKey]; 129 | } 130 | } 131 | if (self.headerViewBlock) { 132 | self.headerViewBlock(header, section); 133 | } 134 | return header; 135 | } 136 | 137 | - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { 138 | if (self.viewForFooterInSectionBlock) { 139 | return self.viewForFooterInSectionBlock(tableView, section); 140 | } 141 | static NSString *identtityKey = @"myTableViewFooterIdentityKey1"; 142 | UITableViewHeaderFooterView *footer = [tableView dequeueReusableHeaderFooterViewWithIdentifier:self.footerIdentifier ? self.footerIdentifier : identtityKey]; 143 | if (!footer) { 144 | if (self.headerClass) { 145 | footer = [[self.headerClass alloc] initWithReuseIdentifier:identtityKey]; 146 | 147 | } else { 148 | footer = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:identtityKey]; 149 | } 150 | } 151 | if (self.footerViewBlock) { 152 | self.footerViewBlock(footer, section); 153 | } 154 | return footer; 155 | } 156 | 157 | #pragma mark - UIScrollView相关代理实现 158 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 159 | if (self.scrollViewDidScrollBlock) { 160 | self.scrollViewDidScrollBlock(scrollView); 161 | } 162 | } 163 | 164 | - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView { 165 | if (self.scrollViewWillBeginDeceleratingBlock) { 166 | self.scrollViewWillBeginDeceleratingBlock(scrollView); 167 | } 168 | } 169 | 170 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { 171 | if (self.scrollViewDidEndDeceleratingBlock) { 172 | self.scrollViewDidEndDeceleratingBlock(scrollView); 173 | } 174 | } 175 | 176 | - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { 177 | if (self.scrollViewWillEndDraggingBlock) { 178 | self.scrollViewWillEndDraggingBlock(scrollView, velocity, targetContentOffset); 179 | } 180 | } 181 | 182 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { 183 | if (self.scrollViewDidEndDraggingBlock) { 184 | self.scrollViewDidEndDraggingBlock(scrollView, decelerate); 185 | } 186 | } 187 | 188 | - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { 189 | !self.scrollViewDidEndScrollingAnimationBlock ?: self.scrollViewDidEndScrollingAnimationBlock(scrollView); 190 | } 191 | 192 | #pragma mark - 私有方法 193 | - (void)setIsCellSelecting:(BOOL)isCellSelecting { 194 | @synchronized(self) { 195 | if (!isCellSelecting) { 196 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 197 | _isCellSelecting = NO; 198 | }); 199 | } else { 200 | _isCellSelecting = YES; 201 | } 202 | } 203 | } 204 | @end 205 | -------------------------------------------------------------------------------- /LightweightUITableViewDemo/LightweightUITableView/UITableView+KC.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // UITableView+KC.m 4 | // CMJStudio 5 | // 6 | // Created by KenshinCui on 15/4/29. 7 | // Copyright (c) 2015年 CMJStudio. All rights reserved. 8 | // 9 | 10 | #import "UITableView+KC.h" 11 | #import "UIView+KC.h" 12 | #import "UITableViewCell+KC.h" 13 | #import "KCTableViewArrayDataSource.h" 14 | #import "KCTableViewDelegate.h" 15 | @import ObjectiveC; 16 | 17 | @implementation UITableView (KC) 18 | 19 | #pragma mark - 生命周期及其基类方法 20 | static long kKCAutoCellHeightKey; 21 | + (void)load { 22 | objc_setAssociatedObject(self, &kKCAutoCellHeightKey, @(NO), OBJC_ASSOCIATION_ASSIGN); 23 | 24 | SEL selectors[] = { 25 | @selector(reloadData), 26 | @selector(insertSections:withRowAnimation:), 27 | @selector(deleteSections:withRowAnimation:), 28 | @selector(reloadSections:withRowAnimation:), 29 | @selector(moveSection:toSection:), 30 | @selector(insertRowsAtIndexPaths:withRowAnimation:), 31 | @selector(deleteRowsAtIndexPaths:withRowAnimation:), 32 | @selector(reloadRowsAtIndexPaths:withRowAnimation:), 33 | @selector(moveRowAtIndexPath:toIndexPath:) 34 | }; 35 | for (int i = 0; i < sizeof(selectors) / sizeof(SEL); ++i) { 36 | SEL originSelector = selectors[i]; 37 | SEL swizzledSelector = NSSelectorFromString([NSString stringWithFormat:@"kc_%@", NSStringFromSelector(originSelector)]); 38 | 39 | Method originMethod = class_getInstanceMethod(self, originSelector); 40 | Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector); 41 | 42 | method_exchangeImplementations(originMethod, swizzledMethod); 43 | } 44 | } 45 | 46 | #pragma mark - 公共方法 47 | - (CGFloat)heightWithIndexPath:(NSIndexPath *)indexPath { 48 | if (!indexPath) { 49 | return 0.0; 50 | } 51 | CGFloat height = [self getCachedHeightWithIndexPath:indexPath]; 52 | if (height == 0) { 53 | // UITableViewCell *cell = [self cellForRowAtIndexPath:indexPath];//注意:不能调用此方法,不然会出现死循环,因为此方法会调用高度计算 54 | if (![self.dataSource isKindOfClass:[KCTableViewArrayDataSource class]]) { 55 | NSLog(@"计算高度过程中发生错误,错误详情:使用高度自适应功能必须配合KCTableViewArrayDataSource使用."); 56 | return 0.0; 57 | } 58 | if (![self.delegate isKindOfClass:[KCTableViewDelegate class]]) { 59 | NSLog(@"计算高度过程中发生错误,错误详情:使用高度自适应功能必须配合KCTableViewDelegate使用."); 60 | return 0.0; 61 | } 62 | KCTableViewArrayDataSource *dataSource = (KCTableViewArrayDataSource *)self.dataSource; 63 | KCTableViewDelegate *delegate = (KCTableViewDelegate *)self.delegate; 64 | if (dataSource.cellBlock) { 65 | UITableViewCell *cell; 66 | if (dataSource.cellClass) { 67 | cell = [[dataSource.cellClass alloc] init]; 68 | } else if(dataSource.nibName){ 69 | cell = [[[NSBundle mainBundle] loadNibNamed:dataSource.nibName owner:nil options:nil] firstObject]; 70 | } else { 71 | cell = [[UITableViewCell alloc] init]; 72 | } 73 | id item; 74 | if (dataSource.data && dataSource.data.count > 0) { 75 | if (dataSource.sectionCount == 1 && dataSource.data.count > indexPath.row) { 76 | item = [dataSource itemAtIndex:indexPath]; 77 | } else if (dataSource.sectionCount > 1 && [dataSource.data[indexPath.section] isKindOfClass:[NSArray class]]) { 78 | item = dataSource.data[indexPath.section][indexPath.row]; 79 | } 80 | } 81 | if (dataSource.cellBlock) { 82 | dataSource.cellBlock(cell, item, indexPath); 83 | } 84 | 85 | height = cell.height; 86 | 87 | } else if (delegate.heightForRowAtIndexPathBlock) { 88 | height = delegate.heightForRowAtIndexPathBlock(indexPath); 89 | } else { 90 | NSLog(@"未配置cellConfigHandler的情况下请自行实现“tableView:heightForRowAtIndexPath:”计算高度!"); 91 | } 92 | 93 | [self cacheHeightStoreWithIndexPath:indexPath height:height]; 94 | // self.heightStore[indexPath.section][indexPath.row] = @(height); 95 | } 96 | return height; 97 | } 98 | 99 | #pragma mark - 属性 100 | - (NSMutableArray *)heightStore { 101 | return objc_getAssociatedObject(self, _cmd); 102 | } 103 | - (void)setHeightStore:(NSMutableArray *)heightStore { 104 | objc_setAssociatedObject(self, @selector(heightStore), heightStore, OBJC_ASSOCIATION_RETAIN); 105 | } 106 | 107 | - (BOOL)autoCellHeight { 108 | return [objc_getAssociatedObject(self, &kKCAutoCellHeightKey) boolValue]; 109 | } 110 | - (void)setAutoCellHeight:(BOOL)autoCellHeight { 111 | objc_setAssociatedObject(self, &kKCAutoCellHeightKey, @(autoCellHeight), OBJC_ASSOCIATION_ASSIGN); 112 | } 113 | 114 | #pragma mark - 私有方法 115 | - (void)buildEmptyHeightStoreIfNeedWithIndexPaths:(NSArray *)indexPaths { 116 | if (!self.heightStore) { 117 | self.heightStore = [NSMutableArray array]; 118 | } 119 | [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) { 120 | for (int i=0; i<=indexPath.section; ++i) { 121 | if (i>=self.heightStore.count) { 122 | self.heightStore[i]=@[].mutableCopy; 123 | } 124 | } 125 | NSMutableArray *rows=self.heightStore[indexPath.section]; 126 | for (int j=0; j<=indexPath.row; ++j) { 127 | if (j>=rows.count) { 128 | rows[j]=@(0); 129 | } 130 | } 131 | }]; 132 | } 133 | - (CGFloat)getCachedHeightWithIndexPath:(NSIndexPath *)indexPath { 134 | [self buildEmptyHeightStoreIfNeedWithIndexPaths:@[ indexPath ]]; 135 | return [self.heightStore[indexPath.section][indexPath.row] floatValue]; 136 | } 137 | - (void)cacheHeightStoreWithIndexPath:(NSIndexPath *)indexPath height:(CGFloat)height { 138 | [self buildEmptyHeightStoreIfNeedWithIndexPaths:@[ indexPath ]]; 139 | self.heightStore[indexPath.section][indexPath.row] = @(height); 140 | } 141 | //即将缓存但是还没有缓存的分组和行 142 | - (NSArray *)indexPathsOfHaveNoCache { 143 | NSMutableArray *toBeCacheIndexPaths = [NSMutableArray array]; 144 | NSInteger sectionCount = [self numberOfSections]; 145 | for (NSInteger i = 0; i < sectionCount; ++i) { 146 | NSInteger rowCount = [self numberOfRowsInSection:i]; 147 | for (NSInteger j = 0; j < rowCount; ++j) { 148 | NSIndexPath *indexPath=[NSIndexPath indexPathForRow:j inSection:i]; 149 | [self buildEmptyHeightStoreIfNeedWithIndexPaths:@[indexPath]]; 150 | CGFloat height = [self.heightStore[i][j] floatValue]; 151 | if (height == 0) { 152 | [toBeCacheIndexPaths addObject:[NSIndexPath indexPathForRow:j inSection:i]]; 153 | } 154 | } 155 | } 156 | return [toBeCacheIndexPaths copy]; 157 | } 158 | - (void)preCacheHeightStore { 159 | if (!self.autoCellHeight) { 160 | return; 161 | } 162 | if (![self.delegate respondsToSelector:@selector(tableView:heightForRowAtIndexPath:)]) { 163 | return; 164 | } 165 | NSMutableArray *indexPathsOfHaveNoCache = [self indexPathsOfHaveNoCache].mutableCopy; 166 | CFRunLoopRef runloop = CFRunLoopGetCurrent(); 167 | CFStringRef mode = kCFRunLoopDefaultMode; 168 | CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { 169 | if (indexPathsOfHaveNoCache.count==0) { 170 | CFRunLoopRemoveObserver(runloop, observer, mode); 171 | CFRelease(observer); 172 | return ; 173 | } 174 | NSIndexPath *indexPath=indexPathsOfHaveNoCache.firstObject; 175 | [indexPathsOfHaveNoCache removeObject:indexPath]; 176 | 177 | [self performSelectorOnMainThread:@selector(preCacheHeightWithIndexPath:) withObject:indexPath waitUntilDone:NO modes:@[NSDefaultRunLoopMode]]; 178 | }); 179 | CFRunLoopAddObserver(runloop, observer, mode); 180 | } 181 | - (void)preCacheHeightWithIndexPath:(NSIndexPath *)indexPath { 182 | CGFloat height = [self.delegate tableView:self heightForRowAtIndexPath:indexPath]; 183 | self.heightStore[indexPath.section][indexPath.row] = @(height); 184 | } 185 | 186 | #pragma mark - Swizzle方法 187 | - (void)kc_reloadData { 188 | if (self.autoCellHeight) { 189 | [self.heightStore removeAllObjects]; 190 | } 191 | 192 | [self kc_reloadData]; 193 | [self preCacheHeightStore]; 194 | } 195 | - (void)kc_insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation { 196 | if (self.autoCellHeight) { 197 | [sections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 198 | [self.heightStore insertObject:@[].mutableCopy atIndex:idx]; 199 | }]; 200 | } 201 | 202 | [self kc_insertSections:sections withRowAnimation:animation]; 203 | [self preCacheHeightStore]; 204 | } 205 | - (void)kc_deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation { 206 | if (self.autoCellHeight) { 207 | [sections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 208 | [self.heightStore removeObjectAtIndex:idx]; 209 | }]; 210 | } 211 | [self kc_deleteSections:sections withRowAnimation:animation]; 212 | } 213 | - (void)kc_reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation { 214 | if (self.autoCellHeight) { 215 | [sections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 216 | if (idx