├── .gitignore ├── AITableView.podspec ├── AITableView ├── AITableView.h ├── AITableView.m ├── AITableViewProtocal.h ├── AITableViewSection.h └── AITableViewSection.m ├── AITableViewDemo ├── AITableViewDemo.xcodeproj │ └── project.pbxproj ├── AITableViewDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── DemoNameCellModel.h │ ├── DemoNameCellModel.m │ ├── DemoTableViewFooterView.h │ ├── DemoTableViewFooterView.m │ ├── DemoTableViewFooterView.xib │ ├── DemoTableViewHeaderView.h │ ├── DemoTableViewHeaderView.m │ ├── DemoTableViewNameCell.h │ ├── DemoTableViewNameCell.m │ ├── DemoTableViewPhoneCell.h │ ├── DemoTableViewPhoneCell.m │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ └── main.m └── AITableViewDemoTests │ ├── AITableViewDemoTests.m │ └── Info.plist ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 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 | project.xcworkspace 14 | profile 15 | *.moved-aside 16 | DerivedData 17 | .idea/ 18 | .svn/ 19 | *.hmap 20 | *.xccheckout 21 | node_modules/ 22 | xcshareddata/ 23 | 24 | -------------------------------------------------------------------------------- /AITableView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "AITableView" 3 | s.version = "0.1.1" 4 | s.summary = "An amazing tableview." 5 | s.description = <<-DESC 6 | It is a tableview used on iOS, which implement by Objective-C. 7 | DESC 8 | s.homepage = "https://github.com/chentoo/AITableView" 9 | # s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2" 10 | s.license = 'MIT' 11 | s.author = { "chentoo" => "chentoo@gmail.com" } 12 | s.source = { :git => "https://github.com/chentoo/AITableView.git", :tag => s.version.to_s } 13 | # s.social_media_url = 'https://weibo.com/chentoo' 14 | 15 | s.platform = :ios, '7.0' 16 | # s.ios.deployment_target = '6.0' 17 | # s.osx.deployment_target = '10.7' 18 | s.requires_arc = true 19 | 20 | s.source_files = 'AITableView/*' 21 | # s.resources = 'Assets' 22 | 23 | # s.ios.exclude_files = 'Classes/osx' 24 | # s.osx.exclude_files = 'Classes/ios' 25 | # s.public_header_files = 'Classes/**/*.h' 26 | s.frameworks = 'Foundation', 'UIKit' 27 | 28 | end -------------------------------------------------------------------------------- /AITableView/AITableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // AITableView.h 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 15/7/7. 6 | // Copyright (c) 2015年 chentoo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AITableViewSection.h" 11 | 12 | @interface AITableViewStaticCellModel : NSObject 13 | 14 | @property (strong, nonatomic) NSString *value; 15 | 16 | @end 17 | 18 | @interface AITableViewStaticHeaderFooterModel : NSObject 19 | 20 | @property (strong, nonatomic) NSString *value; 21 | 22 | @end 23 | 24 | @class AITableView; 25 | 26 | @protocol AITableViewDelegate 27 | 28 | - (void)tableView:(AITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath withCellModel:(id)cellModel; 29 | 30 | @end 31 | 32 | typedef void(^AITableViewDidSelectRowBlock)(AITableView *tableView, NSIndexPath *indexPath, id cellModel); 33 | 34 | @interface AITableView : UITableView 35 | 36 | @property (nonatomic, weak) id AIDelegate; 37 | 38 | + (instancetype)tableView; 39 | + (instancetype)tableViewWithFrame:(CGRect)frame; 40 | - (void)setAIDidSelectRowBlock:(AITableViewDidSelectRowBlock)didSelectRowBlock; 41 | 42 | #pragma mark - Cell 43 | 44 | //如果cell不需要对应的model来完成配置,第二个参数请传nil。 45 | //但建议使用 - bindStatacCellClass 来完成 cell bind。 46 | - (void)bindCellClass:(Class)cellClass withModelClass:(Class)modelClass; 47 | - (void)bindCellNibClass:(Class)cellNibClass withModelClass:(Class)modelClass; 48 | 49 | //如果cell不需要对应的model来完成配置,请使用这个方法bind它。 50 | - (void)bindStaticCellWithCellClass:(Class)cellClass; 51 | - (void)bindStaticCellWithCellNibClass:(Class)cellNibClass; 52 | 53 | //如果cell不需要对应的model来完成配置,可以用此方法生成一个这个cell对应的model,放入updateTabelViewWithModels的models 中。 54 | - (AITableViewStaticCellModel *)modelWithStaticCellClass:(Class)cellClass; 55 | 56 | //更新tableview,根据传入的models 57 | - (void)updateTableViewWithModels:(NSArray *)models; 58 | 59 | //如果需要有多个Section 可用以下方法拼装 60 | #pragma mark - Section 61 | 62 | - (void)bindHeaderFooterClass:(Class)sectionClass withModelClass:(Class)modelClass; 63 | - (void)bindHeaderFooterNibClass:(Class)sectionNibClass withModelClass:(Class)modelClass; 64 | 65 | //如果section不需要对应的model来完成配置,请使用这个方法bind它。 66 | - (void)bindStaticHeaderFooterWithClass:(Class)headerFooterClass; 67 | - (void)bindStaticHeaderFooterWithNibClass:(Class)headerFooterNibClass; 68 | 69 | //如果HeaderFooter不需要对应的model来完成配置,可以用此方法生成一个这个cell对应的HeaderFooter。 70 | - (AITableViewStaticHeaderFooterModel *)modelWithStaticHeaderFooterClass:(Class)headerFooterClass; 71 | 72 | - (void)updateTableViewWithSections:(NSArray *)sections; 73 | 74 | 75 | @end 76 | 77 | -------------------------------------------------------------------------------- /AITableView/AITableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // AITableView.m 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 15/7/7. 6 | // Copyright (c) 2015年 chentoo. All rights reserved. 7 | // 8 | 9 | #import "AITableView.h" 10 | #import "AITableViewProtocal.h" 11 | 12 | @implementation AITableViewStaticCellModel 13 | 14 | @end 15 | 16 | @implementation AITableViewStaticHeaderFooterModel 17 | 18 | @end 19 | 20 | static NSString * const kAITableViewBindDicModelDefault = @"kAITableViewBindDicModelDefault"; 21 | 22 | @interface AITableView () 23 | 24 | @property (strong, nonatomic) NSMutableDictionary *bindDic; 25 | @property (strong, nonatomic) NSMutableDictionary *bindSectionDic; 26 | @property (strong, nonatomic) NSArray *models; 27 | @property (strong, nonatomic) NSArray *sections; 28 | @property (nonatomic, copy) AITableViewDidSelectRowBlock didSelectRowBlock; 29 | 30 | @end 31 | 32 | @implementation AITableView 33 | 34 | - (instancetype)init 35 | { 36 | self = [super init]; 37 | if (self) { 38 | _models = [NSArray array]; 39 | _sections = [NSArray array]; 40 | _bindDic = [NSMutableDictionary dictionary]; 41 | _bindSectionDic = [NSMutableDictionary dictionary]; 42 | self.dataSource = self; 43 | self.delegate = self; 44 | self.tableFooterView = [[UIView alloc] init]; 45 | } 46 | return self; 47 | } 48 | 49 | + (instancetype)tableView 50 | { 51 | AITableView *tableView = [[AITableView alloc] init]; 52 | 53 | return tableView; 54 | } 55 | 56 | + (instancetype)tableViewWithFrame:(CGRect)frame 57 | { 58 | AITableView *tableView = [AITableView tableView]; 59 | tableView.frame = frame; 60 | 61 | return tableView; 62 | } 63 | 64 | - (void)setAIDidSelectRowBlock:(AITableViewDidSelectRowBlock)didSelectRowBlock 65 | { 66 | self.didSelectRowBlock = didSelectRowBlock; 67 | } 68 | 69 | #pragma mark - Cell Public 70 | 71 | - (void)bindCellClass:(Class)cellClass withModelClass:(Class)modelClass 72 | { 73 | [self registerCellWithClass:cellClass]; 74 | if (modelClass) 75 | { 76 | [self.bindDic setObject:NSStringFromClass(cellClass) forKey:NSStringFromClass(modelClass)]; 77 | } 78 | else 79 | { 80 | NSString *key = [self keyOfBindDicWithStaticCellClassName:NSStringFromClass(cellClass)]; 81 | [self.bindDic setObject:NSStringFromClass(cellClass) forKey:key]; 82 | } 83 | } 84 | 85 | - (void)bindCellNibClass:(Class)cellNibClass withModelClass:(Class)modelClass 86 | { 87 | [self registerCellWithNib:cellNibClass]; 88 | if (modelClass) 89 | { 90 | [self.bindDic setObject:NSStringFromClass(cellNibClass) forKey:NSStringFromClass(modelClass)]; 91 | } 92 | else 93 | { 94 | NSString *key = [self keyOfBindDicWithStaticCellClassName:NSStringFromClass(cellNibClass)]; 95 | [self.bindDic setObject:NSStringFromClass(cellNibClass) forKey:key]; 96 | 97 | } 98 | } 99 | 100 | - (void)bindStaticCellWithCellClass:(Class)cellClass 101 | { 102 | [self bindCellClass:cellClass withModelClass:Nil]; 103 | } 104 | 105 | - (void)bindStaticCellWithCellNibClass:(Class)cellNibClass 106 | { 107 | [self bindCellNibClass:cellNibClass withModelClass:Nil]; 108 | } 109 | 110 | - (AITableViewStaticCellModel *)modelWithStaticCellClass:(Class)cellClass 111 | { 112 | AITableViewStaticCellModel *model = [[AITableViewStaticCellModel alloc] init]; 113 | model.value = [self keyOfBindDicWithStaticCellClassName:NSStringFromClass(cellClass)]; 114 | return model; 115 | } 116 | 117 | - (void)updateTableViewWithModels:(NSArray *)models 118 | { 119 | self.models = models; 120 | [self reloadData]; 121 | } 122 | 123 | #pragma mark - Section Public 124 | 125 | - (void)bindHeaderFooterClass:(Class)sectionClass withModelClass:(Class)modelClass 126 | { 127 | [self registerSectionWithClass:sectionClass]; 128 | if (modelClass) 129 | { 130 | [self.bindSectionDic setObject:NSStringFromClass(sectionClass) forKey:NSStringFromClass(modelClass)]; 131 | } 132 | else 133 | { 134 | NSString *key = [self keyOfBindSectionDicWithStaticSectionClassName:NSStringFromClass(sectionClass)]; 135 | [self.bindSectionDic setObject:NSStringFromClass(sectionClass) forKey:key]; 136 | } 137 | } 138 | 139 | - (void)bindHeaderFooterNibClass:(Class)sectionNibClass withModelClass:(Class)modelClass 140 | { 141 | [self registerSectionWithNibClass:sectionNibClass]; 142 | if (modelClass) 143 | { 144 | [self.bindSectionDic setObject:NSStringFromClass(sectionNibClass) forKey:NSStringFromClass(modelClass)]; 145 | } 146 | else 147 | { 148 | NSString *key = [self keyOfBindSectionDicWithStaticSectionClassName:NSStringFromClass(sectionNibClass)]; 149 | [self.bindSectionDic setObject:NSStringFromClass(sectionNibClass) forKey:key]; 150 | } 151 | } 152 | 153 | - (void)bindStaticHeaderFooterWithClass:(Class)headerFooterClass 154 | { 155 | [self bindHeaderFooterClass:headerFooterClass withModelClass:Nil]; 156 | } 157 | 158 | - (void)bindStaticHeaderFooterWithNibClass:(Class)headerFooterNibClass 159 | { 160 | [self bindHeaderFooterNibClass:headerFooterNibClass withModelClass:Nil]; 161 | } 162 | 163 | - (AITableViewStaticHeaderFooterModel *)modelWithStaticHeaderFooterClass:(Class)headerFooterClass 164 | { 165 | AITableViewStaticHeaderFooterModel *model = [[AITableViewStaticHeaderFooterModel alloc] init]; 166 | model.value = [self keyOfBindSectionDicWithStaticSectionClassName:NSStringFromClass(headerFooterClass)]; 167 | return model; 168 | } 169 | 170 | - (void)updateTableViewWithSections:(NSArray *)sections 171 | { 172 | self.sections = sections; 173 | self.models = nil; 174 | [self reloadData]; 175 | } 176 | 177 | 178 | #pragma mark - Reigster Cell 179 | 180 | - (void)registerCellWithClass:(Class)cellClass 181 | { 182 | if(![cellClass conformsToProtocol:@protocol(AITableViewCellProtocal)]) 183 | { 184 | NSAssert(NO, @"Your cell did not have protocal : AITableViewCellProtocal"); 185 | return; 186 | } 187 | 188 | NSString *cellIdentifier = [self identifierOfCellClass:cellClass]; 189 | NSAssert(cellIdentifier, @"Your cell protocal AITableViewCellProtocal 's method :' + reuseIdentifier ' return nil or empty!"); 190 | 191 | [self registerClass:cellClass forCellReuseIdentifier:cellIdentifier]; 192 | } 193 | 194 | - (void)registerCellWithNib:(Class)nibClass 195 | { 196 | if(![nibClass conformsToProtocol:@protocol(AITableViewCellProtocal)]) 197 | { 198 | NSAssert(NO, @"Your cell did not have protocal : AITableViewCellProtocal"); 199 | return; 200 | } 201 | 202 | NSString *cellIdentifier = [self identifierOfCellClass:nibClass]; 203 | NSAssert(cellIdentifier, @"Your cell protocal AITableViewCellProtocal 's method :' + reuseIdentifier ' return nil or empty!"); 204 | 205 | NSBundle *mainBundle = [NSBundle mainBundle]; 206 | NSString *path = [mainBundle pathForResource:NSStringFromClass(nibClass) ofType:@"nib"]; 207 | NSAssert(path, @"Your cell class nib is nil!"); 208 | if (path.length > 0) { 209 | UINib *nib = [UINib nibWithNibName:NSStringFromClass(nibClass) bundle:nil]; 210 | [self registerNib:nib forCellReuseIdentifier:cellIdentifier]; 211 | } 212 | } 213 | 214 | #pragma mark - Reigster Section 215 | 216 | - (void)registerSectionWithClass:(Class)sectionClass 217 | { 218 | if(![sectionClass conformsToProtocol:@protocol(AITableViewSectionProtocal)]) 219 | { 220 | NSAssert(NO, @"Your sectionClass did not have protocal : AITableViewSectionProtocal"); 221 | return; 222 | } 223 | NSString *sectionIdentifier = [self identifierOfSectionClass:sectionClass]; 224 | if (sectionIdentifier.length == 0) { 225 | NSAssert(NO, @"Your section protocal AITableViewSectionProtocal 's method :' + reuseIdentifier ' return nil or empty!"); 226 | } 227 | else { 228 | [self registerClass:sectionClass forHeaderFooterViewReuseIdentifier:sectionIdentifier]; 229 | } 230 | } 231 | 232 | - (void)registerSectionWithNibClass:(Class)sectionNibClass 233 | { 234 | if(![sectionNibClass conformsToProtocol:@protocol(AITableViewSectionProtocal)]) 235 | { 236 | NSAssert(NO, @"Your sectionClass did not have protocal : AITableViewSectionProtocal"); 237 | return; 238 | } 239 | NSString *sectionIdentifier = [self identifierOfSectionClass:sectionNibClass]; 240 | if (sectionIdentifier.length == 0) { 241 | NSAssert(NO, @"Your section protocal AITableViewSectionProtocal 's method :' + reuseIdentifier ' return nil or empty!"); 242 | } 243 | else { 244 | NSBundle *mainBundle = [NSBundle mainBundle]; 245 | NSString *path = [mainBundle pathForResource:NSStringFromClass(sectionNibClass) ofType:@"nib"]; 246 | NSAssert(path, @"Your cell class nib is nil!"); 247 | if (path.length > 0) { 248 | UINib *nib = [UINib nibWithNibName:NSStringFromClass(sectionNibClass) bundle:nil]; 249 | [self registerNib:nib forHeaderFooterViewReuseIdentifier:sectionIdentifier]; 250 | } 251 | } 252 | } 253 | 254 | #pragma mark - Cell Private 255 | 256 | - (NSString *)keyOfBindDicWithStaticCellClassName:(NSString *)cellClassName 257 | { 258 | return [kAITableViewBindDicModelDefault stringByAppendingString:cellClassName]; 259 | } 260 | 261 | - (NSString *)identifierOfCellClass:(Class)cellClass 262 | { 263 | // Class cellClassProtocal = cellClass; 264 | // return [cellClassProtocal AIReuseIdentifier]; 265 | return NSStringFromClass(cellClass); 266 | } 267 | 268 | - (Class)cellClassWithBindModel:(id)model 269 | { 270 | NSString *cellModelClassName; 271 | if ([model isKindOfClass:[AITableViewStaticCellModel class]]) 272 | { 273 | cellModelClassName = [(AITableViewStaticCellModel *)model value]; 274 | } 275 | else 276 | { 277 | cellModelClassName = NSStringFromClass([model class]); 278 | } 279 | 280 | NSString *cellClassName = self.bindDic[cellModelClassName]; 281 | Class cellClass = NSClassFromString(cellClassName); 282 | return cellClass; 283 | } 284 | 285 | #pragma mark - Section Private 286 | 287 | - (NSString *)keyOfBindSectionDicWithStaticSectionClassName:(NSString *)sectionClassName 288 | { 289 | return [kAITableViewBindDicModelDefault stringByAppendingString:sectionClassName]; 290 | } 291 | 292 | - (NSString *)identifierOfSectionClass:(Class)sectionClass 293 | { 294 | // Class sectionClassProtocal = sectionClass; 295 | // return [sectionClassProtocal AIReuseIdentifier]; 296 | return NSStringFromClass(sectionClass); 297 | } 298 | 299 | - (Class)sectionClassWithBindModel:(id)model 300 | { 301 | NSString *sectionModelClassName; 302 | if ([model isKindOfClass:[AITableViewStaticHeaderFooterModel class]]) 303 | { 304 | sectionModelClassName = [(AITableViewStaticHeaderFooterModel *)model value]; 305 | } 306 | else 307 | { 308 | sectionModelClassName = NSStringFromClass([model class]); 309 | } 310 | 311 | NSString *sectionClassName = self.bindSectionDic[sectionModelClassName]; 312 | Class sectionClass = NSClassFromString(sectionClassName); 313 | return sectionClass; 314 | } 315 | 316 | #pragma mark - UITableView Datesource 317 | 318 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 319 | { 320 | return MAX(self.sections.count, 1); 321 | } 322 | 323 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 324 | { 325 | if (self.sections.count > 0) { 326 | AITableViewSection *sectionObject = self.sections[section]; 327 | 328 | return sectionObject.cellModels.count; 329 | } 330 | return self.models.count; 331 | } 332 | 333 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 334 | { 335 | id cellModel; 336 | if (self.sections.count > 0) { 337 | AITableViewSection *sectionObject = self.sections[indexPath.section]; 338 | cellModel = sectionObject.cellModels[indexPath.row]; 339 | } 340 | else { 341 | cellModel = self.models[indexPath.row]; 342 | } 343 | 344 | Class cellClass = [self cellClassWithBindModel:cellModel]; 345 | 346 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[self identifierOfCellClass:cellClass] forIndexPath:indexPath]; 347 | [cell performSelector:@selector(AIConfigureWithModel:) withObject:cellModel]; 348 | 349 | return cell; 350 | } 351 | 352 | - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 353 | { 354 | if (self.sections.count > 0) { 355 | AITableViewSection *sectionObject = self.sections[section]; 356 | if (!sectionObject.headerModel) { 357 | return nil; 358 | } 359 | Class sectionClass = [self sectionClassWithBindModel:sectionObject.headerModel]; 360 | 361 | UITableViewHeaderFooterView *headerView = [self dequeueReusableHeaderFooterViewWithIdentifier:[self identifierOfSectionClass:sectionClass]]; 362 | [headerView performSelector:@selector(AIConfigureWithModel:) withObject:sectionObject.headerModel]; 363 | return headerView; 364 | } 365 | return nil; 366 | } 367 | 368 | - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section 369 | { 370 | if (self.sections.count > 0) { 371 | AITableViewSection *sectionObject = self.sections[section]; 372 | if (!sectionObject.footerModel) { 373 | return nil; 374 | } 375 | Class sectionClass = [self sectionClassWithBindModel:sectionObject.footerModel]; 376 | 377 | UITableViewHeaderFooterView *footerView = [self dequeueReusableHeaderFooterViewWithIdentifier:[self identifierOfSectionClass:sectionClass]]; 378 | [footerView performSelector:@selector(AIConfigureWithModel:) withObject:sectionObject.footerModel]; 379 | return footerView; 380 | } 381 | return nil; 382 | } 383 | 384 | #pragma mark - UITableView Delegate 385 | 386 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 387 | { 388 | id cellModel; 389 | if (self.sections.count > 0) { 390 | AITableViewSection *sectionObject = self.sections[indexPath.section]; 391 | cellModel = sectionObject.cellModels[indexPath.row]; 392 | } 393 | else { 394 | cellModel = self.models[indexPath.row]; 395 | } 396 | 397 | Class cellClass = [self cellClassWithBindModel:cellModel]; 398 | Class cellClassProtocal = cellClass; 399 | 400 | return [cellClassProtocal AIHeightWithModel:cellModel]; 401 | } 402 | 403 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 404 | { 405 | if (self.sections.count > 0) { 406 | AITableViewSection *sectionObject = self.sections[section]; 407 | if (!sectionObject.headerModel) { 408 | return 0; 409 | } 410 | Class sectionClass = [self sectionClassWithBindModel:sectionObject.headerModel]; 411 | Class sectionClassProtocal = sectionClass; 412 | 413 | return [sectionClassProtocal AIHeightWithModel:sectionObject.headerModel]; 414 | } 415 | return 0; 416 | } 417 | 418 | - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 419 | { 420 | if (self.sections.count > 0) { 421 | AITableViewSection *sectionObject = self.sections[section]; 422 | if (!sectionObject.footerModel) { 423 | return 0; 424 | } 425 | Class sectionClass = [self sectionClassWithBindModel:sectionObject.footerModel]; 426 | Class sectionClassProtocal = sectionClass; 427 | 428 | return [sectionClassProtocal AIHeightWithModel:sectionObject.footerModel]; 429 | } 430 | return 0; 431 | } 432 | 433 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 434 | { 435 | id cellModel; 436 | if (self.sections.count > 0) { 437 | AITableViewSection *sectionObject = self.sections[indexPath.section]; 438 | cellModel = sectionObject.cellModels[indexPath.row]; 439 | } 440 | else { 441 | cellModel = self.models[indexPath.row]; 442 | } 443 | 444 | // AITableView delegate 方式传递cell select事件 445 | 446 | id strongDelegate = self.AIDelegate; 447 | if ([strongDelegate respondsToSelector:@selector(tableView:didSelectRowAtIndexPath:withCellModel:)]) { 448 | [strongDelegate tableView:self didSelectRowAtIndexPath:indexPath withCellModel:cellModel]; 449 | } 450 | 451 | // AITableView Block 方式传递cell select事件 452 | 453 | if (self.didSelectRowBlock) { 454 | self.didSelectRowBlock(self, indexPath, cellModel); 455 | } 456 | 457 | // AITableViewModelProtocal 方式,向model传递 cell select 事件 458 | 459 | id modelProtocal = cellModel; 460 | if ([modelProtocal respondsToSelector:@selector(AIDidSelectBlock)]) { 461 | AITableViewCellDidSelectBlock didSelectBlock = [modelProtocal AIDidSelectBlock]; 462 | if (didSelectBlock) { 463 | didSelectBlock(indexPath); 464 | } 465 | } 466 | } 467 | 468 | @end 469 | 470 | -------------------------------------------------------------------------------- /AITableView/AITableViewProtocal.h: -------------------------------------------------------------------------------- 1 | // 2 | // AITableViewCellProtocal.h 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 15/7/7. 6 | // Copyright (c) 2015年 chentoo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol AITableViewCellProtocal 12 | 13 | @required 14 | - (void)AIConfigureWithModel:(id)model; 15 | + (CGFloat)AIHeightWithModel:(id)model; 16 | 17 | @end 18 | 19 | @protocol AITableViewSectionProtocal 20 | 21 | @required 22 | - (void)AIConfigureWithModel:(id)model; 23 | + (CGFloat)AIHeightWithModel:(id)model; 24 | 25 | @end 26 | 27 | typedef void(^AITableViewCellDidSelectBlock)(NSIndexPath *indexPath); 28 | 29 | @protocol AITableViewModelProtocal 30 | 31 | @optional 32 | 33 | @property (nonatomic, copy) AITableViewCellDidSelectBlock AIDidSelectBlock; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /AITableView/AITableViewSection.h: -------------------------------------------------------------------------------- 1 | // 2 | // AITableViewSection.h 3 | // AITableViewDemo 4 | // 5 | // Created by chentoo on 15/8/20. 6 | // Copyright (c) 2015年 chentoo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AITableViewSection : NSObject 12 | 13 | @property (strong, nonatomic) id headerModel; 14 | @property (strong, nonatomic) id footerModel; 15 | @property (strong, nonatomic) NSArray *cellModels; 16 | 17 | + (instancetype)sectionWithHeaderModel:(id)sectionHeaderModel 18 | footerModel:(id)sectionFooterModel 19 | cellModels:(NSArray *)cellModels; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /AITableView/AITableViewSection.m: -------------------------------------------------------------------------------- 1 | // 2 | // AITableViewSection.m 3 | // AITableViewDemo 4 | // 5 | // Created by chentoo on 15/8/20. 6 | // Copyright (c) 2015年 chentoo. All rights reserved. 7 | // 8 | 9 | #import "AITableViewSection.h" 10 | 11 | @implementation AITableViewSection 12 | 13 | - (instancetype)init 14 | { 15 | self = [super init]; 16 | if (self) { 17 | _cellModels = [NSArray array]; 18 | } 19 | return self; 20 | } 21 | 22 | 23 | + (instancetype)sectionWithHeaderModel:(id)sectionHeaderModel 24 | footerModel:(id)sectionFooterModel 25 | cellModels:(NSArray *)cellModels 26 | { 27 | AITableViewSection *sectionObject = [[AITableViewSection alloc] init]; 28 | 29 | sectionObject.headerModel = sectionHeaderModel; 30 | sectionObject.footerModel = sectionFooterModel; 31 | sectionObject.cellModels = cellModels; 32 | 33 | return sectionObject; 34 | } 35 | 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | DA022A421B85A9CE00AC299C /* AITableViewSection.m in Sources */ = {isa = PBXBuildFile; fileRef = DA022A411B85A9CE00AC299C /* AITableViewSection.m */; }; 11 | DA022A451B85B60600AC299C /* DemoTableViewHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA022A441B85B60600AC299C /* DemoTableViewHeaderView.m */; }; 12 | DA0A9CD01B86FDEA0031EC1A /* DemoTableViewFooterView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0A9CCF1B86FDEA0031EC1A /* DemoTableViewFooterView.m */; }; 13 | DA0A9CD21B8706540031EC1A /* DemoTableViewFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA0A9CD11B8706540031EC1A /* DemoTableViewFooterView.xib */; }; 14 | DA14096F1B70A6130082A638 /* AITableView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA14096D1B70A6130082A638 /* AITableView.m */; }; 15 | DA796B851C61A5B900A15854 /* DemoTableViewNameCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DA796B841C61A5B900A15854 /* DemoTableViewNameCell.m */; }; 16 | DA796B881C61A66C00A15854 /* DemoNameCellModel.m in Sources */ = {isa = PBXBuildFile; fileRef = DA796B871C61A66C00A15854 /* DemoNameCellModel.m */; }; 17 | DA796B8B1C61B1DA00A15854 /* DemoTableViewPhoneCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DA796B8A1C61B1DA00A15854 /* DemoTableViewPhoneCell.m */; }; 18 | DAAC13261B4BC89100F7CFFB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DAAC13251B4BC89100F7CFFB /* main.m */; }; 19 | DAAC13291B4BC89100F7CFFB /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DAAC13281B4BC89100F7CFFB /* AppDelegate.m */; }; 20 | DAAC132C1B4BC89100F7CFFB /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAAC132B1B4BC89100F7CFFB /* ViewController.m */; }; 21 | DAAC132F1B4BC89100F7CFFB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAAC132D1B4BC89100F7CFFB /* Main.storyboard */; }; 22 | DAAC13311B4BC89100F7CFFB /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DAAC13301B4BC89100F7CFFB /* Images.xcassets */; }; 23 | DAAC13341B4BC89100F7CFFB /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = DAAC13321B4BC89100F7CFFB /* LaunchScreen.xib */; }; 24 | DAAC13401B4BC89100F7CFFB /* AITableViewDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAAC133F1B4BC89100F7CFFB /* AITableViewDemoTests.m */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | DAAC133A1B4BC89100F7CFFB /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = DAAC13181B4BC89100F7CFFB /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = DAAC131F1B4BC89100F7CFFB; 33 | remoteInfo = AITableViewDemo; 34 | }; 35 | /* End PBXContainerItemProxy section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | DA022A401B85A9CE00AC299C /* AITableViewSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AITableViewSection.h; sourceTree = ""; }; 39 | DA022A411B85A9CE00AC299C /* AITableViewSection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AITableViewSection.m; sourceTree = ""; }; 40 | DA022A431B85B60600AC299C /* DemoTableViewHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoTableViewHeaderView.h; sourceTree = ""; }; 41 | DA022A441B85B60600AC299C /* DemoTableViewHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoTableViewHeaderView.m; sourceTree = ""; }; 42 | DA0A9CCE1B86FDEA0031EC1A /* DemoTableViewFooterView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoTableViewFooterView.h; sourceTree = ""; }; 43 | DA0A9CCF1B86FDEA0031EC1A /* DemoTableViewFooterView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoTableViewFooterView.m; sourceTree = ""; }; 44 | DA0A9CD11B8706540031EC1A /* DemoTableViewFooterView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DemoTableViewFooterView.xib; sourceTree = ""; }; 45 | DA14096C1B70A6130082A638 /* AITableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AITableView.h; sourceTree = ""; }; 46 | DA14096D1B70A6130082A638 /* AITableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AITableView.m; sourceTree = ""; }; 47 | DA14096E1B70A6130082A638 /* AITableViewProtocal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AITableViewProtocal.h; sourceTree = ""; }; 48 | DA796B831C61A5B900A15854 /* DemoTableViewNameCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoTableViewNameCell.h; sourceTree = ""; }; 49 | DA796B841C61A5B900A15854 /* DemoTableViewNameCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoTableViewNameCell.m; sourceTree = ""; }; 50 | DA796B861C61A66C00A15854 /* DemoNameCellModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoNameCellModel.h; sourceTree = ""; }; 51 | DA796B871C61A66C00A15854 /* DemoNameCellModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoNameCellModel.m; sourceTree = ""; }; 52 | DA796B891C61B1D900A15854 /* DemoTableViewPhoneCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoTableViewPhoneCell.h; sourceTree = ""; }; 53 | DA796B8A1C61B1DA00A15854 /* DemoTableViewPhoneCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoTableViewPhoneCell.m; sourceTree = ""; }; 54 | DAAC13201B4BC89100F7CFFB /* AITableViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AITableViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | DAAC13241B4BC89100F7CFFB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | DAAC13251B4BC89100F7CFFB /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 57 | DAAC13271B4BC89100F7CFFB /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 58 | DAAC13281B4BC89100F7CFFB /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 59 | DAAC132A1B4BC89100F7CFFB /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 60 | DAAC132B1B4BC89100F7CFFB /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 61 | DAAC132E1B4BC89100F7CFFB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 62 | DAAC13301B4BC89100F7CFFB /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 63 | DAAC13331B4BC89100F7CFFB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 64 | DAAC13391B4BC89100F7CFFB /* AITableViewDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AITableViewDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | DAAC133E1B4BC89100F7CFFB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 66 | DAAC133F1B4BC89100F7CFFB /* AITableViewDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AITableViewDemoTests.m; sourceTree = ""; }; 67 | /* End PBXFileReference section */ 68 | 69 | /* Begin PBXFrameworksBuildPhase section */ 70 | DAAC131D1B4BC89100F7CFFB /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | ); 75 | runOnlyForDeploymentPostprocessing = 0; 76 | }; 77 | DAAC13361B4BC89100F7CFFB /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | /* End PBXFrameworksBuildPhase section */ 85 | 86 | /* Begin PBXGroup section */ 87 | DA14096B1B70A6130082A638 /* AITableView */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | DA14096C1B70A6130082A638 /* AITableView.h */, 91 | DA14096D1B70A6130082A638 /* AITableView.m */, 92 | DA022A401B85A9CE00AC299C /* AITableViewSection.h */, 93 | DA022A411B85A9CE00AC299C /* AITableViewSection.m */, 94 | DA14096E1B70A6130082A638 /* AITableViewProtocal.h */, 95 | ); 96 | name = AITableView; 97 | path = ../../AITableView; 98 | sourceTree = ""; 99 | }; 100 | DAAC13171B4BC89100F7CFFB = { 101 | isa = PBXGroup; 102 | children = ( 103 | DAAC13221B4BC89100F7CFFB /* AITableViewDemo */, 104 | DAAC133C1B4BC89100F7CFFB /* AITableViewDemoTests */, 105 | DAAC13211B4BC89100F7CFFB /* Products */, 106 | ); 107 | sourceTree = ""; 108 | }; 109 | DAAC13211B4BC89100F7CFFB /* Products */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | DAAC13201B4BC89100F7CFFB /* AITableViewDemo.app */, 113 | DAAC13391B4BC89100F7CFFB /* AITableViewDemoTests.xctest */, 114 | ); 115 | name = Products; 116 | sourceTree = ""; 117 | }; 118 | DAAC13221B4BC89100F7CFFB /* AITableViewDemo */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | DA14096B1B70A6130082A638 /* AITableView */, 122 | DAAC13271B4BC89100F7CFFB /* AppDelegate.h */, 123 | DAAC13281B4BC89100F7CFFB /* AppDelegate.m */, 124 | DA796B831C61A5B900A15854 /* DemoTableViewNameCell.h */, 125 | DA796B841C61A5B900A15854 /* DemoTableViewNameCell.m */, 126 | DA796B861C61A66C00A15854 /* DemoNameCellModel.h */, 127 | DA796B871C61A66C00A15854 /* DemoNameCellModel.m */, 128 | DA796B891C61B1D900A15854 /* DemoTableViewPhoneCell.h */, 129 | DA796B8A1C61B1DA00A15854 /* DemoTableViewPhoneCell.m */, 130 | DA022A431B85B60600AC299C /* DemoTableViewHeaderView.h */, 131 | DA022A441B85B60600AC299C /* DemoTableViewHeaderView.m */, 132 | DA0A9CCE1B86FDEA0031EC1A /* DemoTableViewFooterView.h */, 133 | DA0A9CCF1B86FDEA0031EC1A /* DemoTableViewFooterView.m */, 134 | DA0A9CD11B8706540031EC1A /* DemoTableViewFooterView.xib */, 135 | DAAC132A1B4BC89100F7CFFB /* ViewController.h */, 136 | DAAC132B1B4BC89100F7CFFB /* ViewController.m */, 137 | DAAC132D1B4BC89100F7CFFB /* Main.storyboard */, 138 | DAAC13301B4BC89100F7CFFB /* Images.xcassets */, 139 | DAAC13321B4BC89100F7CFFB /* LaunchScreen.xib */, 140 | DAAC13231B4BC89100F7CFFB /* Supporting Files */, 141 | ); 142 | path = AITableViewDemo; 143 | sourceTree = ""; 144 | }; 145 | DAAC13231B4BC89100F7CFFB /* Supporting Files */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | DAAC13241B4BC89100F7CFFB /* Info.plist */, 149 | DAAC13251B4BC89100F7CFFB /* main.m */, 150 | ); 151 | name = "Supporting Files"; 152 | sourceTree = ""; 153 | }; 154 | DAAC133C1B4BC89100F7CFFB /* AITableViewDemoTests */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | DAAC133F1B4BC89100F7CFFB /* AITableViewDemoTests.m */, 158 | DAAC133D1B4BC89100F7CFFB /* Supporting Files */, 159 | ); 160 | path = AITableViewDemoTests; 161 | sourceTree = ""; 162 | }; 163 | DAAC133D1B4BC89100F7CFFB /* Supporting Files */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | DAAC133E1B4BC89100F7CFFB /* Info.plist */, 167 | ); 168 | name = "Supporting Files"; 169 | sourceTree = ""; 170 | }; 171 | /* End PBXGroup section */ 172 | 173 | /* Begin PBXNativeTarget section */ 174 | DAAC131F1B4BC89100F7CFFB /* AITableViewDemo */ = { 175 | isa = PBXNativeTarget; 176 | buildConfigurationList = DAAC13431B4BC89100F7CFFB /* Build configuration list for PBXNativeTarget "AITableViewDemo" */; 177 | buildPhases = ( 178 | DAAC131C1B4BC89100F7CFFB /* Sources */, 179 | DAAC131D1B4BC89100F7CFFB /* Frameworks */, 180 | DAAC131E1B4BC89100F7CFFB /* Resources */, 181 | ); 182 | buildRules = ( 183 | ); 184 | dependencies = ( 185 | ); 186 | name = AITableViewDemo; 187 | productName = AITableViewDemo; 188 | productReference = DAAC13201B4BC89100F7CFFB /* AITableViewDemo.app */; 189 | productType = "com.apple.product-type.application"; 190 | }; 191 | DAAC13381B4BC89100F7CFFB /* AITableViewDemoTests */ = { 192 | isa = PBXNativeTarget; 193 | buildConfigurationList = DAAC13461B4BC89100F7CFFB /* Build configuration list for PBXNativeTarget "AITableViewDemoTests" */; 194 | buildPhases = ( 195 | DAAC13351B4BC89100F7CFFB /* Sources */, 196 | DAAC13361B4BC89100F7CFFB /* Frameworks */, 197 | DAAC13371B4BC89100F7CFFB /* Resources */, 198 | ); 199 | buildRules = ( 200 | ); 201 | dependencies = ( 202 | DAAC133B1B4BC89100F7CFFB /* PBXTargetDependency */, 203 | ); 204 | name = AITableViewDemoTests; 205 | productName = AITableViewDemoTests; 206 | productReference = DAAC13391B4BC89100F7CFFB /* AITableViewDemoTests.xctest */; 207 | productType = "com.apple.product-type.bundle.unit-test"; 208 | }; 209 | /* End PBXNativeTarget section */ 210 | 211 | /* Begin PBXProject section */ 212 | DAAC13181B4BC89100F7CFFB /* Project object */ = { 213 | isa = PBXProject; 214 | attributes = { 215 | LastUpgradeCheck = 0630; 216 | ORGANIZATIONNAME = chentoo; 217 | TargetAttributes = { 218 | DAAC131F1B4BC89100F7CFFB = { 219 | CreatedOnToolsVersion = 6.3; 220 | }; 221 | DAAC13381B4BC89100F7CFFB = { 222 | CreatedOnToolsVersion = 6.3; 223 | TestTargetID = DAAC131F1B4BC89100F7CFFB; 224 | }; 225 | }; 226 | }; 227 | buildConfigurationList = DAAC131B1B4BC89100F7CFFB /* Build configuration list for PBXProject "AITableViewDemo" */; 228 | compatibilityVersion = "Xcode 3.2"; 229 | developmentRegion = English; 230 | hasScannedForEncodings = 0; 231 | knownRegions = ( 232 | en, 233 | Base, 234 | ); 235 | mainGroup = DAAC13171B4BC89100F7CFFB; 236 | productRefGroup = DAAC13211B4BC89100F7CFFB /* Products */; 237 | projectDirPath = ""; 238 | projectRoot = ""; 239 | targets = ( 240 | DAAC131F1B4BC89100F7CFFB /* AITableViewDemo */, 241 | DAAC13381B4BC89100F7CFFB /* AITableViewDemoTests */, 242 | ); 243 | }; 244 | /* End PBXProject section */ 245 | 246 | /* Begin PBXResourcesBuildPhase section */ 247 | DAAC131E1B4BC89100F7CFFB /* Resources */ = { 248 | isa = PBXResourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | DAAC132F1B4BC89100F7CFFB /* Main.storyboard in Resources */, 252 | DAAC13341B4BC89100F7CFFB /* LaunchScreen.xib in Resources */, 253 | DAAC13311B4BC89100F7CFFB /* Images.xcassets in Resources */, 254 | DA0A9CD21B8706540031EC1A /* DemoTableViewFooterView.xib in Resources */, 255 | ); 256 | runOnlyForDeploymentPostprocessing = 0; 257 | }; 258 | DAAC13371B4BC89100F7CFFB /* Resources */ = { 259 | isa = PBXResourcesBuildPhase; 260 | buildActionMask = 2147483647; 261 | files = ( 262 | ); 263 | runOnlyForDeploymentPostprocessing = 0; 264 | }; 265 | /* End PBXResourcesBuildPhase section */ 266 | 267 | /* Begin PBXSourcesBuildPhase section */ 268 | DAAC131C1B4BC89100F7CFFB /* Sources */ = { 269 | isa = PBXSourcesBuildPhase; 270 | buildActionMask = 2147483647; 271 | files = ( 272 | DAAC132C1B4BC89100F7CFFB /* ViewController.m in Sources */, 273 | DA0A9CD01B86FDEA0031EC1A /* DemoTableViewFooterView.m in Sources */, 274 | DA022A421B85A9CE00AC299C /* AITableViewSection.m in Sources */, 275 | DA796B851C61A5B900A15854 /* DemoTableViewNameCell.m in Sources */, 276 | DA796B8B1C61B1DA00A15854 /* DemoTableViewPhoneCell.m in Sources */, 277 | DA14096F1B70A6130082A638 /* AITableView.m in Sources */, 278 | DAAC13291B4BC89100F7CFFB /* AppDelegate.m in Sources */, 279 | DA796B881C61A66C00A15854 /* DemoNameCellModel.m in Sources */, 280 | DAAC13261B4BC89100F7CFFB /* main.m in Sources */, 281 | DA022A451B85B60600AC299C /* DemoTableViewHeaderView.m in Sources */, 282 | ); 283 | runOnlyForDeploymentPostprocessing = 0; 284 | }; 285 | DAAC13351B4BC89100F7CFFB /* Sources */ = { 286 | isa = PBXSourcesBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | DAAC13401B4BC89100F7CFFB /* AITableViewDemoTests.m in Sources */, 290 | ); 291 | runOnlyForDeploymentPostprocessing = 0; 292 | }; 293 | /* End PBXSourcesBuildPhase section */ 294 | 295 | /* Begin PBXTargetDependency section */ 296 | DAAC133B1B4BC89100F7CFFB /* PBXTargetDependency */ = { 297 | isa = PBXTargetDependency; 298 | target = DAAC131F1B4BC89100F7CFFB /* AITableViewDemo */; 299 | targetProxy = DAAC133A1B4BC89100F7CFFB /* PBXContainerItemProxy */; 300 | }; 301 | /* End PBXTargetDependency section */ 302 | 303 | /* Begin PBXVariantGroup section */ 304 | DAAC132D1B4BC89100F7CFFB /* Main.storyboard */ = { 305 | isa = PBXVariantGroup; 306 | children = ( 307 | DAAC132E1B4BC89100F7CFFB /* Base */, 308 | ); 309 | name = Main.storyboard; 310 | sourceTree = ""; 311 | }; 312 | DAAC13321B4BC89100F7CFFB /* LaunchScreen.xib */ = { 313 | isa = PBXVariantGroup; 314 | children = ( 315 | DAAC13331B4BC89100F7CFFB /* Base */, 316 | ); 317 | name = LaunchScreen.xib; 318 | sourceTree = ""; 319 | }; 320 | /* End PBXVariantGroup section */ 321 | 322 | /* Begin XCBuildConfiguration section */ 323 | DAAC13411B4BC89100F7CFFB /* Debug */ = { 324 | isa = XCBuildConfiguration; 325 | buildSettings = { 326 | ALWAYS_SEARCH_USER_PATHS = NO; 327 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 328 | CLANG_CXX_LIBRARY = "libc++"; 329 | CLANG_ENABLE_MODULES = YES; 330 | CLANG_ENABLE_OBJC_ARC = YES; 331 | CLANG_WARN_BOOL_CONVERSION = YES; 332 | CLANG_WARN_CONSTANT_CONVERSION = YES; 333 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 334 | CLANG_WARN_EMPTY_BODY = YES; 335 | CLANG_WARN_ENUM_CONVERSION = YES; 336 | CLANG_WARN_INT_CONVERSION = YES; 337 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 338 | CLANG_WARN_UNREACHABLE_CODE = YES; 339 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 340 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 341 | COPY_PHASE_STRIP = NO; 342 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 343 | ENABLE_STRICT_OBJC_MSGSEND = YES; 344 | GCC_C_LANGUAGE_STANDARD = gnu99; 345 | GCC_DYNAMIC_NO_PIC = NO; 346 | GCC_NO_COMMON_BLOCKS = YES; 347 | GCC_OPTIMIZATION_LEVEL = 0; 348 | GCC_PREPROCESSOR_DEFINITIONS = ( 349 | "DEBUG=1", 350 | "$(inherited)", 351 | ); 352 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 353 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 354 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 355 | GCC_WARN_UNDECLARED_SELECTOR = YES; 356 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 357 | GCC_WARN_UNUSED_FUNCTION = YES; 358 | GCC_WARN_UNUSED_VARIABLE = YES; 359 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 360 | MTL_ENABLE_DEBUG_INFO = YES; 361 | ONLY_ACTIVE_ARCH = YES; 362 | SDKROOT = iphoneos; 363 | }; 364 | name = Debug; 365 | }; 366 | DAAC13421B4BC89100F7CFFB /* Release */ = { 367 | isa = XCBuildConfiguration; 368 | buildSettings = { 369 | ALWAYS_SEARCH_USER_PATHS = NO; 370 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 371 | CLANG_CXX_LIBRARY = "libc++"; 372 | CLANG_ENABLE_MODULES = YES; 373 | CLANG_ENABLE_OBJC_ARC = YES; 374 | CLANG_WARN_BOOL_CONVERSION = YES; 375 | CLANG_WARN_CONSTANT_CONVERSION = YES; 376 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 377 | CLANG_WARN_EMPTY_BODY = YES; 378 | CLANG_WARN_ENUM_CONVERSION = YES; 379 | CLANG_WARN_INT_CONVERSION = YES; 380 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 381 | CLANG_WARN_UNREACHABLE_CODE = YES; 382 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 383 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 384 | COPY_PHASE_STRIP = NO; 385 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 386 | ENABLE_NS_ASSERTIONS = NO; 387 | ENABLE_STRICT_OBJC_MSGSEND = YES; 388 | GCC_C_LANGUAGE_STANDARD = gnu99; 389 | GCC_NO_COMMON_BLOCKS = YES; 390 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 391 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 392 | GCC_WARN_UNDECLARED_SELECTOR = YES; 393 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 394 | GCC_WARN_UNUSED_FUNCTION = YES; 395 | GCC_WARN_UNUSED_VARIABLE = YES; 396 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 397 | MTL_ENABLE_DEBUG_INFO = NO; 398 | SDKROOT = iphoneos; 399 | VALIDATE_PRODUCT = YES; 400 | }; 401 | name = Release; 402 | }; 403 | DAAC13441B4BC89100F7CFFB /* Debug */ = { 404 | isa = XCBuildConfiguration; 405 | buildSettings = { 406 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 407 | CODE_SIGN_IDENTITY = "iPhone Developer"; 408 | INFOPLIST_FILE = AITableViewDemo/Info.plist; 409 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 410 | PRODUCT_NAME = "$(TARGET_NAME)"; 411 | }; 412 | name = Debug; 413 | }; 414 | DAAC13451B4BC89100F7CFFB /* Release */ = { 415 | isa = XCBuildConfiguration; 416 | buildSettings = { 417 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 418 | CODE_SIGN_IDENTITY = "iPhone Developer"; 419 | INFOPLIST_FILE = AITableViewDemo/Info.plist; 420 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 421 | PRODUCT_NAME = "$(TARGET_NAME)"; 422 | }; 423 | name = Release; 424 | }; 425 | DAAC13471B4BC89100F7CFFB /* Debug */ = { 426 | isa = XCBuildConfiguration; 427 | buildSettings = { 428 | BUNDLE_LOADER = "$(TEST_HOST)"; 429 | FRAMEWORK_SEARCH_PATHS = ( 430 | "$(SDKROOT)/Developer/Library/Frameworks", 431 | "$(inherited)", 432 | ); 433 | GCC_PREPROCESSOR_DEFINITIONS = ( 434 | "DEBUG=1", 435 | "$(inherited)", 436 | ); 437 | INFOPLIST_FILE = AITableViewDemoTests/Info.plist; 438 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 439 | PRODUCT_NAME = "$(TARGET_NAME)"; 440 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AITableViewDemo.app/AITableViewDemo"; 441 | }; 442 | name = Debug; 443 | }; 444 | DAAC13481B4BC89100F7CFFB /* Release */ = { 445 | isa = XCBuildConfiguration; 446 | buildSettings = { 447 | BUNDLE_LOADER = "$(TEST_HOST)"; 448 | FRAMEWORK_SEARCH_PATHS = ( 449 | "$(SDKROOT)/Developer/Library/Frameworks", 450 | "$(inherited)", 451 | ); 452 | INFOPLIST_FILE = AITableViewDemoTests/Info.plist; 453 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 454 | PRODUCT_NAME = "$(TARGET_NAME)"; 455 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AITableViewDemo.app/AITableViewDemo"; 456 | }; 457 | name = Release; 458 | }; 459 | /* End XCBuildConfiguration section */ 460 | 461 | /* Begin XCConfigurationList section */ 462 | DAAC131B1B4BC89100F7CFFB /* Build configuration list for PBXProject "AITableViewDemo" */ = { 463 | isa = XCConfigurationList; 464 | buildConfigurations = ( 465 | DAAC13411B4BC89100F7CFFB /* Debug */, 466 | DAAC13421B4BC89100F7CFFB /* Release */, 467 | ); 468 | defaultConfigurationIsVisible = 0; 469 | defaultConfigurationName = Release; 470 | }; 471 | DAAC13431B4BC89100F7CFFB /* Build configuration list for PBXNativeTarget "AITableViewDemo" */ = { 472 | isa = XCConfigurationList; 473 | buildConfigurations = ( 474 | DAAC13441B4BC89100F7CFFB /* Debug */, 475 | DAAC13451B4BC89100F7CFFB /* Release */, 476 | ); 477 | defaultConfigurationIsVisible = 0; 478 | defaultConfigurationName = Release; 479 | }; 480 | DAAC13461B4BC89100F7CFFB /* Build configuration list for PBXNativeTarget "AITableViewDemoTests" */ = { 481 | isa = XCConfigurationList; 482 | buildConfigurations = ( 483 | DAAC13471B4BC89100F7CFFB /* Debug */, 484 | DAAC13481B4BC89100F7CFFB /* Release */, 485 | ); 486 | defaultConfigurationIsVisible = 0; 487 | defaultConfigurationName = Release; 488 | }; 489 | /* End XCConfigurationList section */ 490 | }; 491 | rootObject = DAAC13181B4BC89100F7CFFB /* Project object */; 492 | } 493 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 15/7/7. 6 | // Copyright (c) 2015年 chentoo. 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 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 15/7/7. 6 | // Copyright (c) 2015年 chentoo. 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 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/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 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/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 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/DemoNameCellModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoNameCellModel.h 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 16/2/3. 6 | // Copyright © 2016年 chentoo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AITableViewProtocal.h" 11 | 12 | @interface DemoNameCellModel : NSObject 13 | 14 | @property (nonatomic, copy) NSString *name; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/DemoNameCellModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoNameCellModel.m 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 16/2/3. 6 | // Copyright © 2016年 chentoo. All rights reserved. 7 | // 8 | 9 | #import "DemoNameCellModel.h" 10 | 11 | @interface DemoNameCellModel () 12 | 13 | @end 14 | 15 | 16 | @implementation DemoNameCellModel 17 | 18 | @synthesize AIDidSelectBlock; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/DemoTableViewFooterView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoTableViewFooterView.h 3 | // AITableViewDemo 4 | // 5 | // Created by chentoo on 15/8/21. 6 | // Copyright (c) 2015年 chentoo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DemoTableViewFooterView : UITableViewHeaderFooterView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/DemoTableViewFooterView.m: -------------------------------------------------------------------------------- 1 | // 2 | // HEHETableViewFooterView.m 3 | // AITableViewDemo 4 | // 5 | // Created by chentoo on 15/8/21. 6 | // Copyright (c) 2015年 chentoo. All rights reserved. 7 | // 8 | 9 | #import "DemoTableViewFooterView.h" 10 | #import "AITableViewProtocal.h" 11 | 12 | @interface DemoTableViewFooterView () 13 | 14 | @property (weak, nonatomic) IBOutlet UILabel *footerLabel; 15 | 16 | @end 17 | 18 | @implementation DemoTableViewFooterView 19 | 20 | - (void)awakeFromNib 21 | { 22 | //do sth. 23 | } 24 | 25 | - (void)layoutSubviews 26 | { 27 | [super layoutSubviews]; 28 | self.footerLabel.frame = self.bounds; 29 | } 30 | 31 | 32 | #pragma mark - AITableViewSectionProtocal 33 | 34 | - (void)AIConfigureWithModel:(id)model 35 | { 36 | self.footerLabel.text = @" footer view!"; 37 | } 38 | 39 | + (CGFloat)AIHeightWithModel:(id)model 40 | { 41 | return 20; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/DemoTableViewFooterView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/DemoTableViewHeaderView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoTableViewHeaderView.h 3 | // AITableViewDemo 4 | // 5 | // Created by chentoo on 15/8/20. 6 | // Copyright (c) 2015年 chentoo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DemoTableViewHeaderView : UITableViewHeaderFooterView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/DemoTableViewHeaderView.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoTableViewHeaderView.m 3 | // AITableViewDemo 4 | // 5 | // Created by chentoo on 15/8/20. 6 | // Copyright (c) 2015年 chentoo. All rights reserved. 7 | // 8 | 9 | #import "DemoTableViewHeaderView.h" 10 | #import "AITableViewProtocal.h" 11 | 12 | @interface DemoTableViewHeaderView () 13 | 14 | @property (strong, nonatomic) UILabel *titleLabel; 15 | 16 | @end 17 | 18 | @implementation DemoTableViewHeaderView 19 | 20 | - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier 21 | { 22 | self = [super initWithReuseIdentifier:reuseIdentifier]; 23 | if (self) { 24 | _titleLabel = [[UILabel alloc] init]; 25 | [self.contentView addSubview:_titleLabel]; 26 | } 27 | return self; 28 | } 29 | 30 | - (void)layoutSubviews 31 | { 32 | [super layoutSubviews]; 33 | self.titleLabel.frame = self.bounds; 34 | } 35 | 36 | 37 | #pragma mark - AITableViewSectionProtocal 38 | 39 | - (void)AIConfigureWithModel:(id)model 40 | { 41 | self.titleLabel.text = @" Head view!"; 42 | } 43 | 44 | + (CGFloat)AIHeightWithModel:(id)model 45 | { 46 | return 50; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/DemoTableViewNameCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoTableViewNameCell.h 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 16/2/3. 6 | // Copyright © 2016年 chentoo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DemoTableViewNameCell : UITableViewCell 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/DemoTableViewNameCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoTableViewNameCell.m 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 16/2/3. 6 | // Copyright © 2016年 chentoo. All rights reserved. 7 | // 8 | 9 | #import "DemoTableViewNameCell.h" 10 | #import "AITableViewProtocal.h" 11 | #import "DemoNameCellModel.h" 12 | 13 | @interface DemoTableViewNameCell () 14 | 15 | @property (nonatomic, strong) UILabel *nameLabel; 16 | 17 | @end 18 | 19 | @implementation DemoTableViewNameCell 20 | 21 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 22 | { 23 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 24 | if (self) { 25 | [self initSubViews]; 26 | } 27 | return self; 28 | } 29 | 30 | - (void)initSubViews 31 | { 32 | _nameLabel = [[UILabel alloc] init]; 33 | [self.contentView addSubview:_nameLabel]; 34 | } 35 | 36 | - (void)layoutSubviews 37 | { 38 | [super layoutSubviews]; 39 | self.nameLabel.frame = self.bounds; 40 | } 41 | 42 | #pragma mark - AITableViewCellProtocal 43 | 44 | - (void)AIConfigureWithModel:(DemoNameCellModel *)model 45 | { 46 | self.nameLabel.text = model.name; 47 | } 48 | 49 | + (CGFloat)AIHeightWithModel:(id)model 50 | { 51 | return 30.0f; 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/DemoTableViewPhoneCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoTableViewPhoneCell.h 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 16/2/3. 6 | // Copyright © 2016年 chentoo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DemoTableViewPhoneCell : UITableViewCell 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/DemoTableViewPhoneCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoTableViewPhoneCell.m 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 16/2/3. 6 | // Copyright © 2016年 chentoo. All rights reserved. 7 | // 8 | 9 | #import "DemoTableViewPhoneCell.h" 10 | #import "AITableViewProtocal.h" 11 | 12 | @interface DemoTableViewPhoneCell () 13 | 14 | @property (nonatomic, copy) UILabel *phoneLabel; 15 | 16 | @end 17 | 18 | @implementation DemoTableViewPhoneCell 19 | 20 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 21 | { 22 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 23 | if (self) { 24 | [self initSubViews]; 25 | } 26 | return self; 27 | } 28 | 29 | - (void)initSubViews 30 | { 31 | _phoneLabel = [[UILabel alloc] init]; 32 | _phoneLabel.font = [UIFont systemFontOfSize:10.0f]; 33 | [self.contentView addSubview:_phoneLabel]; 34 | } 35 | 36 | - (void)layoutSubviews 37 | { 38 | [super layoutSubviews]; 39 | self.phoneLabel.frame = self.bounds; 40 | } 41 | 42 | #pragma mark - AITableViewCellProtocal 43 | 44 | - (void)AIConfigureWithModel:(id)model 45 | { 46 | self.phoneLabel.text = @"1392883322"; 47 | } 48 | 49 | + (CGFloat)AIHeightWithModel:(id)model 50 | { 51 | return 20.0f; 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/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 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.chentoo.$(PRODUCT_NAME:rfc1034identifier) 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 | 40 | 41 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 15/7/7. 6 | // Copyright (c) 2015年 chentoo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 15/7/7. 6 | // Copyright (c) 2015年 chentoo. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "AITableView.h" 11 | #import "DemoTableViewHeaderView.h" 12 | #import "DemoTableViewFooterView.h" 13 | #import "DemoNameCellModel.h" 14 | #import "DemoTableViewNameCell.h" 15 | #import "DemoTableViewPhoneCell.h" 16 | 17 | @interface ViewController () 18 | 19 | @property (strong, nonatomic) AITableView *topTableview; 20 | @property (strong, nonatomic) AITableView *bottomTableview; 21 | 22 | @end 23 | 24 | @implementation ViewController 25 | 26 | - (void)viewDidLoad { 27 | [super viewDidLoad]; 28 | // Do any additional setup after loading the view, typically from a nib. 29 | 30 | // 包含section的 topTableview 31 | [self configureTopTableView]; 32 | // 不含section的简单 bottomTableView 33 | [self configureBottomTableView]; 34 | } 35 | 36 | - (void)configureTopTableView 37 | { 38 | self.topTableview = [AITableView tableViewWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height / 2)]; 39 | [self.view addSubview:self.topTableview]; 40 | 41 | [self.topTableview bindStaticHeaderFooterWithClass:[DemoTableViewHeaderView class]]; 42 | [self.topTableview bindStaticHeaderFooterWithNibClass:[DemoTableViewFooterView class]]; 43 | 44 | [self.topTableview bindCellClass:[DemoTableViewNameCell class] withModelClass:[DemoNameCellModel class]]; 45 | [self.topTableview bindStaticCellWithCellClass:[DemoTableViewPhoneCell class]]; 46 | 47 | DemoNameCellModel *nameCellmodel = [[DemoNameCellModel alloc] init]; 48 | nameCellmodel.name = @"我是名字"; 49 | 50 | AITableViewStaticCellModel *phoneCellModel = [self.topTableview modelWithStaticCellClass:[DemoTableViewPhoneCell class]]; 51 | 52 | AITableViewStaticHeaderFooterModel *headerModel = [self.topTableview modelWithStaticHeaderFooterClass:[DemoTableViewHeaderView class]]; 53 | AITableViewStaticHeaderFooterModel *footerModel = [self.topTableview modelWithStaticHeaderFooterClass:[DemoTableViewFooterView class]]; 54 | AITableViewSection *aiSection = [AITableViewSection sectionWithHeaderModel:headerModel 55 | footerModel:footerModel 56 | cellModels:@[nameCellmodel, phoneCellModel]]; 57 | 58 | // [self.tableview updateTableViewWithModels:@[model, sModel, sModel, model]]; 59 | [self.topTableview setAIDidSelectRowBlock:^(AITableView *tableView, NSIndexPath *indexPath, id cellModel) { 60 | NSLog(@"通过AITableView Block 的方式设置点击事件--%@", indexPath); 61 | }]; 62 | 63 | [self.topTableview updateTableViewWithSections:@[aiSection, aiSection, aiSection]]; 64 | self.topTableview.AIDelegate = self; 65 | } 66 | 67 | - (void)configureBottomTableView 68 | { 69 | self.bottomTableview = [AITableView tableViewWithFrame:CGRectMake(0, self.view.bounds.size.height / 2 + 100, self.view.bounds.size.width, self.view.bounds.size.height / 2)]; 70 | [self.view addSubview:self.bottomTableview]; 71 | 72 | [self.bottomTableview bindCellClass:[DemoTableViewNameCell class] withModelClass:[DemoNameCellModel class]]; 73 | [self.bottomTableview bindStaticCellWithCellClass:[DemoTableViewPhoneCell class]]; 74 | 75 | DemoNameCellModel *nameCellmodel = [[DemoNameCellModel alloc] init]; 76 | nameCellmodel.name = @"我是名字"; 77 | nameCellmodel.AIDidSelectBlock = ^(NSIndexPath *indexPath) { 78 | NSLog(@"通过实现model protocal 的方式设置点击事件--%@", indexPath); 79 | }; 80 | 81 | AITableViewStaticCellModel *phoneCellModel = [self.topTableview modelWithStaticCellClass:[DemoTableViewPhoneCell class]]; 82 | 83 | [self.bottomTableview setAIDidSelectRowBlock:^(AITableView *tableView, NSIndexPath *indexPath, id cellModel) { 84 | NSLog(@"通过AITableView Block 的方式设置点击事件--%@", indexPath); 85 | }]; 86 | 87 | self.bottomTableview.AIDelegate = self; 88 | [self.bottomTableview updateTableViewWithModels:@[nameCellmodel, phoneCellModel]]; 89 | } 90 | 91 | - (void)didReceiveMemoryWarning { 92 | [super didReceiveMemoryWarning]; 93 | // Dispose of any resources that can be recreated. 94 | } 95 | 96 | #pragma mark - AITableViewDelegate 97 | 98 | - (void)tableView:(AITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath withCellModel:(id)cellModel 99 | { 100 | NSLog(@"通过AITableViewDelegate 的方式设置点击事件--%@", indexPath); 101 | } 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // AITableViewDemo 4 | // 5 | // Created by Zhidi Xia on 15/7/7. 6 | // Copyright (c) 2015年 chentoo. 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 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemoTests/AITableViewDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // AITableViewDemoTests.m 3 | // AITableViewDemoTests 4 | // 5 | // Created by Zhidi Xia on 15/7/7. 6 | // Copyright (c) 2015年 chentoo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface AITableViewDemoTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation AITableViewDemoTests 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 | -------------------------------------------------------------------------------- /AITableViewDemo/AITableViewDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.chentoo.$(PRODUCT_NAME:rfc1034identifier) 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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 chentoo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AITableView 2 | 3 | ## 做什么用? 4 | 5 | 这是一个简化UITableView使用方式的一个尝试,不需要再实现UI TableView繁多的delegate和datasource方法,不需要重复实现繁多的cell的if else / switch 逻辑,只需要简单的配置过程,你就可以轻松的驾驭和布局TableView。 6 | 7 | 这是一个基于MVVM思想的尝试,并且最终拼装成为TableView的元素不再是一个个的cell,而是一个个轻量的ViewModel(我们暂且叫他CellModel)。每个CellModel对应值唯一的一种cell,CellModel只拥有属性, 且每一个属性都将直接决定Cell的展示效果。 8 | 9 | 长远来看,你可以轻松的组建一个你自己的CellModel库。在同一个TableView的不同的逻辑情况下,或者不同的TableView中,你可以根据自己的需求选出合适的CellModel,配置属性,拼装组建即可。 10 | 11 | ## 怎么使用? 12 | 13 | 首先使用AITabelView,你不需要更改你原本的Cell的基类和model的基类,只需根据需要实现特定的Protocal即可。 14 | 15 | 1、 你的每个Cell需要实现AITableViewCellProtocal,并实现对应方法。你应该把你所有的Cell UI元素的配置放在 16 | 17 | ```objective-c 18 | - (void)AIConfigureWithModel:(DemoNameCellModel *)model 19 | ``` 20 | 并在类方法 21 | 22 | ```objective-c 23 | + (CGFloat)AIHeightWithModel:(id)model 24 | ``` 25 | 返回你的cell的高度。 26 | 27 | 比如: 28 | 29 | ```objective-c 30 | #import "DemoTableViewNameCell.h" 31 | #import "AITableViewProtocal.h" 32 | #import "DemoNameCellModel.h" 33 | 34 | @interface DemoTableViewNameCell () 35 | 36 | @property (nonatomic, strong) UILabel *nameLabel; 37 | 38 | @end 39 | 40 | @implementation DemoTableViewNameCell 41 | 42 | #pragma mark - AITableViewCellProtocal 43 | 44 | - (void)AIConfigureWithModel:(DemoNameCellModel *)model 45 | { 46 | self.nameLabel.text = model.name; 47 | } 48 | 49 | + (CGFloat)AIHeightWithModel:(id)model 50 | { 51 | return 30.0f; 52 | } 53 | 54 | @end 55 | 56 | ``` 57 | 58 | 2、接下来去写一个能够唯一对应这个cell的cellModel,它可以继承自任何基类,也不需实现任何Protocal。但是需要保证的是,cell可以根据它所唯一对应的cellModel完成所有配置。 59 | 60 | 需要特别注意的是,每个CellModel类,对应且唯一对应一个Cell类,也即不同的Cell Class 不能对应同一个CellModel类。 61 | 62 | 完成cell对应的cellModel后,使用下面的方法,去绑定他们。 63 | 64 | ```objective-c 65 | //AITableView.h 66 | 67 | - (void)bindModelClass:(Class)modelClass withCellClass:(Class)cellClass; 68 | - (void)bindModelClass:(Class)modelClass withCellNibClass:(Class)cellNibClass; 69 | ``` 70 | 特别的,如果一个cell的逻辑不依赖外部的变化而变化,那么他可能不需要一个cellModel去控制。那么有下面的特别方法去绑定它们。 71 | 72 | 当然其实我并不建议这么做,因为从长远组建CellModel库的角度来讲,拥有一个唯一的cellModel可能更容易管理和使用。 73 | 74 | ```objective-c 75 | //AITableView.h 76 | 77 | - (void)bindStaticCellWithCellClass:(Class)cellClass; 78 | - (void)bindStaticCellWithCellNibClass:(Class)cellNibClass; 79 | ``` 80 | 81 | 3、最后使用下面的方法就可以更新你的TableView了。 82 | 83 | ```objective-c 84 | [self.tableview updateTabelViewWithModels:@[model, sModel, sModel, model]]; 85 | ``` 86 | 87 | 88 | 4、如果你需要包含不同的section,或者需要headview footerview,那么你可以使用: 89 | AITableViewSection 去构建。 90 | 91 | ```objective-c 92 | @interface AITableViewSection : NSObject 93 | 94 | @property (strong, nonatomic) id headerModel; 95 | @property (strong, nonatomic) id footerModel; 96 | @property (strong, nonatomic) NSArray *cellModels; 97 | 98 | + (instancetype)sectionWithHeaderModel:(id)sectionHeaderModel 99 | footerModel:(id)sectionFooterModel 100 | cellModels:(NSArray *)cellModels; 101 | 102 | @end 103 | ``` 104 | 并且使用下面的方法去更新TableView 105 | 106 | ```objective-c 107 | [self.tableview updateTableViewWithSections:@[aiSection, aiSection, aiSection]]; 108 | ``` 109 | 110 | 5、更多的请参看完整示例代码。 111 | 112 | ## 如何接收cell 点击事件? 113 | 114 | 提供了三种方式: 115 | 116 | 1. AITableView的 delegate 117 | 2. AITableView的 Block 118 | 3. model 的 protocal block(可以方便的配置在model身上) 119 | 120 | 具体请看示例代码。 121 | 122 | ## Easy To Get Started 123 | 124 | #### 1、Your Cell have to implement AITableViewCellProtocal 125 | 126 | ```objective-c 127 | //HEHETableViewCell.h 128 | #import 129 | #import "AITableViewCellProtocal.h" 130 | 131 | @interface HEHETableViewCell : UITableViewCell 132 | 133 | @end 134 | 135 | //HEHETableViewCell.m 136 | #import "HEHETableViewCell.h" 137 | 138 | @implementation HEHETableViewCell 139 | 140 | + (NSString *)AIReuseIdentifier 141 | { 142 | return @"HEHETableViewCellReuseIdentifier"; 143 | } 144 | 145 | - (void)AIConfigureWithModel:(id)model 146 | { 147 | self.textLabel.text = @"Hey, girl~"; 148 | } 149 | 150 | + (CGFloat)AIHeightWithModel:(id)model 151 | { 152 | return 40.0f; 153 | } 154 | 155 | @end 156 | ``` 157 | You have to put cell configure code in this methed: 158 | 159 | ```objective-c 160 | - (void)AIConfigureWithModel:(id)model 161 | ``` 162 | 163 | Return your cell 's height in this class methed: 164 | 165 | ```objective-c 166 | + (CGFloat)AIHeightWithModel:(id)model 167 | ``` 168 | 169 | #### 2、Then ,each cell corresponds to a unique model, or the cell does not need a model(a static cell). 170 | You have to bind model and cell ,or bind static cell: 171 | 172 | ```objective-c 173 | //AITableView.h 174 | 175 | - (void)bindModelClass:(Class)modelClass withCellClass:(Class)cellClass; 176 | - (void)bindModelClass:(Class)modelClass withCellNibClass:(Class)cellNibClass; 177 | 178 | - (void)bindStaticCellWithCellClass:(Class)cellClass; 179 | - (void)bindStaticCellWithCellNibClass:(Class)cellNibClass; 180 | ``` 181 | 182 | #### 3、Enjoy your AITableView... 183 | ```objective-c 184 | self.tableview = [AITableView tableViewWithFrame:self.view.bounds]; 185 | [self.view addSubview:self.tableview]; 186 | 187 | [self.tableview bindModelClass:[HEHECellModel class] withCellClass:[HEHETableViewCell class]]; 188 | [self.tableview bindStaticCellWithCellNibClass:[HAHATableViewCell class]]; 189 | 190 | HEHECellModel *model = [[HEHECellModel alloc] init]; 191 | AITableViewStaticCellModel *sModel = [self.tableview modelWithStaticCellClass:[HAHATableViewCell class]]; 192 | 193 | [self.tableview updateTabelViewWithModels:@[model, sModel, sModel, model]]; 194 | ``` 195 | 196 | #### May be your need to see Demo. 197 | 198 | 199 | #License 200 | MIT 201 | --------------------------------------------------------------------------------