├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Example ├── HoloTableView.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── HoloTableView-Example.xcscheme ├── HoloTableView.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── HoloTableView │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── HoloAppDelegate.h │ ├── HoloAppDelegate.m │ ├── HoloExampleFooterView.h │ ├── HoloExampleFooterView.m │ ├── HoloExampleHeaderView.h │ ├── HoloExampleHeaderView.m │ ├── HoloExampleTableViewCell.h │ ├── HoloExampleTableViewCell.m │ ├── HoloTableView-Info.plist │ ├── HoloTableView-Prefix.pch │ ├── HoloViewController.h │ ├── HoloViewController.m │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── en.lproj │ │ └── InfoPlist.strings │ └── main.m ├── Podfile ├── Podfile.lock └── Tests │ ├── HoloTableRowInsterTest.m │ ├── HoloTableRowMakerTest.m │ ├── HoloTableRowRemakerTest.m │ ├── HoloTableRowRemoverTest.m │ ├── HoloTableRowUpdaterTest.m │ ├── HoloTableSectionInsterTest.m │ ├── HoloTableSectionMakerTest.m │ ├── HoloTableSectionRemakerTest.m │ ├── HoloTableSectionRemoverTest.m │ ├── HoloTableSectionUpdaterTest.m │ ├── Tests-Info.plist │ ├── Tests-Prefix.pch │ ├── Tests.m │ └── en.lproj │ └── InfoPlist.strings ├── HoloTableView.podspec ├── HoloTableView ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── Core │ ├── HoloTableViewProxy.h │ ├── HoloTableViewProxy.m │ ├── HoloTableViewProxyData.h │ ├── HoloTableViewProxyData.m │ ├── Protocol │ │ ├── HoloTableViewCellProtocol.h │ │ ├── HoloTableViewFooterProtocol.h │ │ ├── HoloTableViewHeaderProtocol.h │ │ └── HoloTableViewProtocol.h │ ├── Row │ │ ├── HoloTableRow.h │ │ └── HoloTableRow.m │ ├── Section │ │ ├── HoloTableSection.h │ │ └── HoloTableSection.m │ ├── SwipeAction │ │ ├── HoloTableViewRowSwipeAction.h │ │ └── HoloTableViewRowSwipeAction.m │ ├── UITableView+HoloTableViewProxy.h │ └── UITableView+HoloTableViewProxy.m │ ├── HoloTableView.h │ ├── Macro │ └── HoloTableViewMacro.h │ ├── Maker │ ├── Deprecated │ │ ├── UITableView+HoloDeprecated.h │ │ └── UITableView+HoloDeprecated.m │ ├── Row │ │ ├── HoloTableRowMaker.h │ │ ├── HoloTableRowMaker.m │ │ ├── HoloTableViewRowMaker.h │ │ └── HoloTableViewRowMaker.m │ ├── Section │ │ ├── HoloTableSectionMaker.h │ │ ├── HoloTableSectionMaker.m │ │ ├── HoloTableViewSectionMaker.h │ │ └── HoloTableViewSectionMaker.m │ ├── TableView │ │ ├── HoloTableViewMaker.h │ │ └── HoloTableViewMaker.m │ ├── UITableView+HoloTableView.h │ ├── UITableView+HoloTableView.m │ └── Update │ │ ├── HoloTableViewUpdateRowMaker.h │ │ └── HoloTableViewUpdateRowMaker.m │ └── Responder Event │ ├── UIResponder+HoloEvent.h │ └── UIResponder+HoloEvent.m ├── LICENSE ├── README.md └── README_CN.md /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 26 | # Carthage/Checkouts 27 | 28 | Carthage/Build 29 | 30 | # We recommend against adding the Pods directory to your .gitignore. However 31 | # you should judge for yourself, the pros and cons are mentioned at: 32 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 33 | # 34 | # Note: if you ignore the Pods directory, make sure to uncomment 35 | # `pod install` in .travis.yml 36 | # 37 | Pods/ 38 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * https://www.objc.io/issues/6-build-tools/travis-ci/ 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode12 6 | language: objective-c 7 | # cache: cocoapods 8 | # podfile: Example/Podfile 9 | # before_install: 10 | # - gem install cocoapods # Since Travis is not always on latest version 11 | # - pod install --project-directory=Example 12 | script: 13 | # - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/HoloTableView.xcworkspace -scheme HoloTableView-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty 14 | - pod lib lint --verbose 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | 6 | ## 3.1.2 (06/03/2021) 7 | 8 | ### Updated 9 | 10 | - Check the cell class type and so on after the list appears. 11 | - Provide default cell class for row and default header and footer class for section. 12 | - Change `holo_proxy` of `UITableView+HoloTableViewProxy.h` to readonly. 13 | 14 | 15 | ## 3.1.1 (05/23/2021) 16 | 17 | ### Updated 18 | 19 | - Change api: 1, replace `holo_updateRows:inSection:` with `holo_updateRowsInSection:block:`; 2, replace `holo_remakeRows:inSection:` with `holo_remakeRowsInSection:block:`. 20 | 21 | 22 | ## 3.1.0 (05/20/2021) 23 | 24 | ### Added 25 | 26 | - Support for updating and remaking rows for a target section with a tag. 27 | - Support the `updateRows` and `remakeRows` methods for `sectionMaker`. 28 | 29 | ### Fixed 30 | 31 | - Update sections by `holo_updateSections:` method. 32 | 33 | 34 | ## 3.0.0 (05/04/2021) 35 | 36 | ### Added 37 | 38 | - Support to reload a table view by setting datasource with `HoloTableSection` and `HoloTableRow`. Add `holo_sections` for `UITableView`. 39 | - Add `holo_sectionIndexTitles` for `UITableView`. 40 | - Add `holo_sectionForSectionIndexTitleHandler` for `UITableView`. 41 | - Add `holo_scrollDelegate` for `UITableView`. 42 | 43 | ### Updated 44 | 45 | - Reuse header and footer. And if has no header and header title, return nil for header, if has no footer and footer title, return nil for footer. 46 | 47 | ### Removed 48 | 49 | - No longer support `headerFooterConfigSEL`, `headerFooterHeightSEL` and `headerFooterEstimatedHeightSEL` properties. 50 | - No longer support `rowS`, `headerS` and `footerS` properties. And no longer support to regist key-Class map (`rowsMap`, `headersMap` and `footersMap`). 51 | 52 | 53 | ## 2.4.0 (16/02/2021) 54 | 55 | - Update `HoloTableView.h`, use angle-bracketed instead of double-quoted. 56 | - Update `HoloTableViewMacro`, add `#if !defined()`. 57 | - Update `leadingSwipeActions` and `trailingSwipeActions`, only accept `HoloTableViewRowSwipeAction` type. 58 | 59 | ## 2.3.0 (09/12/2020) 60 | 61 | - Add `nullable` to property. 62 | - Delete the judgment that rows of section are greater than 0, in order to get the right section data. 63 | 64 | ## 2.2.0 (12/11/2020) 65 | 66 | - Add `beforeConfigureHandler` and `afterConfigureHandler`, performed before and after `configSEL`. 67 | 68 | 69 | ## 2.1.0 (13/08/2020) 70 | 71 | - Add `_Nullable` to method parameters in cell protocol, header protocol and footer protocol. 72 | 73 | 74 | ## 2.0.0 (23/07/2020) 75 | 76 | - Refactor the update, remake and insert methods for `UITableView` and optimize the code logic. 77 | - Provide more properties of section and row maker to handle proxy events of `UITableVIew`. 78 | - Provide more protocols, implemented in cells, headers and footers to handle proxy events of `UITableVIew`. 79 | - Support to regist maps (key-Class) for row, header and footer. 80 | - Check the index in `HoloTableViewProxy` for safety. 81 | 82 | 83 | ## 1.x (2019 ~ 2020) 84 | 85 | `HoloTableView` provides chained syntax calls that encapsulate delegate methods for `UITableView`. The delegate methods for `UITableView` is distributed to each `cell`, each `cell` having its own method for setting Class, model, height, and click event, etc. 86 | 87 | 88 | -------------------------------------------------------------------------------- /Example/HoloTableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/HoloTableView.xcodeproj/xcshareddata/xcschemes/HoloTableView-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 42 | 48 | 49 | 50 | 51 | 52 | 62 | 64 | 70 | 71 | 72 | 73 | 79 | 81 | 87 | 88 | 89 | 90 | 92 | 93 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /Example/HoloTableView.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/HoloTableView.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/HoloTableView/Base.lproj/LaunchScreen.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 | -------------------------------------------------------------------------------- /Example/HoloTableView/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 | -------------------------------------------------------------------------------- /Example/HoloTableView/HoloAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloAppDelegate.h 3 | // HoloTableView 4 | // 5 | // Created by gonghonglou on 07/28/2019. 6 | // Copyright (c) 2019 gonghonglou. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface HoloAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Example/HoloTableView/HoloAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloAppDelegate.m 3 | // HoloTableView 4 | // 5 | // Created by gonghonglou on 07/28/2019. 6 | // Copyright (c) 2019 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import "HoloAppDelegate.h" 10 | 11 | @implementation HoloAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // 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. 22 | // 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. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // 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. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // 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. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 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 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Example/HoloTableView/HoloExampleFooterView.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloExampleFooterView.h 3 | // HoloTableView_Example 4 | // 5 | // Created by 与佳期 on 2019/8/3. 6 | // Copyright © 2019 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface HoloExampleFooterView : UITableViewHeaderFooterView 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/HoloTableView/HoloExampleFooterView.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloExampleFooterView.m 3 | // HoloTableView_Example 4 | // 5 | // Created by 与佳期 on 2019/8/3. 6 | // Copyright © 2019 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import "HoloExampleFooterView.h" 10 | 11 | @implementation HoloExampleFooterView 12 | 13 | - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier { 14 | self = [super initWithReuseIdentifier:reuseIdentifier]; 15 | if (self) { 16 | self.contentView.backgroundColor = [UIColor lightGrayColor]; 17 | // self.textLabel.text will became nil when the footer is reused 18 | // self.textLabel.text = @"footer"; 19 | } 20 | return self; 21 | } 22 | 23 | - (void)holo_configureFooterWithModel:(NSDictionary *)model { 24 | self.textLabel.text = model[@"title"]; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Example/HoloTableView/HoloExampleHeaderView.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloExampleHeaderView.h 3 | // HoloTableView_Example 4 | // 5 | // Created by 与佳期 on 2019/8/3. 6 | // Copyright © 2019 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface HoloExampleHeaderView : UITableViewHeaderFooterView 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Example/HoloTableView/HoloExampleHeaderView.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloExampleHeaderView.m 3 | // HoloTableView_Example 4 | // 5 | // Created by 与佳期 on 2019/8/3. 6 | // Copyright © 2019 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import "HoloExampleHeaderView.h" 10 | 11 | @implementation HoloExampleHeaderView 12 | 13 | - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier { 14 | self = [super initWithReuseIdentifier:reuseIdentifier]; 15 | if (self) { 16 | self.contentView.backgroundColor = [UIColor lightGrayColor]; 17 | self.textLabel.text = @"header"; 18 | } 19 | return self; 20 | } 21 | 22 | - (void)holo_configureHeaderWithModel:(NSDictionary *)model { 23 | self.textLabel.text = model[@"title"]; 24 | } 25 | 26 | + (CGFloat)holo_heightForHeaderWithModel:(id)model { 27 | return 100; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Example/HoloTableView/HoloExampleTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloExampleTableViewCell.h 3 | // HoloTableView_Example 4 | // 5 | // Created by 与佳期 on 2019/7/28. 6 | // Copyright © 2019 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface HoloExampleTableViewCell : UITableViewCell 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Example/HoloTableView/HoloExampleTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloExampleTableViewCell.m 3 | // HoloTableView_Example 4 | // 5 | // Created by 与佳期 on 2019/7/28. 6 | // Copyright © 2019 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import "HoloExampleTableViewCell.h" 10 | 11 | @implementation HoloExampleTableViewCell 12 | 13 | - (void)holo_configureCellWithModel:(NSDictionary *)model { 14 | self.backgroundColor = model[@"bgColor"]; 15 | self.textLabel.text = model[@"text"]; 16 | } 17 | 18 | + (CGFloat)holo_heightForCellWithModel:(NSDictionary *)model { 19 | return [model[@"height"] floatValue]; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Example/HoloTableView/HoloTableView-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Example/HoloTableView/HoloTableView-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | #endif 17 | -------------------------------------------------------------------------------- /Example/HoloTableView/HoloViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloViewController.h 3 | // HoloTableView 4 | // 5 | // Created by gonghonglou on 07/28/2019. 6 | // Copyright (c) 2019 gonghonglou. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface HoloViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/HoloTableView/HoloViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloViewController.m 3 | // HoloTableView 4 | // 5 | // Created by gonghonglou on 07/28/2019. 6 | // Copyright (c) 2019 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import "HoloViewController.h" 10 | #import 11 | #import "HoloExampleHeaderView.h" 12 | #import "HoloExampleFooterView.h" 13 | #import "HoloExampleTableViewCell.h" 14 | 15 | #define HOLO_SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.width 16 | #define HOLO_SCREEN_HEIGHT [[UIScreen mainScreen] bounds].size.height 17 | 18 | @interface HoloViewController () 19 | 20 | @property (nonatomic, strong) UIButton *addButton; 21 | 22 | @property (nonatomic, strong) UITableView *tableView; 23 | 24 | @property (nonatomic, copy) NSArray *modelArray; 25 | 26 | @end 27 | 28 | @implementation HoloViewController 29 | 30 | - (void)dealloc { 31 | NSLog(@"HoloExampleOneViewController dealloc"); 32 | } 33 | 34 | - (void)viewDidLoad { 35 | [super viewDidLoad]; 36 | // Do any additional setup after loading the view. 37 | [self.view addSubview:self.addButton]; 38 | [self.view addSubview:self.tableView]; 39 | 40 | 41 | [self makeSectionByMaker]; 42 | 43 | // [self makeRowListWithDefaultSection]; 44 | 45 | // [self makeSectionListByObject]; 46 | } 47 | 48 | 49 | #pragma mark - Maker 50 | 51 | - (void)makeSectionByMaker { 52 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 53 | make.section(TAG) 54 | .header(HoloExampleHeaderView.class).headerModel(@{@"title":@"header"}) 55 | .footer(HoloExampleFooterView.class).footerModel(@{@"title":@"footer"}).footerHeight(100) 56 | .makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 57 | for (NSDictionary *dict in self.modelArray) { 58 | make.row(HoloExampleTableViewCell.class).model(dict).didSelectHandler(^(id _Nullable model) { 59 | NSLog(@"did select row : %@", model); 60 | }); 61 | } 62 | }); 63 | 64 | // make.section(@"1") 65 | // make.section(@"2") 66 | // ... 67 | }]; 68 | [self.tableView reloadData]; 69 | } 70 | 71 | - (void)insertRowToSectionWithReloadAnimation { 72 | [self.tableView holo_insertRowsAtIndex:0 inSection:TAG block:^(HoloTableViewRowMaker * _Nonnull make) { 73 | make.row(HoloExampleTableViewCell.class).model(@{@"bgColor": [UIColor redColor], @"text": @"cell", @"height": @44}); 74 | } withReloadAnimation:UITableViewRowAnimationNone]; 75 | } 76 | 77 | - (void)makeRowListWithDefaultSection { 78 | [self.tableView holo_makeRows:^(HoloTableViewRowMaker * _Nonnull make) { 79 | for (NSDictionary *dict in self.modelArray) { 80 | make.row(HoloExampleTableViewCell.class).model(dict).didSelectHandler(^(id _Nullable model) { 81 | NSLog(@"did select row : %@", model); 82 | }); 83 | } 84 | }]; 85 | [self.tableView reloadData]; 86 | } 87 | 88 | 89 | #pragma mark - Object 90 | 91 | - (void)makeSectionListByObject { 92 | HoloTableSection *section = [HoloTableSection new]; 93 | section.tag = TAG; 94 | 95 | section.header = HoloExampleHeaderView.class; 96 | section.headerModel = @{@"title":@"header"}; 97 | 98 | section.footer = HoloExampleFooterView.class; 99 | section.footerModel = @{@"title":@"footer"}; 100 | section.footerHeight = 100; 101 | 102 | NSMutableArray *rows = [NSMutableArray new]; 103 | for (NSDictionary *dict in self.modelArray) { 104 | HoloTableRow *row = [HoloTableRow new]; 105 | row.cell = HoloExampleTableViewCell.class; 106 | row.model = dict; 107 | [rows addObject:row]; 108 | } 109 | section.rows = rows; 110 | 111 | self.tableView.holo_sections = @[section]; 112 | [self.tableView reloadData]; 113 | } 114 | 115 | 116 | #pragma mark - buttonAction 117 | 118 | - (void)_addButtonAction:(UIButton *)sender { 119 | [self insertRowToSectionWithReloadAnimation]; 120 | } 121 | 122 | 123 | #pragma mark - getter 124 | 125 | - (UIButton *)addButton { 126 | if (!_addButton) { 127 | _addButton = [UIButton buttonWithType:UIButtonTypeSystem]; 128 | _addButton.frame = CGRectMake(50, 44, HOLO_SCREEN_WIDTH - 100, 44); 129 | [_addButton setTitle:@"add a cell" forState:UIControlStateNormal]; 130 | [_addButton addTarget:self action:@selector(_addButtonAction:) forControlEvents:UIControlEventTouchUpInside]; 131 | } 132 | return _addButton; 133 | } 134 | 135 | - (UITableView *)tableView { 136 | if (!_tableView) { 137 | CGRect frame = CGRectMake(0, 100, HOLO_SCREEN_WIDTH, HOLO_SCREEN_HEIGHT - 100); 138 | _tableView = [[UITableView alloc] initWithFrame:frame style:UITableViewStylePlain]; 139 | _tableView.tableFooterView = [UIView new]; 140 | _tableView.estimatedRowHeight = 0; 141 | _tableView.estimatedSectionHeaderHeight = 0; 142 | _tableView.estimatedSectionFooterHeight = 0; 143 | } 144 | return _tableView; 145 | } 146 | 147 | - (NSArray *)modelArray { 148 | if (!_modelArray) { 149 | _modelArray = @[ 150 | @{@"bgColor": [UIColor yellowColor], @"text": @"cell-1", @"height": @66}, 151 | @{@"bgColor": [UIColor cyanColor], @"text": @"cell-2", @"height": @66}, 152 | @{@"bgColor": [UIColor orangeColor], @"text": @"cell-3", @"height": @66}, 153 | ]; 154 | } 155 | return _modelArray; 156 | } 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /Example/HoloTableView/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Example/HoloTableView/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/HoloTableView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // HoloTableView 4 | // 5 | // Created by gonghonglou on 07/28/2019. 6 | // Copyright (c) 2019 gonghonglou. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import "HoloAppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) 13 | { 14 | @autoreleasepool { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([HoloAppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | #use_frameworks! 2 | 3 | platform :ios, '8.0' 4 | 5 | target 'HoloTableView_Example' do 6 | pod 'HoloTableView', :path => '../' 7 | 8 | target 'HoloTableView_Tests' do 9 | inherit! :search_paths 10 | 11 | 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - HoloTableView (3.1.2) 3 | 4 | DEPENDENCIES: 5 | - HoloTableView (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | HoloTableView: 9 | :path: "../" 10 | 11 | SPEC CHECKSUMS: 12 | HoloTableView: 0bb60eaded87d266df87e48aa7a1e58055ed29d2 13 | 14 | PODFILE CHECKSUM: 4a04413c8d8cb6d0e0045bb58a41b9b63e9ba415 15 | 16 | COCOAPODS: 1.10.1 17 | -------------------------------------------------------------------------------- /Example/Tests/HoloTableRowInsterTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableRowInsterTest.m 3 | // HoloTableView_Tests 4 | // 5 | // Created by 与佳期 on 2021/5/22. 6 | // Copyright © 2021 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface HoloTableRowInsterTest : XCTestCase 13 | 14 | @property (nonatomic, strong) UITableView *tableView; 15 | 16 | @end 17 | 18 | @implementation HoloTableRowInsterTest 19 | 20 | - (void)setUp { 21 | // Put setup code here. This method is called before the invocation of each test method in the class. 22 | 23 | self.tableView = [UITableView new]; 24 | 25 | [self.tableView holo_makeRows:^(HoloTableViewRowMaker * _Nonnull make) { 26 | make.row(UITableViewCell.class).tag(TAG); 27 | }]; 28 | 29 | 30 | // insert rows in section 31 | 32 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 33 | make.section(@"section-1").headerHeight(100).makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 34 | make.row(UITableViewCell.class).tag(@"0").model(@"0").height(0); 35 | make.row(UITableViewCell.class).tag(@"1").model(@"1").height(1); 36 | }); 37 | 38 | make.section(@"section-1").headerHeight(100).makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 39 | make.row(UITableViewCell.class).tag(@"0").model(@"0").height(0); 40 | make.row(UITableViewCell.class).tag(@"1").model(@"1").height(1); 41 | }); 42 | }]; 43 | } 44 | 45 | - (void)tearDown { 46 | // Put teardown code here. This method is called after the invocation of each test method in the class. 47 | } 48 | 49 | 50 | #pragma mark - insert rows 51 | 52 | - (void)testInsertRows { 53 | [self.tableView holo_insertRowsAtIndex:0 block:^(HoloTableViewRowMaker * _Nonnull make) { 54 | make.row(UITableViewCell.class).tag(@"0").height(0); 55 | make.row(UITableViewCell.class).tag(@"1").height(1); 56 | }]; 57 | 58 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 59 | 60 | HoloTableSection *section = self.tableView.holo_sections[0]; 61 | 62 | XCTAssertEqual(section.rows.count, 3); 63 | 64 | 65 | HoloTableRow *row0 = section.rows[0]; 66 | HoloTableRow *row1 = section.rows[1]; 67 | HoloTableRow *row2 = section.rows[2]; 68 | 69 | XCTAssertEqual(row0.tag, @"0"); 70 | XCTAssertEqual(row1.tag, @"1"); 71 | XCTAssertEqual(row2.tag, TAG); 72 | 73 | XCTAssertEqual(row0.height, 0); 74 | XCTAssertEqual(row1.height, 1); 75 | XCTAssertEqual(row2.height, CGFLOAT_MIN); 76 | 77 | [self.tableView holo_insertRowsAtIndex:3 block:^(HoloTableViewRowMaker * _Nonnull make) { 78 | make.row(UITableViewCell.class).tag(@"3").height(3); 79 | make.row(UITableViewCell.class).tag(@"4").height(4); 80 | }]; 81 | 82 | XCTAssertEqual(section.rows.count, 5); 83 | 84 | HoloTableRow *row3 = section.rows[3]; 85 | HoloTableRow *row4 = section.rows[4]; 86 | 87 | XCTAssertEqual(row3.tag, @"3"); 88 | XCTAssertEqual(row3.height, 3); 89 | 90 | XCTAssertEqual(row4.tag, @"4"); 91 | XCTAssertEqual(row4.height, 4); 92 | } 93 | 94 | 95 | #pragma mark - insert rows in section 96 | 97 | - (void)testInsertRowsInSection { 98 | [self.tableView holo_insertRowsAtIndex:2 inSection:@"section-1" block:^(HoloTableViewRowMaker * _Nonnull make) { 99 | make.row(UITableViewCell.class).tag(@"2").model(@"2").height(2); 100 | }]; 101 | 102 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 103 | 104 | HoloTableSection *section0 = self.tableView.holo_sections[0]; 105 | HoloTableSection *section1 = self.tableView.holo_sections[1]; 106 | HoloTableSection *section2 = self.tableView.holo_sections[2]; 107 | 108 | XCTAssertEqual(section0.rows.count, 1); 109 | XCTAssertEqual(section1.rows.count, 3); // changed 110 | XCTAssertEqual(section2.rows.count, 2); 111 | 112 | 113 | // when you insert some rows to a section that doesn't already exist, will automatically create a new section. 114 | 115 | [self.tableView holo_insertRowsAtIndex:2 inSection:@"section-1000" block:^(HoloTableViewRowMaker * _Nonnull make) { 116 | make.row(UITableViewCell.class).tag(@"2").model(@"2").height(2); 117 | }]; 118 | 119 | XCTAssertEqual(self.tableView.holo_sections.count, 4); 120 | 121 | HoloTableSection *section3 = self.tableView.holo_sections[3]; 122 | XCTAssertEqual(section3.rows.count, 1); 123 | } 124 | 125 | - (void)testPerformanceExample { 126 | // This is an example of a performance test case. 127 | [self measureBlock:^{ 128 | // Put the code you want to measure the time of here. 129 | }]; 130 | } 131 | 132 | @end 133 | -------------------------------------------------------------------------------- /Example/Tests/HoloTableRowMakerTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableRowMakerTest.m 3 | // HoloTableView_Tests 4 | // 5 | // Created by 与佳期 on 2021/5/20. 6 | // Copyright © 2021 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface HoloTableRowMakerTest : XCTestCase 13 | 14 | @property (nonatomic, strong) UITableView *tableView; 15 | 16 | @end 17 | 18 | @implementation HoloTableRowMakerTest 19 | 20 | - (void)setUp { 21 | // Put setup code here. This method is called before the invocation of each test method in the class. 22 | 23 | self.tableView = [UITableView new]; 24 | 25 | [self.tableView holo_makeRows:^(HoloTableViewRowMaker * _Nonnull make) { 26 | make.row(UITableViewCell.class) 27 | .model(@"model") 28 | .modelHandler(^id _Nonnull{ 29 | return @"modelHandler"; 30 | }) 31 | 32 | .style(UITableViewCellStyleValue1) 33 | .styleHandler(^UITableViewCellStyle(id _Nullable model) { 34 | return UITableViewCellStyleValue2; 35 | }) 36 | 37 | .reuseId(@"reuseId") 38 | .reuseIdHandler(^NSString * _Nonnull(id _Nullable model) { 39 | return @"reuseIdHandler"; 40 | }) 41 | 42 | .tag(TAG) 43 | 44 | .height(10) 45 | .heightHandler(^CGFloat(id _Nullable model) { 46 | return 11; 47 | }) 48 | 49 | .estimatedHeight(100) 50 | .estimatedHeightHandler(^CGFloat(id _Nullable model) { 51 | return 101; 52 | }) 53 | 54 | .shouldHighlight(NO) 55 | .shouldHighlightHandler(^BOOL(id _Nullable model) { 56 | return NO; 57 | }) 58 | 59 | .canEdit(YES) 60 | .canEditHandler(^BOOL(id _Nullable model) { 61 | return YES; 62 | }) 63 | 64 | .canMove(YES) 65 | .canMoveHandler(^BOOL(id _Nullable model) { 66 | return YES; 67 | }) 68 | 69 | .leadingSwipeActions(@[[HoloTableViewRowSwipeAction new]]) 70 | .trailingSwipeActions(@[[HoloTableViewRowSwipeAction new]]) 71 | 72 | .editingDeleteTitle(@"editingDeleteTitle") 73 | .editingDeleteTitleHandler(^NSString * _Nonnull(id _Nullable model) { 74 | return @"editingDeleteTitleHandler"; 75 | }) 76 | 77 | .editingStyle(UITableViewCellEditingStyleDelete) 78 | .editingStyleHandler(^UITableViewCellEditingStyle(id _Nullable model) { 79 | return UITableViewCellEditingStyleInsert; 80 | }); 81 | }]; 82 | 83 | 84 | // make rows in section 85 | 86 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 87 | make.section(@"section-1").headerHeight(100).makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 88 | make.row(UITableViewCell.class).tag(@"0").model(@"0").height(0); 89 | make.row(UITableViewCell.class).tag(@"1").model(@"1").height(1); 90 | }); 91 | 92 | make.section(@"section-1").headerHeight(100).makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 93 | make.row(UITableViewCell.class).tag(@"0").model(@"0").height(0); 94 | make.row(UITableViewCell.class).tag(@"1").model(@"1").height(1); 95 | }); 96 | }]; 97 | } 98 | 99 | - (void)tearDown { 100 | // Put teardown code here. This method is called after the invocation of each test method in the class. 101 | } 102 | 103 | #pragma mark - make rows 104 | 105 | - (void)testMakeRows { 106 | // This is an example of a functional test case. 107 | // Use XCTAssert and related functions to verify your tests produce the correct results. 108 | 109 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 110 | 111 | HoloTableSection *section = self.tableView.holo_sections[0]; 112 | 113 | XCTAssertEqual(section.rows.count, 1); 114 | 115 | HoloTableRow *row = section.rows[0]; 116 | 117 | XCTAssertEqual(row.cell, UITableViewCell.class); 118 | XCTAssertEqual(row.model, @"model"); 119 | XCTAssertEqual(row.style, UITableViewCellStyleValue1); 120 | XCTAssertEqual(row.reuseId, @"reuseId"); 121 | XCTAssertEqual(row.tag, TAG); 122 | XCTAssertEqual(row.height, 10); 123 | XCTAssertEqual(row.estimatedHeight, 100); 124 | XCTAssertEqual(row.shouldHighlight, NO); 125 | XCTAssertEqual(row.canEdit, YES); 126 | XCTAssertEqual(row.canMove, YES); 127 | XCTAssertEqual(row.leadingSwipeActions.count, 1); 128 | XCTAssertEqual(row.trailingSwipeActions.count, 1); 129 | XCTAssertEqual(row.editingDeleteTitle, @"editingDeleteTitle"); 130 | XCTAssertEqual(row.editingStyle, UITableViewCellEditingStyleDelete); 131 | } 132 | 133 | 134 | #pragma mark - make rows in section 135 | 136 | - (void)testMakeRowsInSection { 137 | // This is an example of a functional test case. 138 | // Use XCTAssert and related functions to verify your tests produce the correct results. 139 | 140 | [self.tableView holo_makeRowsInSection:@"section-1" block:^(HoloTableViewRowMaker * _Nonnull make) { 141 | make.row(UITableViewCell.class).tag(@"2").model(@"2").height(2); 142 | }]; 143 | 144 | // section(TAG) 145 | // section(@"section-1") 146 | // section(@"section-1") 147 | 148 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 149 | 150 | HoloTableSection *section0 = self.tableView.holo_sections[0]; 151 | HoloTableSection *section1 = self.tableView.holo_sections[1]; 152 | HoloTableSection *section2 = self.tableView.holo_sections[2]; 153 | 154 | XCTAssertEqual(section0.rows.count, 1); 155 | XCTAssertEqual(section1.rows.count, 3); // changed 156 | XCTAssertEqual(section2.rows.count, 2); 157 | 158 | 159 | // when you make some rows to a section that doesn't already exist, will automatically create a new section. 160 | 161 | [self.tableView holo_makeRowsInSection:@"section-1000" block:^(HoloTableViewRowMaker * _Nonnull make) { 162 | make.row(UITableViewCell.class).tag(@"2").model(@"2").height(2); 163 | }]; 164 | 165 | // section(TAG) 166 | // section(@"section-1") 167 | // section(@"section-1") 168 | // section(@"section-1000") 169 | 170 | XCTAssertEqual(self.tableView.holo_sections.count, 4); 171 | 172 | HoloTableSection *section3 = self.tableView.holo_sections[3]; 173 | XCTAssertEqual(section3.rows.count, 1); 174 | } 175 | 176 | - (void)testPerformanceExample { 177 | // This is an example of a performance test case. 178 | [self measureBlock:^{ 179 | // Put the code you want to measure the time of here. 180 | }]; 181 | } 182 | 183 | @end 184 | -------------------------------------------------------------------------------- /Example/Tests/HoloTableRowRemakerTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableRowRemakerTest.m 3 | // HoloTableView_Tests 4 | // 5 | // Created by 与佳期 on 2021/5/22. 6 | // Copyright © 2021 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface TestTableViewCell2 : UITableViewCell 13 | @end 14 | @implementation TestTableViewCell2 15 | @end 16 | 17 | 18 | @interface HoloTableRowRemakerTest : XCTestCase 19 | 20 | @property (nonatomic, strong) UITableView *tableView; 21 | 22 | @end 23 | 24 | @implementation HoloTableRowRemakerTest 25 | 26 | - (void)setUp { 27 | // Put setup code here. This method is called before the invocation of each test method in the class. 28 | 29 | self.tableView = [UITableView new]; 30 | 31 | [self.tableView holo_makeRows:^(HoloTableViewRowMaker * _Nonnull make) { 32 | make.row(UITableViewCell.class) 33 | .model(@"model") 34 | .modelHandler(^id _Nonnull{ 35 | return @"modelHandler"; 36 | }) 37 | 38 | .style(UITableViewCellStyleValue1) 39 | .styleHandler(^UITableViewCellStyle(id _Nullable model) { 40 | return UITableViewCellStyleValue2; 41 | }) 42 | 43 | .reuseId(@"reuseId") 44 | .reuseIdHandler(^NSString * _Nonnull(id _Nullable model) { 45 | return @"reuseIdHandler"; 46 | }) 47 | 48 | .tag(TAG) 49 | 50 | .height(10) 51 | .heightHandler(^CGFloat(id _Nullable model) { 52 | return 11; 53 | }) 54 | 55 | .estimatedHeight(100) 56 | .estimatedHeightHandler(^CGFloat(id _Nullable model) { 57 | return 101; 58 | }) 59 | 60 | .shouldHighlight(NO) 61 | .shouldHighlightHandler(^BOOL(id _Nullable model) { 62 | return NO; 63 | }) 64 | 65 | .canEdit(YES) 66 | .canEditHandler(^BOOL(id _Nullable model) { 67 | return YES; 68 | }) 69 | 70 | .canMove(YES) 71 | .canMoveHandler(^BOOL(id _Nullable model) { 72 | return YES; 73 | }) 74 | 75 | .leadingSwipeActions(@[[HoloTableViewRowSwipeAction new]]) 76 | .trailingSwipeActions(@[[HoloTableViewRowSwipeAction new]]) 77 | 78 | .editingDeleteTitle(@"editingDeleteTitle") 79 | .editingDeleteTitleHandler(^NSString * _Nonnull(id _Nullable model) { 80 | return @"editingDeleteTitleHandler"; 81 | }) 82 | 83 | .editingStyle(UITableViewCellEditingStyleDelete) 84 | .editingStyleHandler(^UITableViewCellEditingStyle(id _Nullable model) { 85 | return UITableViewCellEditingStyleInsert; 86 | }); 87 | }]; 88 | 89 | 90 | // remake rows in section 91 | 92 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 93 | make.section(@"section-1").headerHeight(100).makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 94 | make.row(UITableViewCell.class).tag(@"0").model(@"0").height(0); 95 | make.row(UITableViewCell.class).tag(@"1").model(@"1").height(1); 96 | }); 97 | 98 | make.section(@"section-1").headerHeight(100).makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 99 | make.row(UITableViewCell.class).tag(@"0").model(@"0").height(0); 100 | make.row(UITableViewCell.class).tag(@"1").model(@"1").height(1); 101 | }); 102 | }]; 103 | } 104 | 105 | - (void)tearDown { 106 | // Put teardown code here. This method is called after the invocation of each test method in the class. 107 | } 108 | 109 | 110 | #pragma mark - remake rows 111 | 112 | - (void)testRemakeRows { 113 | [self.tableView holo_remakeRows:^(HoloTableViewUpdateRowMaker * _Nonnull make) { 114 | make.tag(TAG).row(TestTableViewCell2.class); 115 | }]; 116 | 117 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 118 | 119 | HoloTableSection *section = self.tableView.holo_sections[0]; 120 | 121 | XCTAssertEqual(section.rows.count, 1); 122 | 123 | HoloTableRow *row = section.rows[0]; 124 | 125 | 126 | XCTAssertEqual(row.cell, TestTableViewCell2.class); 127 | XCTAssertNil(row.model); 128 | XCTAssertEqual(row.style, UITableViewCellStyleDefault); 129 | XCTAssertNil(row.reuseId); 130 | XCTAssertEqual(row.height, CGFLOAT_MIN); 131 | XCTAssertEqual(row.estimatedHeight, CGFLOAT_MIN); 132 | XCTAssertEqual(row.shouldHighlight, YES); 133 | XCTAssertEqual(row.canEdit, NO); 134 | XCTAssertEqual(row.canMove, NO); 135 | XCTAssertEqual(row.leadingSwipeActions.count, 0); 136 | XCTAssertEqual(row.trailingSwipeActions.count, 0); 137 | XCTAssertNil(row.editingDeleteTitle); 138 | XCTAssertEqual(row.editingStyle, UITableViewCellEditingStyleNone); 139 | 140 | 141 | // multiple rows with the same tag 142 | 143 | [self.tableView holo_makeRows:^(HoloTableViewRowMaker * _Nonnull make) { 144 | make.row(UITableViewCell.class).tag(@"1"); 145 | make.row(UITableViewCell.class).tag(@"1"); 146 | }]; 147 | 148 | HoloTableRow *row1 = section.rows[1]; 149 | HoloTableRow *row2 = section.rows[2]; 150 | 151 | XCTAssertEqual(row1.cell, UITableViewCell.class); 152 | XCTAssertEqual(row2.cell, UITableViewCell.class); 153 | 154 | [self.tableView holo_remakeRows:^(HoloTableViewUpdateRowMaker * _Nonnull make) { 155 | make.tag(@"1").row(TestTableViewCell2.class); 156 | make.tag(@"1").row(TestTableViewCell2.class); 157 | }]; 158 | 159 | HoloTableRow *rowNew1 = section.rows[1]; 160 | HoloTableRow *rowNew2 = section.rows[2]; 161 | XCTAssertEqual(rowNew1.cell, TestTableViewCell2.class); 162 | XCTAssertEqual(rowNew2.cell, UITableViewCell.class); 163 | } 164 | 165 | 166 | #pragma mark - remake rows in section 167 | 168 | - (void)testRemakeRowsInSection { 169 | [self.tableView holo_remakeRowsInSection:@"section-1" block:^(HoloTableViewUpdateRowMaker * _Nonnull make) { 170 | make.tag(@"0").row(UITableViewCell.class); 171 | }]; 172 | 173 | // section(TAG) 174 | // section(@"section-1") 175 | // section(@"section-1") 176 | 177 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 178 | 179 | HoloTableSection *section0 = self.tableView.holo_sections[0]; 180 | HoloTableSection *section1 = self.tableView.holo_sections[1]; 181 | HoloTableSection *section2 = self.tableView.holo_sections[2]; 182 | 183 | XCTAssertEqual(section0.rows.count, 1); 184 | XCTAssertEqual(section1.rows.count, 2); 185 | XCTAssertEqual(section2.rows.count, 2); 186 | 187 | HoloTableRow *row0InSection1 = section1.rows[0]; 188 | HoloTableRow *row1InSection1 = section1.rows[1]; 189 | 190 | XCTAssertEqual(row0InSection1.height, CGFLOAT_MIN); // changed 191 | XCTAssertNil(row0InSection1.model); // changed 192 | XCTAssertEqual(row1InSection1.height, 1); 193 | 194 | HoloTableRow *row0InSection2 = section2.rows[0]; 195 | HoloTableRow *row1InSection2 = section2.rows[1]; 196 | 197 | XCTAssertEqual(row0InSection2.height, 0); 198 | XCTAssertEqual(row1InSection2.height, 1); 199 | 200 | 201 | // when you remake some rows to a section that doesn't already exist, then ignore it. 202 | 203 | [self.tableView holo_remakeRowsInSection:@"section-1000" block:^(HoloTableViewUpdateRowMaker * _Nonnull make) { 204 | make.tag(@"0").row(UITableViewCell.class); 205 | }]; 206 | 207 | // section(TAG) 208 | // section(@"section-1") 209 | // section(@"section-1") 210 | 211 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 212 | } 213 | 214 | - (void)testPerformanceExample { 215 | // This is an example of a performance test case. 216 | [self measureBlock:^{ 217 | // Put the code you want to measure the time of here. 218 | }]; 219 | } 220 | 221 | @end 222 | -------------------------------------------------------------------------------- /Example/Tests/HoloTableRowRemoverTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableRowRemoverTest.m 3 | // HoloTableView_Tests 4 | // 5 | // Created by 与佳期 on 2021/5/22. 6 | // Copyright © 2021 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface HoloTableRowRemoverTest : XCTestCase 13 | 14 | @property (nonatomic, strong) UITableView *tableView; 15 | 16 | @end 17 | 18 | @implementation HoloTableRowRemoverTest 19 | 20 | - (void)setUp { 21 | // Put setup code here. This method is called before the invocation of each test method in the class. 22 | 23 | self.tableView = [UITableView new]; 24 | 25 | [self.tableView holo_makeRows:^(HoloTableViewRowMaker * _Nonnull make) { 26 | make.row(UITableViewCell.class).tag(TAG); 27 | }]; 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | } 33 | 34 | - (void)testRemoveRows { 35 | [self.tableView holo_makeRows:^(HoloTableViewRowMaker * _Nonnull make) { 36 | make.row(UITableViewCell.class).tag(@"1"); 37 | make.row(UITableViewCell.class).tag(@"2"); 38 | make.row(UITableViewCell.class).tag(@"2"); 39 | make.row(UITableViewCell.class).tag(@"3"); 40 | }]; 41 | XCTAssertEqual(self.tableView.holo_sections.firstObject.rows.count, 5); 42 | 43 | [self.tableView holo_removeRows:@[@"1", @"2"]]; 44 | 45 | XCTAssertEqual(self.tableView.holo_sections.firstObject.rows.count, 2); 46 | 47 | HoloTableRow *lastRow = self.tableView.holo_sections.firstObject.rows[1]; 48 | XCTAssertEqual(lastRow.tag, @"3"); 49 | 50 | [self.tableView holo_removeAllSections]; 51 | XCTAssertEqual(self.tableView.holo_sections.firstObject.rows.count, 0); 52 | } 53 | 54 | - (void)testPerformanceExample { 55 | // This is an example of a performance test case. 56 | [self measureBlock:^{ 57 | // Put the code you want to measure the time of here. 58 | }]; 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /Example/Tests/HoloTableRowUpdaterTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableRowUpdaterTest.m 3 | // HoloTableView_Tests 4 | // 5 | // Created by 与佳期 on 2021/5/22. 6 | // Copyright © 2021 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface TestTableViewCell : UITableViewCell 13 | @end 14 | @implementation TestTableViewCell 15 | @end 16 | 17 | 18 | @interface HoloTableRowUpdaterTest : XCTestCase 19 | 20 | @property (nonatomic, strong) UITableView *tableView; 21 | 22 | @end 23 | 24 | @implementation HoloTableRowUpdaterTest 25 | 26 | - (void)setUp { 27 | // Put setup code here. This method is called before the invocation of each test method in the class. 28 | 29 | self.tableView = [UITableView new]; 30 | 31 | [self.tableView holo_makeRows:^(HoloTableViewRowMaker * _Nonnull make) { 32 | make.row(UITableViewCell.class) 33 | .model(@"model") 34 | .modelHandler(^id _Nonnull{ 35 | return @"modelHandler"; 36 | }) 37 | 38 | .style(UITableViewCellStyleValue1) 39 | .styleHandler(^UITableViewCellStyle(id _Nullable model) { 40 | return UITableViewCellStyleValue2; 41 | }) 42 | 43 | .reuseId(@"reuseId") 44 | .reuseIdHandler(^NSString * _Nonnull(id _Nullable model) { 45 | return @"reuseIdHandler"; 46 | }) 47 | 48 | .tag(TAG) 49 | 50 | .height(10) 51 | .heightHandler(^CGFloat(id _Nullable model) { 52 | return 11; 53 | }) 54 | 55 | .estimatedHeight(100) 56 | .estimatedHeightHandler(^CGFloat(id _Nullable model) { 57 | return 101; 58 | }) 59 | 60 | .shouldHighlight(NO) 61 | .shouldHighlightHandler(^BOOL(id _Nullable model) { 62 | return NO; 63 | }) 64 | 65 | .canEdit(YES) 66 | .canEditHandler(^BOOL(id _Nullable model) { 67 | return YES; 68 | }) 69 | 70 | .canMove(YES) 71 | .canMoveHandler(^BOOL(id _Nullable model) { 72 | return YES; 73 | }) 74 | 75 | .leadingSwipeActions(@[[HoloTableViewRowSwipeAction new]]) 76 | .trailingSwipeActions(@[[HoloTableViewRowSwipeAction new]]) 77 | 78 | .editingDeleteTitle(@"editingDeleteTitle") 79 | .editingDeleteTitleHandler(^NSString * _Nonnull(id _Nullable model) { 80 | return @"editingDeleteTitleHandler"; 81 | }) 82 | 83 | .editingStyle(UITableViewCellEditingStyleDelete) 84 | .editingStyleHandler(^UITableViewCellEditingStyle(id _Nullable model) { 85 | return UITableViewCellEditingStyleInsert; 86 | }); 87 | }]; 88 | 89 | 90 | // update rows in section 91 | 92 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 93 | make.section(@"section-1").headerHeight(100).makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 94 | make.row(UITableViewCell.class).tag(@"0").model(@"0").height(0); 95 | make.row(UITableViewCell.class).tag(@"1").model(@"1").height(1); 96 | }); 97 | 98 | make.section(@"section-1").headerHeight(100).makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 99 | make.row(UITableViewCell.class).tag(@"0").model(@"0").height(0); 100 | make.row(UITableViewCell.class).tag(@"1").model(@"1").height(1); 101 | }); 102 | }]; 103 | } 104 | 105 | - (void)tearDown { 106 | // Put teardown code here. This method is called after the invocation of each test method in the class. 107 | } 108 | 109 | #pragma mark - update rows 110 | 111 | - (void)testUpdateRows { 112 | [self.tableView holo_updateRows:^(HoloTableViewUpdateRowMaker * _Nonnull make) { 113 | make.tag(TAG) 114 | .row(TestTableViewCell.class) 115 | .model(@"model-new") 116 | .style(UITableViewCellStyleValue2) 117 | .reuseId(@"reuseId-new") 118 | .height(101) 119 | .estimatedHeight(1001) 120 | .shouldHighlight(YES) 121 | .canEdit(NO) 122 | .canMove(NO) 123 | .leadingSwipeActions(@[]) 124 | .trailingSwipeActions(@[]) 125 | .editingDeleteTitle(@"editingDeleteTitle-new") 126 | .editingStyle(UITableViewCellEditingStyleInsert); 127 | }]; 128 | 129 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 130 | 131 | HoloTableSection *section = self.tableView.holo_sections[0]; 132 | 133 | XCTAssertEqual(section.rows.count, 1); 134 | 135 | HoloTableRow *row = section.rows[0]; 136 | 137 | 138 | XCTAssertEqual(row.cell, TestTableViewCell.class); 139 | XCTAssertEqual(row.model, @"model-new"); 140 | XCTAssertEqual(row.style, UITableViewCellStyleValue2); 141 | XCTAssertEqual(row.reuseId, @"reuseId-new"); 142 | XCTAssertEqual(row.height, 101); 143 | XCTAssertEqual(row.estimatedHeight, 1001); 144 | XCTAssertEqual(row.shouldHighlight, YES); 145 | XCTAssertEqual(row.canEdit, NO); 146 | XCTAssertEqual(row.canMove, NO); 147 | XCTAssertEqual(row.leadingSwipeActions.count, 0); 148 | XCTAssertEqual(row.trailingSwipeActions.count, 0); 149 | XCTAssertEqual(row.editingDeleteTitle, @"editingDeleteTitle-new"); 150 | XCTAssertEqual(row.editingStyle, UITableViewCellEditingStyleInsert); 151 | 152 | 153 | // multiple rows with the same tag 154 | 155 | [self.tableView holo_makeRows:^(HoloTableViewRowMaker * _Nonnull make) { 156 | make.row(UITableViewCell.class).tag(@"1").height(1); 157 | make.row(UITableViewCell.class).tag(@"1").height(10); 158 | }]; 159 | 160 | HoloTableRow *row1 = section.rows[1]; 161 | HoloTableRow *row2 = section.rows[2]; 162 | 163 | XCTAssertEqual(row1.height, 1); 164 | XCTAssertEqual(row2.height, 10); 165 | 166 | [self.tableView holo_updateRows:^(HoloTableViewUpdateRowMaker * _Nonnull make) { 167 | make.tag(@"1").height(100); 168 | make.tag(@"1").height(101); 169 | }]; 170 | 171 | HoloTableRow *rowNew1 = section.rows[1]; 172 | HoloTableRow *rowNew2 = section.rows[2]; 173 | 174 | XCTAssertEqual(rowNew1.height, 101); 175 | XCTAssertEqual(rowNew2.height, 10); 176 | } 177 | 178 | #pragma mark - update rows in section 179 | 180 | - (void)testUpdateRowsInSection { 181 | [self.tableView holo_updateRowsInSection:@"section-1" block:^(HoloTableViewUpdateRowMaker * _Nonnull make) { 182 | make.tag(@"0").height(1000); 183 | }]; 184 | 185 | // section(TAG) 186 | // section(@"section-1") 187 | // section(@"section-1") 188 | 189 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 190 | 191 | HoloTableSection *section0 = self.tableView.holo_sections[0]; 192 | HoloTableSection *section1 = self.tableView.holo_sections[1]; 193 | HoloTableSection *section2 = self.tableView.holo_sections[2]; 194 | 195 | XCTAssertEqual(section0.rows.count, 1); 196 | XCTAssertEqual(section1.rows.count, 2); 197 | XCTAssertEqual(section2.rows.count, 2); 198 | 199 | HoloTableRow *row0InSection1 = section1.rows[0]; 200 | HoloTableRow *row1InSection1 = section1.rows[1]; 201 | 202 | XCTAssertEqual(row0InSection1.height, 1000); // changed 203 | XCTAssertEqual(row1InSection1.height, 1); 204 | 205 | HoloTableRow *row0InSection2 = section2.rows[0]; 206 | HoloTableRow *row1InSection2 = section2.rows[1]; 207 | 208 | XCTAssertEqual(row0InSection2.height, 0); 209 | XCTAssertEqual(row1InSection2.height, 1); 210 | 211 | 212 | // when you update some rows to a section that doesn't already exist, then ignore it. 213 | 214 | [self.tableView holo_updateRowsInSection:@"section-1000" block:^(HoloTableViewUpdateRowMaker * _Nonnull make) { 215 | make.tag(@"1").height(1000); 216 | }]; 217 | 218 | // section(TAG) 219 | // section(@"section-1") 220 | // section(@"section-1") 221 | 222 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 223 | } 224 | 225 | 226 | - (void)testPerformanceExample { 227 | // This is an example of a performance test case. 228 | [self measureBlock:^{ 229 | // Put the code you want to measure the time of here. 230 | }]; 231 | } 232 | 233 | @end 234 | -------------------------------------------------------------------------------- /Example/Tests/HoloTableSectionInsterTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableSectionInsterTest.m 3 | // HoloTableView_Tests 4 | // 5 | // Created by 与佳期 on 2021/5/22. 6 | // Copyright © 2021 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface HoloTableSectionInsterTest : XCTestCase 13 | 14 | @property (nonatomic, strong) UITableView *tableView; 15 | 16 | @end 17 | 18 | @implementation HoloTableSectionInsterTest 19 | 20 | - (void)setUp { 21 | // Put setup code here. This method is called before the invocation of each test method in the class. 22 | self.tableView = [UITableView new]; 23 | 24 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 25 | make.section(TAG); 26 | }]; 27 | } 28 | 29 | - (void)tearDown { 30 | // Put teardown code here. This method is called after the invocation of each test method in the class. 31 | } 32 | 33 | - (void)testInsertSections { 34 | [self.tableView holo_insertSectionsAtIndex:0 block:^(HoloTableViewSectionMaker * _Nonnull make) { 35 | make.section(@"0").headerHeight(0); 36 | make.section(@"1").headerHeight(1); 37 | }]; 38 | 39 | // section(@"0") 40 | // section(@"1") 41 | // section(TAG) 42 | 43 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 44 | 45 | HoloTableSection *section0 = self.tableView.holo_sections[0]; 46 | HoloTableSection *section1 = self.tableView.holo_sections[1]; 47 | HoloTableSection *section2 = self.tableView.holo_sections[2]; 48 | 49 | XCTAssertEqual(section0.tag, @"0"); 50 | XCTAssertEqual(section1.tag, @"1"); 51 | XCTAssertEqual(section2.tag, TAG); 52 | 53 | XCTAssertEqual(section0.headerHeight, 0); 54 | XCTAssertEqual(section1.headerHeight, 1); 55 | XCTAssertEqual(section2.headerHeight, CGFLOAT_MIN); 56 | 57 | 58 | [self.tableView holo_insertSectionsAtIndex:3 block:^(HoloTableViewSectionMaker * _Nonnull make) { 59 | make.section(@"3").headerHeight(3); 60 | make.section(@"4").headerHeight(4); 61 | }]; 62 | 63 | // section(@"0") 64 | // section(@"1") 65 | // section(TAG) 66 | // section(@"2") 67 | // section(@"3") 68 | 69 | XCTAssertEqual(self.tableView.holo_sections.count, 5); 70 | 71 | HoloTableSection *section3 = self.tableView.holo_sections[3]; 72 | HoloTableSection *section4 = self.tableView.holo_sections[4]; 73 | 74 | XCTAssertEqual(section3.tag, @"3"); 75 | XCTAssertEqual(section3.headerHeight, 3); 76 | 77 | XCTAssertEqual(section4.tag, @"4"); 78 | XCTAssertEqual(section4.headerHeight, 4); 79 | } 80 | 81 | - (void)testPerformanceExample { 82 | // This is an example of a performance test case. 83 | [self measureBlock:^{ 84 | // Put the code you want to measure the time of here. 85 | }]; 86 | } 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /Example/Tests/HoloTableSectionMakerTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableSectionMakerTest.m 3 | // HoloTableView_Tests 4 | // 5 | // Created by 与佳期 on 2021/5/20. 6 | // Copyright © 2021 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface HoloTableSectionMakerTest : XCTestCase 13 | 14 | @property (nonatomic, strong) UITableView *tableView; 15 | 16 | @end 17 | 18 | @implementation HoloTableSectionMakerTest 19 | 20 | - (void)setUp { 21 | // Put setup code here. This method is called before the invocation of each test method in the class. 22 | self.tableView = [UITableView new]; 23 | 24 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 25 | make.section(TAG) 26 | .header(UITableViewHeaderFooterView.class) 27 | .footer(UITableViewHeaderFooterView.class) 28 | 29 | .headerReuseId(@"headerReuseId") 30 | .headerReuseIdHandler(^NSString * _Nonnull(id _Nullable model) { 31 | return @"headerReuseIdHandler"; 32 | }) 33 | .footerReuseId(@"footerReuseId") 34 | .footerReuseIdHandler(^NSString * _Nonnull(id _Nullable model) { 35 | return @"footerReuseIdHandler"; 36 | }) 37 | 38 | .headerTitle(@"headerTitle") 39 | .headerTitleHandler(^NSString * _Nonnull{ 40 | return @"headerTitleHandler"; 41 | }) 42 | .footerTitle(@"footerTitle") 43 | .footerTitleHandler(^NSString * _Nonnull{ 44 | return @"footerTitleHandler"; 45 | }) 46 | 47 | .headerModel(@"headerModel") 48 | .headerModelHandler(^id _Nonnull{ 49 | return @"headerModelHandler"; 50 | }) 51 | .footerModel(@"footerModel") 52 | .footerModelHandler(^id _Nonnull{ 53 | return @"footerModelHandler"; 54 | }) 55 | 56 | .headerHeight(10) 57 | .headerHeightHandler(^CGFloat(id _Nullable model) { 58 | return 11; 59 | }) 60 | .footerHeight(20) 61 | .footerHeightHandler(^CGFloat(id _Nullable model) { 62 | return 21; 63 | }) 64 | 65 | .headerEstimatedHeight(100) 66 | .headerEstimatedHeightHandler(^CGFloat(id _Nullable model) { 67 | return 101; 68 | }) 69 | .footerEstimatedHeight(200) 70 | .footerEstimatedHeightHandler(^CGFloat(id _Nullable model) { 71 | return 201; 72 | }); 73 | }]; 74 | 75 | 76 | // makeSections with rows 77 | 78 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 79 | make.section(@"section-1").makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 80 | make.row(UITableViewCell.class).tag(@"0").model(@"0").height(0); 81 | make.row(UITableViewCell.class).tag(@"1").model(@"1").height(1); 82 | }); 83 | }]; 84 | } 85 | 86 | - (void)tearDown { 87 | // Put teardown code here. This method is called after the invocation of each test method in the class. 88 | } 89 | 90 | 91 | #pragma mark - makeSections 92 | 93 | - (void)testMakeSections { 94 | // This is an example of a functional test case. 95 | // Use XCTAssert and related functions to verify your tests produce the correct results. 96 | 97 | XCTAssertEqual(self.tableView.holo_sections.count, 2); 98 | 99 | HoloTableSection *section = self.tableView.holo_sections[0]; 100 | 101 | XCTAssertEqual(section.tag, TAG); 102 | 103 | XCTAssertEqual(section.header, UITableViewHeaderFooterView.class); 104 | XCTAssertEqual(section.footer, UITableViewHeaderFooterView.class); 105 | 106 | XCTAssertEqual(section.headerReuseId, @"headerReuseId"); 107 | XCTAssertEqual(section.footerReuseId, @"footerReuseId"); 108 | 109 | XCTAssertEqual(section.headerTitle, @"headerTitle"); 110 | XCTAssertEqual(section.footerTitle, @"footerTitle"); 111 | 112 | XCTAssertEqual(section.headerModel, @"headerModel"); 113 | XCTAssertEqual(section.footerModel, @"footerModel"); 114 | 115 | XCTAssertEqual(section.headerHeight, 10); 116 | XCTAssertEqual(section.footerHeight, 20); 117 | 118 | XCTAssertEqual(section.headerEstimatedHeight, 100); 119 | XCTAssertEqual(section.footerEstimatedHeight, 200); 120 | } 121 | 122 | 123 | #pragma mark - makeSections with rows 124 | 125 | - (void)testMakeSectionsMakeRows { 126 | // This is an example of a functional test case. 127 | // Use XCTAssert and related functions to verify your tests produce the correct results. 128 | 129 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 130 | make.section(@"section-1").makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 131 | make.row(UITableViewCell.class).model(@"0").height(0); 132 | make.row(UITableViewCell.class).model(@"1").height(1); 133 | }); 134 | }]; 135 | 136 | // section(TAG) 137 | // section(@"section-1") 138 | // section(@"section-1") 139 | 140 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 141 | 142 | HoloTableSection *section = self.tableView.holo_sections[2]; 143 | 144 | XCTAssertEqual(section.rows.count, 2); 145 | 146 | HoloTableRow *row0 = section.rows[0]; 147 | HoloTableRow *row1 = section.rows[1]; 148 | 149 | XCTAssertEqual(row0.cell, UITableViewCell.class); 150 | XCTAssertEqual(row0.model, @"0"); 151 | XCTAssertEqual(row0.height, 0); 152 | 153 | XCTAssertEqual(row1.cell, UITableViewCell.class); 154 | XCTAssertEqual(row1.model, @"1"); 155 | XCTAssertEqual(row1.height, 1); 156 | } 157 | 158 | - (void)testMakeSectionsUpdateRows { 159 | // This is an example of a functional test case. 160 | // Use XCTAssert and related functions to verify your tests produce the correct results. 161 | 162 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 163 | make.section(@"section-1").updateRows(^(HoloTableViewUpdateRowMaker * _Nonnull make) { 164 | make.tag(@"0").height(0); 165 | make.tag(@"1").height(1); 166 | }); 167 | }]; 168 | 169 | // section(TAG) 170 | // section(@"section-1") 171 | // section(@"section-1") 172 | 173 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 174 | 175 | HoloTableSection *section = self.tableView.holo_sections[2]; 176 | 177 | XCTAssertEqual(section.rows.count, 0); 178 | } 179 | 180 | - (void)testMakeSectionsRemakeRows { 181 | // This is an example of a functional test case. 182 | // Use XCTAssert and related functions to verify your tests produce the correct results. 183 | 184 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 185 | make.section(@"section-1").remakeRows(^(HoloTableViewUpdateRowMaker * _Nonnull make) { 186 | make.tag(@"0").height(0); 187 | make.tag(@"1").height(1); 188 | }); 189 | }]; 190 | 191 | // section(TAG) 192 | // section(@"section-1") 193 | // section(@"section-1") 194 | 195 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 196 | 197 | HoloTableSection *section = self.tableView.holo_sections[2]; 198 | 199 | XCTAssertEqual(section.rows.count, 0); 200 | } 201 | 202 | - (void)testPerformanceExample { 203 | // This is an example of a performance test case. 204 | [self measureBlock:^{ 205 | // Put the code you want to measure the time of here. 206 | }]; 207 | } 208 | 209 | @end 210 | -------------------------------------------------------------------------------- /Example/Tests/HoloTableSectionRemakerTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableSectionRemakerTest.m 3 | // HoloTableView_Tests 4 | // 5 | // Created by 与佳期 on 2021/5/22. 6 | // Copyright © 2021 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface HoloTableSectionRemakerTest : XCTestCase 13 | 14 | @property (nonatomic, strong) UITableView *tableView; 15 | 16 | @end 17 | 18 | @implementation HoloTableSectionRemakerTest 19 | 20 | - (void)setUp { 21 | // Put setup code here. This method is called before the invocation of each test method in the class. 22 | self.tableView = [UITableView new]; 23 | 24 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 25 | make.section(TAG) 26 | .header(UITableViewHeaderFooterView.class) 27 | .footer(UITableViewHeaderFooterView.class) 28 | 29 | .headerReuseId(@"headerReuseId") 30 | .headerReuseIdHandler(^NSString * _Nonnull(id _Nullable model) { 31 | return @"headerReuseIdHandler"; 32 | }) 33 | .footerReuseId(@"footerReuseId") 34 | .footerReuseIdHandler(^NSString * _Nonnull(id _Nullable model) { 35 | return @"footerReuseIdHandler"; 36 | }) 37 | 38 | .headerTitle(@"headerTitle") 39 | .headerTitleHandler(^NSString * _Nonnull{ 40 | return @"headerTitleHandler"; 41 | }) 42 | .footerTitle(@"footerTitle") 43 | .footerTitleHandler(^NSString * _Nonnull{ 44 | return @"footerTitleHandler"; 45 | }) 46 | 47 | .headerModel(@"headerModel") 48 | .headerModelHandler(^id _Nonnull{ 49 | return @"headerModelHandler"; 50 | }) 51 | .footerModel(@"footerModel") 52 | .footerModelHandler(^id _Nonnull{ 53 | return @"footerModelHandler"; 54 | }) 55 | 56 | .headerHeight(10) 57 | .headerHeightHandler(^CGFloat(id _Nullable model) { 58 | return 11; 59 | }) 60 | .footerHeight(20) 61 | .footerHeightHandler(^CGFloat(id _Nullable model) { 62 | return 21; 63 | }) 64 | 65 | .headerEstimatedHeight(100) 66 | .headerEstimatedHeightHandler(^CGFloat(id _Nullable model) { 67 | return 101; 68 | }) 69 | .footerEstimatedHeight(200) 70 | .footerEstimatedHeightHandler(^CGFloat(id _Nullable model) { 71 | return 201; 72 | }); 73 | }]; 74 | 75 | 76 | // remakeSections with rows 77 | 78 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 79 | make.section(@"section-1").makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 80 | make.row(UITableViewCell.class).tag(@"0").model(@"0").height(0); 81 | make.row(UITableViewCell.class).tag(@"1").model(@"1").height(1); 82 | }); 83 | }]; 84 | } 85 | 86 | - (void)tearDown { 87 | // Put teardown code here. This method is called after the invocation of each test method in the class. 88 | } 89 | 90 | #pragma mark - remakeSections 91 | 92 | - (void)testRemakeSections { 93 | [self.tableView holo_remakeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 94 | make.section(TAG); 95 | }]; 96 | HoloTableSection *section = self.tableView.holo_sections.firstObject; 97 | 98 | XCTAssertEqual(section.header, UITableViewHeaderFooterView.class); 99 | XCTAssertEqual(section.footer, UITableViewHeaderFooterView.class); 100 | 101 | XCTAssertNil(section.headerReuseId); 102 | XCTAssertNil(section.footerReuseId); 103 | 104 | XCTAssertNil(section.headerTitle); 105 | XCTAssertNil(section.footerTitle); 106 | 107 | XCTAssertNil(section.headerModel); 108 | XCTAssertNil(section.footerModel); 109 | 110 | XCTAssertEqual(section.headerHeight, CGFLOAT_MIN); 111 | XCTAssertEqual(section.footerHeight, CGFLOAT_MIN); 112 | 113 | XCTAssertEqual(section.headerEstimatedHeight, CGFLOAT_MIN); 114 | XCTAssertEqual(section.footerEstimatedHeight, CGFLOAT_MIN); 115 | 116 | 117 | // multiple sections with the same tag 118 | 119 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 120 | make.section(@"section-1").headerHeight(1); 121 | }]; 122 | 123 | // section(TAG) 124 | // section(@"section-1") 125 | // section(@"section-1") 126 | 127 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 128 | 129 | HoloTableSection *section1 = self.tableView.holo_sections[1]; 130 | HoloTableSection *section2 = self.tableView.holo_sections[2]; 131 | 132 | XCTAssertEqual(section1.headerHeight, CGFLOAT_MIN); 133 | XCTAssertEqual(section2.headerHeight, 1); 134 | 135 | [self.tableView holo_remakeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 136 | make.section(@"section-1"); 137 | make.section(@"section-1"); 138 | }]; 139 | 140 | HoloTableSection *sectionNew1 = self.tableView.holo_sections[1]; 141 | HoloTableSection *sectionNew2 = self.tableView.holo_sections[2]; 142 | XCTAssertEqual(sectionNew1.headerHeight, CGFLOAT_MIN); // changed 143 | XCTAssertEqual(sectionNew2.headerHeight, 1); // not changed 144 | } 145 | 146 | 147 | #pragma mark - remakeSections with rows 148 | 149 | - (void)testRemakeSectionsMakeRows { 150 | // This is an example of a functional test case. 151 | // Use XCTAssert and related functions to verify your tests produce the correct results. 152 | 153 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 154 | make.section(@"section-1").makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 155 | make.row(UITableViewCell.class).model(@"0").height(0); 156 | make.row(UITableViewCell.class).model(@"1").height(1); 157 | }); 158 | }]; 159 | 160 | // section(TAG) 161 | // section(@"section-1") 162 | // section(@"section-1") 163 | 164 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 165 | 166 | // not found a section with the tag 167 | 168 | [self.tableView holo_remakeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 169 | make.section(@"section-2").makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 170 | make.row(UITableViewCell.class).model(@"0").height(0); 171 | make.row(UITableViewCell.class).model(@"1").height(1); 172 | make.row(UITableViewCell.class).model(@"2").height(2); 173 | }); 174 | }]; 175 | 176 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 177 | 178 | HoloTableSection *section1 = self.tableView.holo_sections[1]; 179 | HoloTableSection *section2 = self.tableView.holo_sections[2]; 180 | 181 | XCTAssertEqual(section1.rows.count, 2); 182 | XCTAssertEqual(section2.rows.count, 2); 183 | 184 | 185 | // found a section with the tag 186 | 187 | [self.tableView holo_remakeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 188 | make.section(@"section-1").makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 189 | make.row(UITableViewCell.class).model(@"0").height(0); 190 | make.row(UITableViewCell.class).model(@"1").height(1); 191 | make.row(UITableViewCell.class).model(@"2").height(2); 192 | }); 193 | }]; 194 | 195 | XCTAssertEqual(self.tableView.holo_sections.count, 3); 196 | 197 | HoloTableSection *section1_new = self.tableView.holo_sections[1]; 198 | HoloTableSection *section2_old = self.tableView.holo_sections[2]; 199 | 200 | XCTAssertEqual(section1_new.rows.count, 3); 201 | XCTAssertEqual(section2_old.rows.count, 2); 202 | 203 | HoloTableRow *row0 = section1_new.rows[0]; 204 | HoloTableRow *row1 = section1_new.rows[1]; 205 | 206 | XCTAssertEqual(row0.cell, UITableViewCell.class); 207 | XCTAssertEqual(row0.model, @"0"); 208 | XCTAssertEqual(row0.height, 0); 209 | 210 | XCTAssertEqual(row1.cell, UITableViewCell.class); 211 | XCTAssertEqual(row1.model, @"1"); 212 | XCTAssertEqual(row1.height, 1); 213 | } 214 | 215 | - (void)testRemakeSectionsUpdateRows { 216 | // This is an example of a functional test case. 217 | // Use XCTAssert and related functions to verify your tests produce the correct results. 218 | 219 | [self.tableView holo_remakeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 220 | make.section(@"section-1").updateRows(^(HoloTableViewUpdateRowMaker * _Nonnull make) { 221 | make.tag(@"1").height(1000); 222 | make.tag(@"2").height(2000); 223 | }); 224 | }]; 225 | 226 | // section(TAG) 227 | // section(@"section-1") 228 | 229 | XCTAssertEqual(self.tableView.holo_sections.count, 2); 230 | 231 | HoloTableSection *section1 = self.tableView.holo_sections[1]; 232 | 233 | XCTAssertEqual(section1.rows.count, 0); 234 | } 235 | 236 | - (void)testRemakeSectionsRemakeRows { 237 | // This is an example of a functional test case. 238 | // Use XCTAssert and related functions to verify your tests produce the correct results. 239 | 240 | [self.tableView holo_remakeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 241 | make.section(@"section-1").remakeRows(^(HoloTableViewUpdateRowMaker * _Nonnull make) { 242 | make.tag(@"1").height(1000); 243 | make.tag(@"2").height(2000); 244 | }); 245 | }]; 246 | 247 | // section(TAG) 248 | // section(@"section-1") 249 | 250 | XCTAssertEqual(self.tableView.holo_sections.count, 2); 251 | 252 | HoloTableSection *section1 = self.tableView.holo_sections[1]; 253 | 254 | XCTAssertEqual(section1.rows.count, 0); 255 | } 256 | 257 | - (void)testPerformanceExample { 258 | // This is an example of a performance test case. 259 | [self measureBlock:^{ 260 | // Put the code you want to measure the time of here. 261 | }]; 262 | } 263 | 264 | @end 265 | -------------------------------------------------------------------------------- /Example/Tests/HoloTableSectionRemoverTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableSectionRemoverTest.m 3 | // HoloTableView_Tests 4 | // 5 | // Created by 与佳期 on 2021/5/22. 6 | // Copyright © 2021 gonghonglou. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface HoloTableSectionRemoverTest : XCTestCase 13 | 14 | @property (nonatomic, strong) UITableView *tableView; 15 | 16 | @end 17 | 18 | @implementation HoloTableSectionRemoverTest 19 | 20 | - (void)setUp { 21 | // Put setup code here. This method is called before the invocation of each test method in the class. 22 | self.tableView = [UITableView new]; 23 | 24 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 25 | make.section(TAG); 26 | }]; 27 | } 28 | 29 | - (void)tearDown { 30 | // Put teardown code here. This method is called after the invocation of each test method in the class. 31 | } 32 | 33 | - (void)testRemoveSections { 34 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 35 | make.section(@"1"); 36 | make.section(@"2"); 37 | make.section(@"2"); 38 | make.section(@"3"); 39 | }]; 40 | 41 | XCTAssertEqual(self.tableView.holo_sections.count, 5); 42 | 43 | [self.tableView holo_removeSections:@[@"1", @"2"]]; 44 | 45 | XCTAssertEqual(self.tableView.holo_sections.count, 2); 46 | 47 | HoloTableSection *lastSection = self.tableView.holo_sections[1]; 48 | XCTAssertEqual(lastSection.tag, @"3"); 49 | 50 | [self.tableView holo_removeAllSections]; 51 | XCTAssertEqual(self.tableView.holo_sections.count, 0); 52 | } 53 | 54 | - (void)testPerformanceExample { 55 | // This is an example of a performance test case. 56 | [self measureBlock:^{ 57 | // Put the code you want to measure the time of here. 58 | }]; 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /Example/Tests/Tests-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 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // The contents of this file are implicitly included at the beginning of every test case source file. 2 | 3 | #ifdef __OBJC__ 4 | 5 | 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /Example/Tests/Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewTests.m 3 | // HoloTableViewTests 4 | // 5 | // Created by gonghonglou on 07/28/2019. 6 | // Copyright (c) 2019 gonghonglou. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | 11 | @interface Tests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Tests 16 | 17 | - (void)setUp 18 | { 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 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | 36 | -------------------------------------------------------------------------------- /Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /HoloTableView.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint HoloTableView.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'HoloTableView' 11 | s.version = '3.1.2' 12 | s.summary = 'Harness the power of UITableView with a simplified, chainable and expressive syntax.' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | s.description = 'HoloTableView is a light-weight extension for UITableView. Harness the power of UITableView with a simplified, chainable and expressive syntax.' 21 | 22 | s.homepage = 'https://github.com/HoloFoundation/HoloTableView' 23 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 24 | s.license = { :type => 'MIT', :file => 'LICENSE' } 25 | s.author = { 'gonghonglou' => 'gonghonglou@icloud.com' } 26 | s.source = { :git => 'https://github.com/HoloFoundation/HoloTableView.git', :tag => s.version.to_s } 27 | # s.social_media_url = 'https://twitter.com/' 28 | 29 | s.ios.deployment_target = '8.0' 30 | 31 | s.source_files = 'HoloTableView/Classes/**/*' 32 | 33 | # s.resource_bundles = { 34 | # 'HoloTableView' => ['HoloTableView/Assets/*.png'] 35 | # } 36 | 37 | # s.public_header_files = 'Pod/Classes/**/*.h' 38 | # s.frameworks = 'UIKit', 'MapKit' 39 | # s.dependency 'AFNetworking', '~> 2.3' 40 | end 41 | -------------------------------------------------------------------------------- /HoloTableView/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HoloFoundation/HoloTableView/35eb14a22954264f0243bfac3abd934b06db5c18/HoloTableView/Assets/.gitkeep -------------------------------------------------------------------------------- /HoloTableView/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HoloFoundation/HoloTableView/35eb14a22954264f0243bfac3abd934b06db5c18/HoloTableView/Classes/.gitkeep -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/HoloTableViewProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewProxy.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/7/27. 6 | // 7 | 8 | #import 9 | #import "HoloTableViewProtocol.h" 10 | @class HoloTableViewProxyData; 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface HoloTableViewProxy : NSObject 15 | 16 | /** 17 | * Proxy data. 18 | */ 19 | @property (nonatomic, strong) HoloTableViewProxyData *proxyData; 20 | 21 | /** 22 | * The delegate of the scroll-view object. 23 | */ 24 | @property (nonatomic, weak, nullable) id scrollDelegate; 25 | 26 | @property (nonatomic, weak, nullable) id dataSource; 27 | 28 | @property (nonatomic, weak, nullable) id delegate; 29 | 30 | @end 31 | 32 | NS_ASSUME_NONNULL_END 33 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/HoloTableViewProxyData.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewProxyData.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/7/29. 6 | // 7 | 8 | #import 9 | @class HoloTableSection; 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface HoloTableViewProxyData : NSObject 14 | 15 | /** 16 | * Datasource of current UITableView. 17 | */ 18 | @property (nonatomic, copy) NSArray *sections; 19 | 20 | /** 21 | * Return list of section titles to display in section index view (e.g. "ABCD...Z#"). 22 | */ 23 | @property (nonatomic, copy, nullable) NSArray *sectionIndexTitles; 24 | 25 | /** 26 | * Tell table which section corresponds to section title/index (e.g. "B",1)). 27 | */ 28 | @property (nonatomic, copy, nullable) NSInteger (^sectionForSectionIndexTitleHandler)(NSString *title, NSInteger index); 29 | 30 | 31 | //@property (nonatomic, copy) NSDictionary *rowsMap; 32 | // 33 | //@property (nonatomic, copy) NSDictionary *headersMap; 34 | // 35 | //@property (nonatomic, copy) NSDictionary *footersMap; 36 | 37 | @end 38 | 39 | NS_ASSUME_NONNULL_END 40 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/HoloTableViewProxyData.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewProxyData.m 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/7/29. 6 | // 7 | 8 | #import "HoloTableViewProxyData.h" 9 | 10 | @implementation HoloTableViewProxyData 11 | 12 | #pragma mark - getter 13 | - (NSArray *)sections { 14 | if (!_sections) { 15 | _sections = [NSArray new]; 16 | } 17 | return _sections; 18 | } 19 | 20 | //- (NSDictionary *)rowsMap { 21 | // if (!_rowsMap) { 22 | // _rowsMap = [NSDictionary new]; 23 | // } 24 | // return _rowsMap; 25 | //} 26 | // 27 | //- (NSDictionary *)headersMap { 28 | // if (!_headersMap) { 29 | // _headersMap = [NSDictionary new]; 30 | // } 31 | // return _headersMap; 32 | //} 33 | // 34 | //- (NSDictionary *)footersMap { 35 | // if (!_footersMap) { 36 | // _footersMap = [NSDictionary new]; 37 | // } 38 | // return _footersMap; 39 | //} 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/Protocol/HoloTableViewCellProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewCellProtocol.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2020/6/2. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @protocol HoloTableViewCellProtocol 13 | 14 | @required 15 | 16 | /** 17 | * Your cell must implement this method in order for the HoloTableView to pass the externally-set model. 18 | */ 19 | - (void)holo_configureCellWithModel:(id _Nullable)model; 20 | 21 | 22 | @optional 23 | 24 | /** 25 | * If your cell implements this method, the HolotableView will set the height of the current cell from the return value of this method. 26 | * 27 | * Note that if your cell implements this method, the `heightHandler` and `height` properties set externally will be invalidated. 28 | */ 29 | + (CGFloat)holo_heightForCellWithModel:(id _Nullable)model; 30 | 31 | /** 32 | * If your cell implements this method, the HolotableView will set the estimated height of the current cell from the return value of this method. 33 | * 34 | * Note that if your cell implements this method, the `estimatedHeightHandler` and `estimatedHeight` properties set externally will be invalidated. 35 | */ 36 | + (CGFloat)holo_estimatedHeightForCellWithModel:(id _Nullable)model; 37 | 38 | /** 39 | * If your cell implements this method, the HolotableView will set the should highlight or not of the current cell from the return value of this method. 40 | * 41 | * Note that if your cell implements this method, the `shouldHighlightHandler` and `shouldHighlight` properties set externally will be invalidated. 42 | */ 43 | - (BOOL)holo_shouldHighlightForCellWithModel:(id _Nullable)model; 44 | 45 | /** 46 | * If your cell implements this method, this method will be called when the cell will select. 47 | * 48 | * Note that if your cell implements this method, the `willSelectHandler` property set externally will be invalidated. 49 | */ 50 | - (void)holo_willSelectCellWithModel:(id _Nullable)model; 51 | 52 | /** 53 | * If your cell implements this method, this method will be called when the cell will deselect. 54 | * 55 | * Note that if your cell implements this method, the `willDeselectHandler` property set externally will be invalidated. 56 | */ 57 | - (void)holo_willDeselectCellWithModel:(id _Nullable)model; 58 | 59 | /** 60 | * If your cell implements this method, this method will be called when the cell did deselect. 61 | * 62 | * Note that if your cell implements this method, the `didDeselectHandler` property set externally will be invalidated. 63 | */ 64 | - (void)holo_didDeselectCellWithModel:(id _Nullable)model; 65 | 66 | /** 67 | * If your cell implements this method, this method will be called when the cell did select. 68 | * 69 | * Note that if your cell implements this method, the `didSelectHandler` property set externally will be invalidated. 70 | */ 71 | - (void)holo_didSelectCellWithModel:(id _Nullable)model; 72 | 73 | /** 74 | * If your cell implements this method, this method will be called when the cell will display. 75 | * 76 | * Note that if your cell implements this method, the `willDisplayHandler` property set externally will be invalidated. 77 | */ 78 | - (void)holo_willDisplayCellWithModel:(id _Nullable)model; 79 | 80 | /** 81 | * If your cell implements this method, this method will be called when the cell did end displaying. 82 | * 83 | * Note that if your cell implements this method, the `didEndDisplayingHandler` property set externally will be invalidated. 84 | */ 85 | - (void)holo_didEndDisplayingCellWithModel:(id _Nullable)model; 86 | 87 | /** 88 | * If your cell implements this method, this method will be called when the cell did highlight. 89 | * 90 | * Note that if your cell implements this method, the `didHighlightHandler` property set externally will be invalidated. 91 | */ 92 | - (void)holo_didHighlightCellWithModel:(id _Nullable)model; 93 | 94 | /** 95 | * If your cell implements this method, this method will be called when the cell did un highlight. 96 | * 97 | * Note that if your cell implements this method, the `didUnHighlightHandler` property set externally will be invalidated. 98 | */ 99 | - (void)holo_didUnHighlightCellWithModel:(id _Nullable)model; 100 | 101 | /** 102 | * If your cell implements this method, this method will be called when the cell accessory button tapped. 103 | * 104 | * Note that if your cell implements this method, the `accessoryButtonTappedHandler` property set externally will be invalidated. 105 | */ 106 | - (void)holo_accessoryButtonTappedCellWithModel:(id _Nullable)model; 107 | 108 | /** 109 | * If your cell implements this method, this method will be called when the cell will begin editing. 110 | * 111 | * Note that if your cell implements this method, the `willBeginEditingHandler` property set externally will be invalidated. 112 | */ 113 | - (void)holo_willBeginEditingCellWithModel:(id _Nullable)model; 114 | 115 | /** 116 | * If your cell implements this method, this method will be called when the cell did end editing. 117 | * 118 | * Note that if your cell implements this method, the `didEndEditingHandler` property set externally will be invalidated. 119 | */ 120 | - (void)holo_didEndEditingCellWithModel:(id _Nullable)model; 121 | 122 | @end 123 | 124 | NS_ASSUME_NONNULL_END 125 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/Protocol/HoloTableViewFooterProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewFooterProtocol.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2020/6/2. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @protocol HoloTableViewFooterProtocol 13 | 14 | @required 15 | 16 | /** 17 | * Your section footer must implement this method in order for the HoloTableView to pass the externally-set model to the current section footer. 18 | */ 19 | - (void)holo_configureFooterWithModel:(id _Nullable)model; 20 | 21 | 22 | @optional 23 | 24 | /** 25 | * If your section footer implements this method, the HolotableView will set the height of the current section footer from the return value of this method. 26 | * 27 | * Note that if your section footer implements this method, the `footerHeightHandler` and `footerHeight` properties set externally will be invalidated. 28 | */ 29 | + (CGFloat)holo_heightForFooterWithModel:(id _Nullable)model; 30 | 31 | /** 32 | * If your section footer implements this method, the HolotableView will set the estimated height of the current section footer from the return value of this method. 33 | * 34 | * Note that if your section footer implements this method, the `estimatedFooterHeightHandler` and `estimatedFooterHeight` properties set externally will be invalidated. 35 | */ 36 | + (CGFloat)holo_estimatedHeightForFooterWithModel:(id _Nullable)model; 37 | 38 | /** 39 | * If your section footer implements this method, this method will be called when the section footer will display. 40 | * 41 | * Note that if your section footer implements this method, the `willDisplayHandler` property set externally will be invalidated. 42 | */ 43 | - (void)holo_willDisplayFooterWithModel:(id _Nullable)model; 44 | 45 | /** 46 | * If your section footer implements this method, this method will be called when the section footer did end displaying. 47 | * 48 | * Note that if your section footer implements this method, the `didEndDisplayingHandler` property set externally will be invalidated. 49 | */ 50 | - (void)holo_didEndDisplayingFooterWithModel:(id _Nullable)model; 51 | 52 | @end 53 | 54 | NS_ASSUME_NONNULL_END 55 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/Protocol/HoloTableViewHeaderProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewHeaderProtocol.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2020/6/2. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @protocol HoloTableViewHeaderProtocol 13 | 14 | @required 15 | 16 | /** 17 | * Your section header must implement this method in order for the HoloTableView to pass the externally-set model to the current section header. 18 | */ 19 | - (void)holo_configureHeaderWithModel:(id _Nullable)model; 20 | 21 | 22 | @optional 23 | 24 | /** 25 | * If your section header implements this method, the HolotableView will set the height of the current section header from the return value of this method. 26 | * 27 | * Note that if your section header implements this method, the `headerHeightHandler` and `headerHeight` properties set externally will be invalidated. 28 | */ 29 | + (CGFloat)holo_heightForHeaderWithModel:(id _Nullable)model; 30 | 31 | /** 32 | * If your section header implements this method, the HolotableView will set the estimated height of the current section header from the return value of this method. 33 | * 34 | * Note that if your section header implements this method, the `estimatedHeaderHeightHandler` and `estimatedHeaderHeight` properties set externally will be invalidated. 35 | */ 36 | + (CGFloat)holo_estimatedHeightForHeaderWithModel:(id _Nullable)model; 37 | 38 | /** 39 | * If your section header implements this method, this method will be called when the section header will display. 40 | * 41 | * Note that if your section header implements this method, the `willDisplayHandler` property set externally will be invalidated. 42 | */ 43 | - (void)holo_willDisplayHeaderWithModel:(id _Nullable)model; 44 | 45 | /** 46 | * If your section header implements this method, this method will be called when the section header did end displaying. 47 | * 48 | * Note that if your section header implements this method, the `didEndDisplayingHandler` property set externally will be invalidated. 49 | */ 50 | - (void)holo_didEndDisplayingHeaderWithModel:(id _Nullable)model; 51 | 52 | @end 53 | 54 | NS_ASSUME_NONNULL_END 55 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/Protocol/HoloTableViewProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewProtocol.h 3 | // Pods 4 | // 5 | // Created by 与佳期 on 2019/7/28. 6 | // 7 | 8 | #ifndef HoloTableViewProtocol_h 9 | #define HoloTableViewProtocol_h 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @protocol HoloTableViewDelegate 14 | 15 | @end 16 | 17 | 18 | @protocol HoloTableViewDataSource 19 | 20 | @optional 21 | 22 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; 23 | 24 | // Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier: 25 | // Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls) 26 | 27 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; 28 | 29 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; // Default is 1 if not implemented 30 | 31 | - (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; // fixed font style. use custom view (UILabel) if you want something different 32 | - (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section; 33 | 34 | // Editing 35 | 36 | // Individual rows can opt out of having the -editing property set for them. If not implemented, all rows are assumed to be editable. 37 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath; 38 | 39 | // Moving/reordering 40 | 41 | // Allows the reorder accessory view to optionally be shown for a particular row. By default, the reorder control will be shown only if the datasource implements -tableView:moveRowAtIndexPath:toIndexPath: 42 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath; 43 | 44 | // Index 45 | 46 | - (nullable NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView; // return list of section titles to display in section index view (e.g. "ABCD...Z#") 47 | - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index; // tell table which section corresponds to section title/index (e.g. "B",1)) 48 | 49 | // Data manipulation - insert and delete support 50 | 51 | // After a row has the minus or plus button invoked (based on the UITableViewCellEditingStyle for the cell), the dataSource must commit the change 52 | // Not called for edit actions using UITableViewRowAction - the action's handler will be invoked instead 53 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath; 54 | 55 | // Data manipulation - reorder / moving support 56 | 57 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath; 58 | 59 | @end 60 | 61 | NS_ASSUME_NONNULL_END 62 | 63 | #endif /* HoloTableViewProtocol_h */ 64 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/Row/HoloTableRow.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableRow.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2020/6/1. 6 | // 7 | 8 | #import 9 | @class HoloTableViewRowSwipeAction; 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface HoloTableRow : NSObject 14 | 15 | /** 16 | * Cell class. 17 | */ 18 | @property (nonatomic, assign) Class cell; 19 | 20 | /** 21 | * Set the data for the cell using the `model` property. 22 | * 23 | * If the `modelHandler` property is nil, then use the `model` property. 24 | */ 25 | @property (nonatomic, strong, nullable) id model; 26 | @property (nonatomic, copy, nullable) id (^modelHandler)(void); 27 | 28 | /** 29 | * The cell must implement the `configSEL` property setting method in order for the HoloTableView to pass the model for the cell. 30 | */ 31 | @property (nonatomic, assign) SEL configSEL; 32 | 33 | /** 34 | * Performed before `configSEL`. 35 | */ 36 | @property (nonatomic, copy, nullable) void (^beforeConfigureHandler)(UITableViewCell *cell, id _Nullable model); 37 | 38 | /** 39 | * Performed after `configSEL`. 40 | */ 41 | @property (nonatomic, copy, nullable) void (^afterConfigureHandler)(UITableViewCell *cell, id _Nullable model); 42 | 43 | 44 | /** 45 | * Set the style for the cell using the `style` property. 46 | * 47 | * If the `styleHandler` property is nil, then use the `style` property. 48 | */ 49 | @property (nonatomic, assign) UITableViewCellStyle style; 50 | @property (nonatomic, copy, nullable) UITableViewCellStyle (^styleHandler)(id _Nullable model); 51 | 52 | /** 53 | * Set the reuse identifier for the cell using the `reuseId` property. 54 | * 55 | * If the `reuseIdHandler` property is nil, then use the `reuseId` property. 56 | */ 57 | @property (nonatomic, copy, nullable) NSString *reuseId; 58 | @property (nonatomic, copy, nullable) NSString *(^reuseIdHandler)(id _Nullable model); 59 | 60 | /** 61 | * Set the tag for the cell using the `tag` property. 62 | */ 63 | @property (nonatomic, copy, nullable) NSString *tag; 64 | 65 | /** 66 | * Set the height for the cell using the `height` property. 67 | * 68 | * If the `heightSEL` property is nil or the cell don't implement the `heightSEL` property setting method, then use the `heightHandler` property. 69 | * If the `heightHandler` property is nil, then use the `height` property. 70 | */ 71 | @property (nonatomic, assign) CGFloat height; 72 | @property (nonatomic, copy, nullable) CGFloat (^heightHandler)(id _Nullable model); 73 | @property (nonatomic, assign) SEL heightSEL; 74 | 75 | /** 76 | * Set the estimated height for the cell using the `estimatedHeight` property. 77 | * 78 | * If the `estimatedHeightSEL` property is nil or the cell don't implement the `estimatedHeightSEL` property setting method, then use the `estimatedHeightHandler` property. 79 | * If the `estimatedHeightHandler` property is nil, then use the `estimatedHeight` property. 80 | */ 81 | @property (nonatomic, assign) CGFloat estimatedHeight; 82 | @property (nonatomic, copy, nullable) CGFloat (^estimatedHeightHandler)(id _Nullable model); 83 | @property (nonatomic, assign) SEL estimatedHeightSEL; 84 | 85 | /** 86 | * Set the should highlight or not for the cell using the `shouldHighlight` property. 87 | * 88 | * If the `shouldHighlightSEL` property is nil or the cell don't implement the `shouldHighlightSEL` property setting method, then use the `shouldHighlightHandler` property. 89 | * If the `shouldHighlightHandler` property is nil, then use the `shouldHighlight` property. 90 | */ 91 | @property (nonatomic, assign) BOOL shouldHighlight; 92 | @property (nonatomic, copy, nullable) BOOL (^shouldHighlightHandler)(id _Nullable model); 93 | @property (nonatomic, assign) SEL shouldHighlightSEL; 94 | 95 | /** 96 | * Set the can edit or not for the cell using the `canEdit` property. 97 | * 98 | * If the `canEditHandler` property is nil, then use the `canEdit` property. 99 | */ 100 | @property (nonatomic, assign) BOOL canEdit; 101 | @property (nonatomic, copy, nullable) BOOL (^canEditHandler)(id _Nullable model); 102 | //@property (nonatomic, assign) SEL canEditSEL; 103 | 104 | /** 105 | * Set the can move or not for the cell using the `canMove` property. 106 | * 107 | * If the `canMoveHandler` property is nil, then use the `canEdit` property. 108 | */ 109 | @property (nonatomic, assign) BOOL canMove; 110 | @property (nonatomic, copy, nullable) BOOL (^canMoveHandler)(id _Nullable model); 111 | //@property (nonatomic, assign) SEL canMoveSEL; 112 | 113 | /** 114 | * Set the leading swipe actions for the cell using the `leadingSwipeActions` property. 115 | * 116 | * If the `leadingSwipeActionsHandler` property is nil, then use the `leadingSwipeActions` property. 117 | */ 118 | @property (nonatomic, copy, nullable) NSArray *leadingSwipeActions API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos); 119 | @property (nonatomic, copy, nullable) NSArray *(^leadingSwipeActionsHandler)(id _Nullable model) API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos); 120 | //@property (nonatomic, assign) SEL leadingSwipeActionsSEL; 121 | 122 | /** 123 | * Set the leading swipe for the cell using the `leadingSwipeHandler` property. 124 | */ 125 | @property (nonatomic, copy, nullable) void (^leadingSwipeHandler)(id action, NSInteger index, void(^completionHandler)(BOOL actionPerformed)) API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos); 126 | //@property (nonatomic, assign) SEL leadingSwipeSEL API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos); 127 | 128 | /** 129 | * Set the trailing swipe actions for the cell using the `trailingSwipeActions` property. 130 | * 131 | * If the `trailingSwipeActionsHandler` property is nil, then use the `trailingSwipeActions` property. 132 | */ 133 | @property (nonatomic, copy, nullable) NSArray *trailingSwipeActions; 134 | @property (nonatomic, copy, nullable) NSArray *(^trailingSwipeActionsHandler)(id _Nullable model); 135 | //@property (nonatomic, assign) SEL trailingSwipeActionsSEL; 136 | 137 | /** 138 | * Set the trailing swipe for the cell using the `trailingSwipeHandler` property. 139 | */ 140 | @property (nonatomic, copy, nullable) void (^trailingSwipeHandler)(id action, NSInteger index, void(^completionHandler)(BOOL actionPerformed)); 141 | //@property (nonatomic, assign) SEL trailingSwipeSEL; 142 | 143 | /** 144 | * Set the editing delete title for the cell using the `editingDeleteTitle` property. 145 | * 146 | * If the `editingDeleteTitleHandler` property is nil, then use the `editingDeleteTitle` property. 147 | */ 148 | @property (nonatomic, copy, nullable) NSString *editingDeleteTitle; 149 | @property (nonatomic, copy, nullable) NSString *(^editingDeleteTitleHandler)(id _Nullable model); 150 | //@property (nonatomic, assign) SEL editingDeleteTitleSEL; 151 | 152 | /** 153 | * Set the editing style for the cell using the `editingStyle` property. 154 | * 155 | * If the `editingStyleHandler` property is nil, then use the `editingStyle` property. 156 | */ 157 | @property (nonatomic, assign) UITableViewCellEditingStyle editingStyle; 158 | @property (nonatomic, copy, nullable) UITableViewCellEditingStyle(^editingStyleHandler)(id _Nullable model); 159 | //@property (nonatomic, assign) SEL editingStyleSEL; 160 | 161 | /** 162 | * If the cell will select, the `willSelectHandler` will be called. 163 | * 164 | * If the `willSelectSEL` property is nil or the cell don't implement the `willSelectSEL` property setting method, then use the `willSelectHandler` property. 165 | */ 166 | @property (nonatomic, copy, nullable) void (^willSelectHandler)(id _Nullable model); 167 | @property (nonatomic, assign) SEL willSelectSEL; 168 | 169 | /** 170 | * If the cell will deselect, the `willDeselectHandler` will be called. 171 | * 172 | * If the `willDeselectSEL` property is nil or the cell don't implement the `willDeselectSEL` property setting method, then use the `willDeselectHandler` property. 173 | */ 174 | @property (nonatomic, copy, nullable) void (^willDeselectHandler)(id _Nullable model); 175 | @property (nonatomic, assign) SEL willDeselectSEL; 176 | 177 | /** 178 | * If the cell did select, the `didSelectHandler` will be called. 179 | * 180 | * If the `didSelectSEL` property is nil or the cell don't implement the `didSelectSEL` property setting method, then use the `didSelectHandler` property. 181 | */ 182 | @property (nonatomic, copy, nullable) void (^didSelectHandler)(id _Nullable model); 183 | @property (nonatomic, assign) SEL didSelectSEL; 184 | 185 | /** 186 | * If the cell did deselect, the `didDeselectHandler` will be called. 187 | * 188 | * If the `didDeselectSEL` property is nil or the cell don't implement the `didDeselectSEL` property setting method, then use the `didDeselectHandler` property. 189 | */ 190 | @property (nonatomic, copy, nullable) void (^didDeselectHandler)(id _Nullable model); 191 | @property (nonatomic, assign) SEL didDeselectSEL; 192 | 193 | /** 194 | * If the cell will display, the `willDisplayHandler` will be called. 195 | * 196 | * If the `willDisplaySEL` property is nil or the cell don't implement the `willDisplaySEL` property setting method, then use the `willDisplayHandler` property. 197 | */ 198 | @property (nonatomic, copy, nullable) void (^willDisplayHandler)(UITableViewCell *cell, id _Nullable model); 199 | @property (nonatomic, assign) SEL willDisplaySEL; 200 | 201 | /** 202 | * If the cell did end displaying, the `didEndDisplayingHandler` will be called. 203 | * 204 | * If the `didEndDisplayingSEL` property is nil or the cell don't implement the `didEndDisplayingSEL` property setting method, then use the `didEndDisplayingHandler` property. 205 | */ 206 | @property (nonatomic, copy, nullable) void (^didEndDisplayingHandler)(UITableViewCell *cell, id _Nullable model); 207 | @property (nonatomic, assign) SEL didEndDisplayingSEL; 208 | 209 | /** 210 | * If the cell did highlight, the `didHighlightHandler` will be called. 211 | * 212 | * If the `didHighlightSEL` property is nil or the cell don't implement the `didHighlightSEL` property setting method, then use the `didHighlightHandler` property. 213 | */ 214 | @property (nonatomic, copy, nullable) void (^didHighlightHandler)(id _Nullable model); 215 | @property (nonatomic, assign) SEL didHighlightSEL; 216 | 217 | /** 218 | * If the cell did unhighlight, the `didUnHighlightHandler` will be called. 219 | * 220 | * If the `didUnHighlightSEL` property is nil or the cell don't implement the `didUnHighlightSEL` property setting method, then use the `didUnHighlightHandler` property. 221 | */ 222 | @property (nonatomic, copy, nullable) void (^didUnHighlightHandler)(id _Nullable model); 223 | @property (nonatomic, assign) SEL didUnHighlightSEL; 224 | 225 | /** 226 | * If the cell accessory button tapped, the `accessoryButtonTappedHandler` will be called. 227 | * 228 | * If the `accessoryButtonTappedSEL` property is nil or the cell don't implement the `accessoryButtonTappedSEL` property setting method, then use the `accessoryButtonTappedHandler` property. 229 | */ 230 | @property (nonatomic, copy, nullable) void (^accessoryButtonTappedHandler)(id _Nullable model); 231 | @property (nonatomic, assign) SEL accessoryButtonTappedSEL; 232 | 233 | /** 234 | * If the cell will begin editing, the `willBeginEditingHandler` will be called. 235 | * 236 | * If the `willBeginEditingSEL` property is nil or the cell don't implement the `willBeginEditingSEL` property setting method, then use the `willBeginEditingHandler` property. 237 | */ 238 | @property (nonatomic, copy, nullable) void (^willBeginEditingHandler)(id _Nullable model); 239 | @property (nonatomic, assign) SEL willBeginEditingSEL; 240 | 241 | /** 242 | * If the cell did end editing, the `didEndEditingHandler` will be called. 243 | * 244 | * If the `didEndEditingSEL` property is nil or the cell don't implement the `didEndEditingSEL` property setting method, then use the `didEndEditingHandler` property. 245 | */ 246 | @property (nonatomic, copy, nullable) void (^didEndEditingHandler)(id _Nullable model); 247 | @property (nonatomic, assign) SEL didEndEditingSEL; 248 | 249 | /** 250 | * Set the target move index for the cell using the `targetMoveHandler` property. 251 | */ 252 | @property (nonatomic, copy, nullable) NSIndexPath *(^targetMoveHandler)(NSIndexPath *atIndexPath, NSIndexPath *toIndexPath); 253 | //@property (nonatomic, assign) SEL targetMoveSEL; 254 | 255 | /** 256 | * If the cell is moved, the `moveHandler` will be called. 257 | */ 258 | @property (nonatomic, copy, nullable) void (^moveHandler)(NSIndexPath *atIndexPath, NSIndexPath *toIndexPath, void(^completionHandler)(BOOL actionPerformed)); 259 | //@property (nonatomic, assign) SEL moveSEL; 260 | 261 | /** 262 | * If the cell is editing delete, the `editingDeleteHandler` will be called. 263 | */ 264 | @property (nonatomic, copy, nullable) void (^editingDeleteHandler)(id _Nullable model, void(^completionHandler)(BOOL actionPerformed)); 265 | //@property (nonatomic, assign) SEL editingDeleteSEL; 266 | 267 | /** 268 | * If the cell is editing Insert, the `editingInsertHandler` will be called. 269 | */ 270 | @property (nonatomic, copy, nullable) void (^editingInsertHandler)(id _Nullable model); 271 | //@property (nonatomic, assign) SEL editingInsertSEL; 272 | 273 | 274 | /** 275 | * Set the delegate for the cell using the `delegate` property. 276 | * 277 | * If the `delegateSEL` property is nil or the cell don't implement the `delegateSEL` property setting method, then use the `delegate` property. 278 | */ 279 | @property (nonatomic, weak, nullable) id delegate; 280 | @property (nonatomic, assign) SEL delegateSEL; 281 | 282 | @end 283 | 284 | NS_ASSUME_NONNULL_END 285 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/Row/HoloTableRow.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableRow.m 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2020/6/1. 6 | // 7 | 8 | #import "HoloTableRow.h" 9 | 10 | @implementation HoloTableRow 11 | 12 | - (instancetype)init { 13 | self = [super init]; 14 | if (self) { 15 | _cell = UITableViewCell.class; 16 | _height = CGFLOAT_MIN; 17 | _estimatedHeight = CGFLOAT_MIN; 18 | _shouldHighlight = YES; 19 | _style = UITableViewCellStyleDefault; 20 | _canEdit = NO; 21 | _canMove = NO; 22 | _editingStyle = UITableViewCellEditingStyleNone; 23 | #pragma clang diagnostic push 24 | #pragma clang diagnostic ignored "-Wundeclared-selector" 25 | _configSEL = @selector(holo_configureCellWithModel:); 26 | _heightSEL = @selector(holo_heightForCellWithModel:); 27 | _estimatedHeightSEL = @selector(holo_estimatedHeightForCellWithModel:); 28 | _shouldHighlightSEL = @selector(holo_shouldHighlightForCellWithModel:); 29 | _willSelectSEL = @selector(holo_willSelectCellWithModel:); 30 | _willDeselectSEL = @selector(holo_willDeselectCellWithModel:); 31 | _didDeselectSEL = @selector(holo_didDeselectCellWithModel:); 32 | _didSelectSEL = @selector(holo_didSelectCellWithModel:); 33 | _willDisplaySEL = @selector(holo_willDisplayCellWithModel:); 34 | _didEndDisplayingSEL = @selector(holo_didEndDisplayingCellWithModel:); 35 | _didHighlightSEL = @selector(holo_didHighlightCellWithModel:); 36 | _didUnHighlightSEL = @selector(holo_didUnHighlightCellWithModel:); 37 | _accessoryButtonTappedSEL = @selector(holo_accessoryButtonTappedCellWithModel:); 38 | _willBeginEditingSEL = @selector(holo_willBeginEditingCellWithModel:); 39 | _didEndEditingSEL = @selector(holo_didEndEditingCellWithModel:); 40 | 41 | // support set a delegate for cell 42 | _delegateSEL = @selector(holo_configureCellDelegate:); 43 | #pragma clang diagnostic pop 44 | } 45 | 46 | return self; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/Section/HoloTableSection.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableSection.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2020/6/2. 6 | // 7 | 8 | #import 9 | @class HoloTableRow; 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface HoloTableSection : NSObject 14 | 15 | /** 16 | * Set the rows for the section using the `rows` property. 17 | */ 18 | @property (nonatomic, copy) NSArray *rows; 19 | 20 | /** 21 | * Set the tag for the section using the `tag` property. 22 | */ 23 | @property (nonatomic, copy, nullable) NSString *tag; 24 | 25 | /** 26 | * Header class. 27 | */ 28 | @property (nonatomic, assign) Class header; 29 | 30 | /** 31 | * Footer class. 32 | */ 33 | @property (nonatomic, assign) Class footer; 34 | 35 | /** 36 | * Set the header title for the section using the `headerTitle` property. 37 | * 38 | * If you set 'header', the `headerTitleHandler` property and `headerTitle` property will be invalid. 39 | * 40 | * If the `headerTitleHandler` property is nil, then use the `headerTitle` property. 41 | */ 42 | @property (nonatomic, copy, nullable) NSString *headerTitle; 43 | @property (nonatomic, copy, nullable) NSString *(^headerTitleHandler)(void); 44 | 45 | /** 46 | * Set the footer title for the section using the `footerTitle` property. 47 | * 48 | * If you set 'footer', the `footerTitleHandler` property and `footerTitle` property will be invalid. 49 | * 50 | * If the `footerTitleHandler` property is nil, then use the `footerTitle` property. 51 | */ 52 | @property (nonatomic, copy, nullable) NSString *footerTitle; 53 | @property (nonatomic, copy, nullable) NSString *(^footerTitleHandler)(void); 54 | 55 | /** 56 | * Set the data for the header using the `headerModel` property. 57 | * 58 | * If the `headerModelHandler` property is nil, then use the `headerModel` property. 59 | */ 60 | @property (nonatomic, strong, nullable) id headerModel; 61 | @property (nonatomic, copy, nullable) id (^headerModelHandler)(void); 62 | 63 | /** 64 | * Set the data for the footer using the `footerModel` property. 65 | * 66 | * If the `footerModelHandler` property is nil, then use the `footerModel` property. 67 | */ 68 | @property (nonatomic, strong, nullable) id footerModel; 69 | @property (nonatomic, copy, nullable) id (^footerModelHandler)(void); 70 | 71 | /** 72 | * The header must implement the `headerConfigSEL` property setting method in order for the HoloTableView to pass the model for the header. 73 | */ 74 | @property (nonatomic, assign) SEL headerConfigSEL; 75 | 76 | /** 77 | * The footer must implement the `footerConfigSEL` property setting method in order for the HoloTableView to pass the model for the footer. 78 | */ 79 | @property (nonatomic, assign) SEL footerConfigSEL; 80 | 81 | /** 82 | * Set the reuse identifier for the header using the `headerReuseId` property. 83 | * 84 | * If the `headerReuseIdHandler` property is nil, then use the `headerReuseId` property. 85 | */ 86 | @property (nonatomic, copy, nullable) NSString *headerReuseId; 87 | @property (nonatomic, copy, nullable) NSString *(^headerReuseIdHandler)(id _Nullable model); 88 | 89 | /** 90 | * Set the reuse identifier for the footer using the `footerReuseId` property. 91 | * 92 | * If the `footerReuseIdHandler` property is nil, then use the `footerReuseId` property. 93 | */ 94 | @property (nonatomic, copy, nullable) NSString *footerReuseId; 95 | @property (nonatomic, copy, nullable) NSString *(^footerReuseIdHandler)(id _Nullable model); 96 | 97 | /** 98 | * Set the height for the header using the `headerHeight` property. 99 | * 100 | * If the `headerHeightSEL` property is nil or the header don't implement the `headerHeightSEL` property setting method, then use the `headerHeightHandler` property. 101 | * If the `headerHeightHandler` property is nil, then use the `headerHeight` property. 102 | */ 103 | @property (nonatomic, assign) CGFloat headerHeight; 104 | @property (nonatomic, copy, nullable) CGFloat (^headerHeightHandler)(id _Nullable model); 105 | @property (nonatomic, assign) SEL headerHeightSEL; 106 | 107 | /** 108 | * Set the height for the footer using the `footerHeight` property. 109 | * 110 | * If the `footerHeightSEL` property is nil or the footer don't implement the `footerHeightSEL` property setting method, then use the `footerHeightHandler` property. 111 | * If the `footerHeightHandler` property is nil, then use the `footerHeight` property. 112 | */ 113 | @property (nonatomic, assign) CGFloat footerHeight; 114 | @property (nonatomic, copy, nullable) CGFloat (^footerHeightHandler)(id _Nullable model); 115 | @property (nonatomic, assign) SEL footerHeightSEL; 116 | 117 | /** 118 | * Set the estimated height for the header using the `headerEstimatedHeight` property. 119 | * 120 | * If the `headerEstimatedHeightSEL` property is nil or the header don't implement the `headerEstimatedHeightSEL` property setting method, then use the `headerEstimatedHeightHandler` property. 121 | * If the `headerEstimatedHeightHandler` property is nil, then use the `headerEstimatedHeight` property. 122 | */ 123 | @property (nonatomic, assign) CGFloat headerEstimatedHeight; 124 | @property (nonatomic, copy, nullable) CGFloat (^headerEstimatedHeightHandler)(id _Nullable model); 125 | @property (nonatomic, assign) SEL headerEstimatedHeightSEL; 126 | 127 | /** 128 | * Set the estimated height for the footer using the `footerEstimatedHeight` property. 129 | * 130 | * If the `footerEstimatedHeightSEL` property is nil or the footer don't implement the `footerEstimatedHeightSEL` property setting method, then use the `footerEstimatedHeightHandler` property. 131 | * If the `footerEstimatedHeightHandler` property is nil, then use the `footerEstimatedHeight` property. 132 | */ 133 | @property (nonatomic, assign) CGFloat footerEstimatedHeight; 134 | @property (nonatomic, copy, nullable) CGFloat (^footerEstimatedHeightHandler)(id _Nullable model); 135 | @property (nonatomic, assign) SEL footerEstimatedHeightSEL; 136 | 137 | /** 138 | * If the header will display, the `willDisplayHeaderHandler` will be called. 139 | * 140 | * If the `willDisplayHeaderSEL` property is nil or the header don't implement the `willDisplayHeaderSEL` property setting method, then use the `willDisplayHeaderHandler` property. 141 | */ 142 | @property (nonatomic, copy, nullable) void (^willDisplayHeaderHandler)(UIView *header, id _Nullable model); 143 | @property (nonatomic, assign) SEL willDisplayHeaderSEL; 144 | 145 | /** 146 | * If the footer will display, the `willDisplayFooterSEL` will be called. 147 | * 148 | * If the `willDisplayFooterSEL` property is nil or the footer don't implement the `willDisplayFooterSEL` property setting method, then use the `willDisplayFooterHandler` property. 149 | */ 150 | @property (nonatomic, copy, nullable) void (^willDisplayFooterHandler)(UIView *footer, id _Nullable model); 151 | @property (nonatomic, assign) SEL willDisplayFooterSEL; 152 | 153 | /** 154 | * If the header did end displaying, the `didEndDisplayingHeaderHandler` will be called. 155 | * 156 | * If the `didEndDisplayingHeaderSEL` property is nil or the header don't implement the `didEndDisplayingHeaderSEL` property setting method, then use the `didEndDisplayingHeaderHandler` property. 157 | */ 158 | @property (nonatomic, copy, nullable) void (^didEndDisplayingHeaderHandler)(UIView *header, id _Nullable model); 159 | @property (nonatomic, assign) SEL didEndDisplayingHeaderSEL; 160 | 161 | /** 162 | * If the footer did end displaying, the `didEndDisplayingFooterHandler` will be called. 163 | * 164 | * If the `didEndDisplayingFooterSEL` property is nil or the footer don't implement the `didEndDisplayingFooterSEL` property setting method, then use the `didEndDisplayingFooterHandler` property. 165 | */ 166 | @property (nonatomic, copy, nullable) void (^didEndDisplayingFooterHandler)(UIView *footer, id _Nullable model); 167 | @property (nonatomic, assign) SEL didEndDisplayingFooterSEL; 168 | 169 | 170 | /** 171 | * Add a row to current section. 172 | */ 173 | - (void)addRow:(HoloTableRow *)row; 174 | 175 | /** 176 | * remove a row from current section. 177 | */ 178 | - (void)removeRow:(HoloTableRow *)row; 179 | 180 | /** 181 | * Remove all rows of current section. 182 | */ 183 | - (void)removeAllRows; 184 | 185 | /** 186 | * Insert a row to current section somewhere. 187 | */ 188 | - (void)insertRow:(HoloTableRow *)row atIndex:(NSInteger)index; 189 | 190 | @end 191 | 192 | 193 | NS_ASSUME_NONNULL_END 194 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/Section/HoloTableSection.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableSection.m 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2020/6/2. 6 | // 7 | 8 | #import "HoloTableSection.h" 9 | 10 | @implementation HoloTableSection 11 | 12 | - (instancetype)init { 13 | self = [super init]; 14 | if (self) { 15 | _rows = [NSArray new]; 16 | _header = UITableViewHeaderFooterView.class; 17 | _footer = UITableViewHeaderFooterView.class; 18 | _headerHeight = CGFLOAT_MIN; 19 | _footerHeight = CGFLOAT_MIN; 20 | _headerEstimatedHeight = CGFLOAT_MIN; 21 | _footerEstimatedHeight = CGFLOAT_MIN; 22 | #pragma clang diagnostic push 23 | #pragma clang diagnostic ignored "-Wundeclared-selector" 24 | _headerConfigSEL = @selector(holo_configureHeaderWithModel:); 25 | _footerConfigSEL = @selector(holo_configureFooterWithModel:); 26 | _headerHeightSEL = @selector(holo_heightForHeaderWithModel:); 27 | _footerHeightSEL = @selector(holo_heightForFooterWithModel:); 28 | _headerEstimatedHeightSEL = @selector(holo_estimatedHeightForHeaderWithModel:); 29 | _footerEstimatedHeightSEL = @selector(holo_estimatedHeightForFooterWithModel:); 30 | 31 | _willDisplayHeaderSEL = @selector(holo_willDisplayHeaderWithModel:); 32 | _willDisplayFooterSEL = @selector(holo_willDisplayFooterWithModel:); 33 | _didEndDisplayingHeaderSEL = @selector(holo_didEndDisplayingHeaderWithModel:); 34 | _didEndDisplayingFooterSEL = @selector(holo_didEndDisplayingFooterWithModel:); 35 | #pragma clang diagnostic pop 36 | } 37 | return self; 38 | } 39 | 40 | 41 | - (void)addRow:(HoloTableRow *)row { 42 | if (!row) return; 43 | 44 | NSMutableArray *array = [NSMutableArray arrayWithArray:self.rows]; 45 | [array addObject:row]; 46 | self.rows = array.copy; 47 | } 48 | 49 | - (void)removeRow:(HoloTableRow *)row { 50 | if (!row) return; 51 | 52 | NSMutableArray *array = [NSMutableArray arrayWithArray:self.rows]; 53 | [array removeObject:row]; 54 | self.rows = array.copy; 55 | } 56 | 57 | - (void)removeAllRows { 58 | self.rows = [NSArray new]; 59 | } 60 | 61 | - (void)insertRow:(HoloTableRow *)row atIndex:(NSInteger)index { 62 | if (!row) return; 63 | 64 | if (index < 0) index = 0; 65 | if (index > self.rows.count) index = self.rows.count; 66 | 67 | NSMutableArray *array = [NSMutableArray arrayWithArray:self.rows]; 68 | [array insertObject:row atIndex:index]; 69 | self.rows = array.copy; 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/SwipeAction/HoloTableViewRowSwipeAction.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewRowSwipeAction.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/8/5. 6 | // 7 | 8 | #import 9 | @class HoloTableViewRowSwipeAction; 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef void (^HoloTableViewRowSwipeActionHandler)(id action, NSInteger index, void(^completionHandler)(BOOL actionPerformed)); 14 | 15 | typedef NS_ENUM(NSInteger, HoloTableViewRowSwipeActionStyle) { 16 | HoloTableViewRowSwipeActionStyleNormal, 17 | HoloTableViewRowSwipeActionStyleDestructive 18 | }; 19 | 20 | @interface HoloTableViewRowSwipeAction : NSObject 21 | 22 | + (instancetype)rowSwipeActionWithStyle:(HoloTableViewRowSwipeActionStyle)style title:(nullable NSString *)title; 23 | 24 | + (instancetype)rowSwipeActionWithStyle:(HoloTableViewRowSwipeActionStyle)style title:(nullable NSString *)title handler:(HoloTableViewRowSwipeActionHandler)handler; 25 | 26 | @property (nonatomic, copy, nullable) NSString *title;; 27 | 28 | @property (nonatomic, assign) HoloTableViewRowSwipeActionStyle style; 29 | 30 | @property (nonatomic, copy, nullable) UIColor *backgroundColor; 31 | 32 | @property (nonatomic, copy, nullable) UIVisualEffect *backgroundEffect NS_DEPRECATED_IOS(8_0, 10_0); 33 | 34 | @property (nonatomic, copy, nullable) UIImage *image API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos); 35 | 36 | @property (nonatomic, copy, nullable) HoloTableViewRowSwipeActionHandler handler; 37 | 38 | @end 39 | 40 | NS_ASSUME_NONNULL_END 41 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/SwipeAction/HoloTableViewRowSwipeAction.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewRowSwipeAction.m 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/8/5. 6 | // 7 | 8 | #import "HoloTableViewRowSwipeAction.h" 9 | 10 | @implementation HoloTableViewRowSwipeAction 11 | 12 | + (instancetype)rowSwipeActionWithStyle:(HoloTableViewRowSwipeActionStyle)style title:(nullable NSString *)title { 13 | HoloTableViewRowSwipeAction *action = [HoloTableViewRowSwipeAction new]; 14 | action.style = style; 15 | action.title = title; 16 | return action; 17 | } 18 | 19 | + (instancetype)rowSwipeActionWithStyle:(HoloTableViewRowSwipeActionStyle)style title:(NSString *)title handler:(HoloTableViewRowSwipeActionHandler)handler { 20 | HoloTableViewRowSwipeAction *action = [HoloTableViewRowSwipeAction new]; 21 | action.style = style; 22 | action.title = title; 23 | action.handler = handler; 24 | return action; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/UITableView+HoloTableViewProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView+HoloTableViewProxy.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/7/27. 6 | // 7 | 8 | #import 9 | @class HoloTableSection, HoloTableViewProxy; 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface UITableView (HoloTableViewProxy) 14 | 15 | /** 16 | * Datasource of current UITableView. 17 | */ 18 | @property (nonatomic, copy) NSArray *holo_sections; 19 | 20 | /** 21 | * Return list of section titles to display in section index view (e.g. "ABCD...Z#"). 22 | */ 23 | @property (nonatomic, copy, nullable) NSArray *holo_sectionIndexTitles; 24 | 25 | /** 26 | * Tell table which section corresponds to section title/index (e.g. "B",1)). 27 | */ 28 | @property (nonatomic, copy, nullable) NSInteger (^holo_sectionForSectionIndexTitleHandler)(NSString *title, NSInteger index); 29 | 30 | /** 31 | * The delegate of the scroll-view object. 32 | */ 33 | @property (nonatomic, weak, nullable) id holo_scrollDelegate; 34 | 35 | /** 36 | * Proxy of current UITableView. 37 | */ 38 | @property (nonatomic, strong, readonly) HoloTableViewProxy *holo_proxy; 39 | 40 | @end 41 | 42 | NS_ASSUME_NONNULL_END 43 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Core/UITableView+HoloTableViewProxy.m: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView+HoloTableViewProxy.m 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/7/27. 6 | // 7 | 8 | #import "UITableView+HoloTableViewProxy.h" 9 | #import 10 | #import "HoloTableViewProxy.h" 11 | #import "HoloTableViewProxyData.h" 12 | 13 | static char kHoloTableViewProxyKey; 14 | 15 | @implementation UITableView (HoloTableViewProxy) 16 | 17 | - (NSArray *)holo_sections { 18 | return self.holo_proxy.proxyData.sections; 19 | } 20 | 21 | - (void)setHolo_sections:(NSArray *)holo_sections { 22 | self.holo_proxy.proxyData.sections = holo_sections; 23 | } 24 | 25 | - (NSArray *)holo_sectionIndexTitles { 26 | return self.holo_proxy.proxyData.sectionIndexTitles; 27 | } 28 | 29 | - (void)setHolo_sectionIndexTitles:(NSArray *)holo_sectionIndexTitles { 30 | self.holo_proxy.proxyData.sectionIndexTitles = holo_sectionIndexTitles; 31 | } 32 | 33 | - (NSInteger (^)(NSString * _Nonnull, NSInteger))holo_sectionForSectionIndexTitleHandler { 34 | return self.holo_proxy.proxyData.sectionForSectionIndexTitleHandler; 35 | } 36 | 37 | - (void)setHolo_sectionForSectionIndexTitleHandler:(NSInteger (^)(NSString * _Nonnull, NSInteger))holo_sectionForSectionIndexTitleHandler { 38 | self.holo_proxy.proxyData.sectionForSectionIndexTitleHandler = holo_sectionForSectionIndexTitleHandler; 39 | } 40 | 41 | - (id)holo_scrollDelegate { 42 | return self.holo_proxy.scrollDelegate; 43 | } 44 | 45 | - (void)setHolo_scrollDelegate:(id)holo_scrollDelegate { 46 | self.holo_proxy.scrollDelegate = holo_scrollDelegate; 47 | } 48 | 49 | - (HoloTableViewProxy *)holo_proxy { 50 | HoloTableViewProxy *tableViewProxy = objc_getAssociatedObject(self, &kHoloTableViewProxyKey); 51 | if (!tableViewProxy) { 52 | tableViewProxy = [HoloTableViewProxy new]; 53 | objc_setAssociatedObject(self, &kHoloTableViewProxyKey, tableViewProxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 54 | self.dataSource = tableViewProxy; 55 | self.delegate = tableViewProxy; 56 | } 57 | return tableViewProxy; 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /HoloTableView/Classes/HoloTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableView.h 3 | // Pods 4 | // 5 | // Created by 与佳期 on 2019/7/27. 6 | // 7 | 8 | #ifndef HoloTableView_h 9 | #define HoloTableView_h 10 | 11 | // Maker 12 | #import 13 | #import 14 | 15 | // Maker (Row) 16 | #import 17 | #import 18 | 19 | // Maker (Section) 20 | #import 21 | #import 22 | 23 | // Maker (TableView) 24 | #import 25 | 26 | // Maker (Update) 27 | #import 28 | 29 | // Core 30 | #import 31 | #import 32 | #import 33 | #import 34 | 35 | // Core (Object) 36 | #import 37 | #import 38 | 39 | // Core (Protocol) 40 | #import 41 | #import 42 | #import 43 | 44 | // Core (SwipeAction) 45 | #import 46 | 47 | // Macro 48 | #import 49 | 50 | // Responder Event 51 | #import 52 | 53 | #endif /* HoloTableView_h */ 54 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Macro/HoloTableViewMacro.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewMacro.h 3 | // Pods 4 | // 5 | // Created by 与佳期 on 2019/8/1. 6 | // 7 | 8 | #ifndef HoloTableViewMacro_h 9 | #define HoloTableViewMacro_h 10 | 11 | #if !defined(TAG) 12 | #define TAG @"HOLO_DEFAULT_TAG" 13 | #endif 14 | 15 | #if !defined(HoloLog) 16 | #ifdef DEBUG 17 | #define HoloLog(...) NSLog(__VA_ARGS__) 18 | #else 19 | #define HoloLog(...) 20 | #endif 21 | #endif 22 | 23 | #endif /* HoloTableViewMacro_h */ 24 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/Deprecated/UITableView+HoloDeprecated.h: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView+HoloDeprecated.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2021/5/22. 6 | // 7 | 8 | #import 9 | @class HoloTableViewUpdateRowMaker; 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface UITableView (HoloDeprecated) 14 | 15 | /** 16 | * Creates a HoloTableViewUpdateRowMaker in the callee for current UITableView. 17 | * Update these rows in the callee for the section according to the tag. 18 | * If the section according to the tag don't contain these rows, ignore them. 19 | * 20 | * @param block Scope within which you can update some rows which you wish to apply to the section according to the tag. 21 | * @param tag The tag of section which you wish to update rows. 22 | */ 23 | - (void)holo_updateRows:(void(NS_NOESCAPE ^)(HoloTableViewUpdateRowMaker *make))block 24 | inSection:(NSString *)tag DEPRECATED_MSG_ATTRIBUTE("Please use `holo_updateRowsInSection:block:` api instead."); 25 | 26 | /** 27 | * Creates a HoloTableViewUpdateRowMaker in the callee for current UITableView. 28 | * Update these rows in the callee for the section according to the tag. 29 | * If the section according to the tag don't contain these rows, ignore them. 30 | * 31 | * Refresh current UITableView automatically. 32 | * 33 | * @param block Scope within which you can update some rows which you wish to apply to the section according to the tag. 34 | * @param tag The tag of section which you wish to update rows. 35 | * @param animation A constant that indicates how the reloading is to be animated, for example, fade out or slide out from the bottom. See UITableViewRowAnimation for descriptions of these constants. The animation constant affects the direction in which both the old and the new rows slide. For example, if the animation constant is UITableViewRowAnimationRight, the old rows slide out to the right and the new cells slide in from the right. 36 | */ 37 | - (void)holo_updateRows:(void(NS_NOESCAPE ^)(HoloTableViewUpdateRowMaker *make))block 38 | inSection:(NSString *)tag 39 | withReloadAnimation:(UITableViewRowAnimation)animation DEPRECATED_MSG_ATTRIBUTE("Please use `holo_updateRowsInSection:block:withReloadAnimation:` api instead."); 40 | 41 | /** 42 | * Creates a HoloTableViewUpdateRowMaker in the callee for current UITableView. 43 | * Re-create these rows in the callee for the section according to the tag. 44 | * If the section according to the tag don't contain these rows, ignore them. 45 | * 46 | * @param block Scope within which you can re-create some rows which you wish to apply to the section according to the tag. 47 | * @param tag The tag of section which you wish to remake rows. 48 | */ 49 | - (void)holo_remakeRows:(void(NS_NOESCAPE ^)(HoloTableViewUpdateRowMaker *make))block 50 | inSection:(NSString *)tag DEPRECATED_MSG_ATTRIBUTE("Please use `holo_remakeRows:block:` api instead."); 51 | 52 | /** 53 | * Creates a HoloTableViewUpdateRowMaker in the callee for current UITableView. 54 | * Re-create these rows in the callee for the section according to the tag. 55 | * If the section according to the tag don't contain these rows, ignore them. 56 | * 57 | * Refresh current UITableView automatically. 58 | * 59 | * @param block Scope within which you can re-create some rows which you wish to apply to the section according to the tag. 60 | * @param tag The tag of section which you wish to remake rows. 61 | * @param animation A constant that indicates how the reloading is to be animated, for example, fade out or slide out from the bottom. See UITableViewRowAnimation for descriptions of these constants. The animation constant affects the direction in which both the old and the new rows slide. For example, if the animation constant is UITableViewRowAnimationRight, the old rows slide out to the right and the new cells slide in from the right. 62 | */ 63 | - (void)holo_remakeRows:(void(NS_NOESCAPE ^)(HoloTableViewUpdateRowMaker *make))block 64 | inSection:(NSString *)tag 65 | withReloadAnimation:(UITableViewRowAnimation)animation DEPRECATED_MSG_ATTRIBUTE("Please use `holo_remakeRows:block:withReloadAnimation:` api instead."); 66 | 67 | @end 68 | 69 | NS_ASSUME_NONNULL_END 70 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/Deprecated/UITableView+HoloDeprecated.m: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView+HoloDeprecated.m 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2021/5/22. 6 | // 7 | 8 | #import "UITableView+HoloDeprecated.h" 9 | #import "HoloTableViewUpdateRowMaker.h" 10 | #import "UITableView+HoloTableView.h" 11 | 12 | @implementation UITableView (HoloDeprecated) 13 | 14 | - (void)holo_updateRows:(void(NS_NOESCAPE ^)(HoloTableViewUpdateRowMaker *make))block 15 | inSection:(NSString *)tag { 16 | [self holo_updateRowsInSection:tag block:block]; 17 | } 18 | 19 | - (void)holo_updateRows:(void(NS_NOESCAPE ^)(HoloTableViewUpdateRowMaker *make))block 20 | inSection:(NSString *)tag 21 | withReloadAnimation:(UITableViewRowAnimation)animation { 22 | [self holo_updateRowsInSection:tag block:block withReloadAnimation:animation]; 23 | } 24 | 25 | - (void)holo_remakeRows:(void(NS_NOESCAPE ^)(HoloTableViewUpdateRowMaker *make))block 26 | inSection:(NSString *)tag { 27 | [self holo_remakeRowsInSection:tag block:block]; 28 | } 29 | 30 | - (void)holo_remakeRows:(void(NS_NOESCAPE ^)(HoloTableViewUpdateRowMaker *make))block 31 | inSection:(NSString *)tag 32 | withReloadAnimation:(UITableViewRowAnimation)animation { 33 | [self holo_remakeRowsInSection:tag block:block withReloadAnimation:animation]; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/Row/HoloTableRowMaker.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableRowMaker.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2020/6/1. 6 | // 7 | 8 | #import 9 | @class HoloTableRow, HoloTableViewRowSwipeAction; 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface HoloTableRowMaker : NSObject 14 | 15 | /** 16 | * Make a cell with class. 17 | */ 18 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^row)(Class row); 19 | 20 | /** 21 | * Set the data for current row using the `model` property. 22 | * 23 | * If the `modelHandler` property is nil, then use the `model` property. 24 | */ 25 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^model)(id model); 26 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^modelHandler)(id (^)(void)); 27 | 28 | /** 29 | * current row must implement the `configSEL` property setting method in order for the HoloTableView to pass the model for current row. 30 | */ 31 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^configSEL)(SEL configSEL); 32 | 33 | /** 34 | * Performed before `configSEL`. 35 | */ 36 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^beforeConfigureHandler)(void(^)(UITableViewCell *cell, id _Nullable model)); 37 | 38 | /** 39 | * Performed after `configSEL`. 40 | */ 41 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^afterConfigureHandler)(void(^)(UITableViewCell *cell, id _Nullable model)); 42 | 43 | /** 44 | * Set the style for current row using the `style` property. 45 | * 46 | * If the `styleHandler` property is nil, then use the `style` property. 47 | */ 48 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^style)(UITableViewCellStyle style); 49 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^styleHandler)(UITableViewCellStyle (^)(id _Nullable model)); 50 | 51 | /** 52 | * Set the reuse identifier for current row using the `reuseId` property. 53 | * 54 | * If the `reuseIdHandler` property is nil, then use the `reuseId` property. 55 | */ 56 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^reuseId)(NSString *reuseId); 57 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^reuseIdHandler)(NSString *(^)(id _Nullable model)); 58 | 59 | /** 60 | * Set the tag for current row using the `tag` property. 61 | */ 62 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^tag)(NSString *tag); 63 | 64 | /** 65 | * Set the height for current row using the `height` property. 66 | * 67 | * If the `heightSEL` property is nil or current row don't implement the `heightSEL` property setting method, then use the `heightHandler` property. 68 | * If the `heightHandler` property is nil, then use the `height` property. 69 | */ 70 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^height)(CGFloat height); 71 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^heightHandler)(CGFloat (^)(id _Nullable model)); 72 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^heightSEL)(SEL heightSEL); 73 | 74 | /** 75 | * Set the estimated height for current row using the `estimatedHeight` property. 76 | * 77 | * If the `estimatedHeightSEL` property is nil or current row don't implement the `estimatedHeightSEL` property setting method, then use the `estimatedHeightHandler` property. 78 | * If the `estimatedHeightHandler` property is nil, then use the `estimatedHeight` property. 79 | */ 80 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^estimatedHeight)(CGFloat estimatedHeight); 81 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^estimatedHeightHandler)(CGFloat (^)(id _Nullable model)); 82 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^estimatedHeightSEL)(SEL estimatedHeightSEL); 83 | 84 | /** 85 | * Set the should highlight or not for current row using the `estimatedHeight` property. 86 | * 87 | * If the `shouldHighlightSEL` property is nil or current row don't implement the `shouldHighlightSEL` property setting method, then use the `shouldHighlightHandler` property. 88 | * If the `shouldHighlightHandler` property is nil, then use the `shouldHighlight` property. 89 | */ 90 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^shouldHighlight)(BOOL shouldHighlight); 91 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^shouldHighlightHandler)(BOOL (^)(id _Nullable model)); 92 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^shouldHighlightSEL)(SEL shouldHighlightSEL); 93 | 94 | /** 95 | * Set the can edit or not for current row using the `canEdit` property. 96 | * 97 | * If the `canEditHandler` property is nil, then use the `canEdit` property. 98 | */ 99 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^canEdit)(BOOL canEdit); 100 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^canEditHandler)(BOOL (^)(id _Nullable model)); 101 | 102 | /** 103 | * Set the can move or not for current row using the `canMove` property. 104 | * 105 | * If the `canMoveHandler` property is nil, then use the `canEdit` property. 106 | */ 107 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^canMove)(BOOL canMove); 108 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^canMoveHandler)(BOOL (^)(id _Nullable model)); 109 | 110 | /** 111 | * Set the leading swipe actions for current row using the `leadingSwipeActions` property. 112 | * 113 | * If the `leadingSwipeActionsHandler` property is nil, then use the `leadingSwipeActions` property. 114 | */ 115 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^leadingSwipeActions)(NSArray *leadingSwipeActions) API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos); 116 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^leadingSwipeActionsHandler)(NSArray *(^)(id _Nullable model)) API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos); 117 | 118 | /** 119 | * Set the leading swipe for current row using the `leadingSwipeHandler` property. 120 | */ 121 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^leadingSwipeHandler)(void(^)(id action, NSInteger index, void(^completionHandler)(BOOL actionPerformed))) API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos); 122 | 123 | /** 124 | * Set the trailing swipe actions for current row using the `trailingSwipeActions` property. 125 | * 126 | * If the `trailingSwipeActionsHandler` property is nil, then use the `trailingSwipeActions` property. 127 | */ 128 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^trailingSwipeActions)(NSArray *trailingSwipeActions); 129 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^trailingSwipeActionsHandler)(NSArray *(^)(id _Nullable model)); 130 | 131 | /** 132 | * Set the trailing swipe for current row using the `trailingSwipeHandler` property. 133 | */ 134 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^trailingSwipeHandler)(void(^)(id action, NSInteger index, void(^completionHandler)(BOOL actionPerformed))); 135 | 136 | /** 137 | * Set the editing delete title for current row using the `editingDeleteTitle` property. 138 | * 139 | * If the `editingDeleteTitleHandler` property is nil, then use the `editingDeleteTitle` property. 140 | */ 141 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^editingDeleteTitle)(NSString *title); 142 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^editingDeleteTitleHandler)(NSString *(^)(id _Nullable model)); 143 | 144 | /** 145 | * Set the editing style for current row using the `editingStyle` property. 146 | * 147 | * If the `editingStyleHandler` property is nil, then use the `editingStyle` property. 148 | */ 149 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^editingStyle)(UITableViewCellEditingStyle editingStyle); 150 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^editingStyleHandler)(UITableViewCellEditingStyle(^)(id _Nullable model)); 151 | 152 | /** 153 | * If current row will select, the `willSelectHandler` will be called. 154 | * 155 | * If the `willSelectSEL` property is nil or current row don't implement the `willSelectSEL` property setting method, then use the `willSelectHandler` property. 156 | */ 157 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^willSelectHandler)(void(^)(id _Nullable model)); 158 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^willSelectSEL)(SEL willSelectSEL); 159 | 160 | /** 161 | * If current row will deselect, the `willDeselectHandler` will be called. 162 | * 163 | * If the `willDeselectSEL` property is nil or current row don't implement the `willDeselectSEL` property setting method, then use the `willDeselectHandler` property. 164 | */ 165 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^willDeselectHandler)(void(^)(id _Nullable model)); 166 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^willDeselectSEL)(SEL willDeselectSEL); 167 | 168 | /** 169 | * If current row did deselect, the `didDeselectHandler` will be called. 170 | * 171 | * If the `didDeselectSEL` property is nil or current row don't implement the `didDeselectSEL` property setting method, then use the `didDeselectHandler` property. 172 | */ 173 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^didDeselectHandler)(void(^)(id _Nullable model)); 174 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^didDeselectSEL)(SEL didDeselectSEL); 175 | 176 | /** 177 | * If current row did select, the `didSelectHandler` will be called. 178 | * 179 | * If the `didSelectSEL` property is nil or current row don't implement the `didSelectSEL` property setting method, then use the `didSelectHandler` property. 180 | */ 181 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^didSelectHandler)(void(^)(id _Nullable model)); 182 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^didSelectSEL)(SEL didSelectSEL); 183 | 184 | /** 185 | * If current row will display, the `willDisplayHandler` will be called. 186 | * 187 | * If the `willDisplaySEL` property is nil or current row don't implement the `willDisplaySEL` property setting method, then use the `willDisplayHandler` property. 188 | */ 189 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^willDisplayHandler)(void(^)(UITableViewCell *cell, id _Nullable model)); 190 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^willDisplaySEL)(SEL willDisplaySEL); 191 | 192 | /** 193 | * If current row did end displaying, the `didEndDisplayingHandler` will be called. 194 | * 195 | * If the `didEndDisplayingSEL` property is nil or current row don't implement the `didEndDisplayingSEL` property setting method, then use the `didEndDisplayingHandler` property. 196 | */ 197 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^didEndDisplayingHandler)(void(^)(UITableViewCell *cell, id _Nullable model)); 198 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^didEndDisplayingSEL)(SEL didEndDisplayingSEL); 199 | 200 | /** 201 | * If current row did highlight, the `didHighlightHandler` will be called. 202 | * 203 | * If the `didHighlightSEL` property is nil or current row don't implement the `didHighlightSEL` property setting method, then use the `didHighlightHandler` property. 204 | */ 205 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^didHighlightHandler)(void(^)(id _Nullable model)); 206 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^didHighlightSEL)(SEL didHighlightSEL); 207 | 208 | /** 209 | * If current row did unhighlight, the `didUnHighlightHandler` will be called. 210 | * 211 | * If the `didUnHighlightSEL` property is nil or current row don't implement the `didUnHighlightSEL` property setting method, then use the `didUnHighlightHandler` property. 212 | */ 213 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^didUnHighlightHandler)(void(^)(id _Nullable model)); 214 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^didUnHighlightSEL)(SEL didUnHighlightSEL); 215 | 216 | /** 217 | * If current row accessory button tapped, the `accessoryButtonTappedHandler` will be called. 218 | * 219 | * If the `accessoryButtonTappedSEL` property is nil or current row don't implement the `accessoryButtonTappedSEL` property setting method, then use the `accessoryButtonTappedHandler` property. 220 | */ 221 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^accessoryButtonTappedHandler)(void(^)(id _Nullable model)); 222 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^accessoryButtonTappedSEL)(SEL accessoryButtonTappedSEL); 223 | 224 | /** 225 | * If current row will begin editing, the `willBeginEditingHandler` will be called. 226 | * 227 | * If the `willBeginEditingSEL` property is nil or current row don't implement the `willBeginEditingSEL` property setting method, then use the `willBeginEditingHandler` property. 228 | */ 229 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^willBeginEditingHandler)(void(^)(id _Nullable model)); 230 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^willBeginEditingSEL)(SEL willBeginEditingSEL); 231 | 232 | /** 233 | * If current row did end editing, the `didEndEditingHandler` will be called. 234 | * 235 | * If the `didEndEditingSEL` property is nil or current row don't implement the `didEndEditingSEL` property setting method, then use the `didEndEditingHandler` property. 236 | */ 237 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^didEndEditingHandler)(void(^)(id _Nullable model)); 238 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^didEndEditingSEL)(SEL didEndEditingSEL); 239 | 240 | /** 241 | * Set the target move index for current row using the `targetMoveHandler` property. 242 | */ 243 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^targetMoveHandler)(NSIndexPath *(^targetIndexPath)(NSIndexPath *atIndexPath, NSIndexPath *toIndexPath)); 244 | 245 | /** 246 | * If current row is moved, the `moveHandler` will be called. 247 | */ 248 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^moveHandler)(void(^)(NSIndexPath *atIndexPath, NSIndexPath *toIndexPath, void(^completionHandler)(BOOL actionPerformed))); 249 | 250 | /** 251 | * If current row is editing delete, the `editingDeleteHandler` will be called. 252 | */ 253 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^editingDeleteHandler)(void(^)(id _Nullable model, void(^completionHandler)(BOOL actionPerformed))); 254 | 255 | /** 256 | * If current row is editing Insert, the `editingInsertHandler` will be called. 257 | */ 258 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^editingInsertHandler)(void(^)(id _Nullable model)); 259 | 260 | 261 | - (HoloTableRow *)fetchTableRow; 262 | 263 | - (void)giveTableRow:(HoloTableRow *)tableRow; 264 | 265 | @end 266 | 267 | NS_ASSUME_NONNULL_END 268 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/Row/HoloTableRowMaker.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableRowMaker.m 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2020/6/1. 6 | // 7 | 8 | #import "HoloTableRowMaker.h" 9 | #import "HoloTableRow.h" 10 | #import "HoloTableViewRowSwipeAction.h" 11 | 12 | @interface HoloTableRowMaker () 13 | 14 | @property (nonatomic, strong) HoloTableRow *tableRow; 15 | 16 | @end 17 | 18 | @implementation HoloTableRowMaker 19 | 20 | - (HoloTableRowMaker * (^)(Class))row { 21 | return ^id(Class cls) { 22 | self.tableRow.cell = cls; 23 | return self; 24 | }; 25 | } 26 | 27 | - (HoloTableRowMaker *(^)(id))model { 28 | return ^id(id obj) { 29 | self.tableRow.model = obj; 30 | return self; 31 | }; 32 | } 33 | - (HoloTableRowMaker * (^)(id (^)(void)))modelHandler { 34 | return ^id(id obj) { 35 | self.tableRow.modelHandler = obj; 36 | return self; 37 | }; 38 | } 39 | 40 | - (HoloTableRowMaker *(^)(SEL))configSEL { 41 | return ^id(SEL s) { 42 | self.tableRow.configSEL = s; 43 | return self; 44 | }; 45 | } 46 | - (HoloTableRowMaker * (^)(void (^)(UITableViewCell *, id)))beforeConfigureHandler { 47 | return ^id(id obj) { 48 | self.tableRow.beforeConfigureHandler = obj; 49 | return self; 50 | }; 51 | } 52 | - (HoloTableRowMaker * (^)(void (^)(UITableViewCell *, id)))afterConfigureHandler { 53 | return ^id(id obj) { 54 | self.tableRow.afterConfigureHandler = obj; 55 | return self; 56 | }; 57 | } 58 | 59 | - (HoloTableRowMaker * (^)(UITableViewCellStyle))style { 60 | return ^id(UITableViewCellStyle style) { 61 | self.tableRow.style = style; 62 | return self; 63 | }; 64 | } 65 | - (HoloTableRowMaker * (^)(UITableViewCellStyle (^)(id)))styleHandler { 66 | return ^id(id obj) { 67 | self.tableRow.styleHandler = obj; 68 | return self; 69 | }; 70 | } 71 | 72 | - (HoloTableRowMaker * (^)(NSString *))reuseId { 73 | return ^id(id obj) { 74 | self.tableRow.reuseId = obj; 75 | return self; 76 | }; 77 | } 78 | - (HoloTableRowMaker * (^)(NSString * (^)(id)))reuseIdHandler { 79 | return ^id(id obj) { 80 | self.tableRow.reuseIdHandler = obj; 81 | return self; 82 | }; 83 | } 84 | 85 | - (HoloTableRowMaker *(^)(NSString *))tag { 86 | return ^id(id obj) { 87 | self.tableRow.tag = obj; 88 | return self; 89 | }; 90 | } 91 | 92 | - (HoloTableRowMaker *(^)(CGFloat))height { 93 | return ^id(CGFloat f) { 94 | self.tableRow.height = f; 95 | return self; 96 | }; 97 | } 98 | - (HoloTableRowMaker * (^)(CGFloat (^)(id)))heightHandler { 99 | return ^id(id obj) { 100 | self.tableRow.heightHandler = obj; 101 | return self; 102 | }; 103 | } 104 | - (HoloTableRowMaker *(^)(SEL))heightSEL { 105 | return ^id(SEL s) { 106 | self.tableRow.heightSEL = s; 107 | return self; 108 | }; 109 | } 110 | 111 | 112 | - (HoloTableRowMaker *(^)(CGFloat))estimatedHeight { 113 | return ^id(CGFloat f) { 114 | self.tableRow.estimatedHeight = f; 115 | return self; 116 | }; 117 | } 118 | - (HoloTableRowMaker * (^)(CGFloat (^)(id)))estimatedHeightHandler { 119 | return ^id(id obj) { 120 | self.tableRow.estimatedHeightHandler = obj; 121 | return self; 122 | }; 123 | } 124 | - (HoloTableRowMaker *(^)(SEL))estimatedHeightSEL { 125 | return ^id(SEL s) { 126 | self.tableRow.estimatedHeightSEL = s; 127 | return self; 128 | }; 129 | } 130 | 131 | - (HoloTableRowMaker *(^)(BOOL))shouldHighlight { 132 | return ^id(BOOL b) { 133 | self.tableRow.shouldHighlight = b; 134 | return self; 135 | }; 136 | } 137 | - (HoloTableRowMaker * (^)(BOOL (^)(id)))shouldHighlightHandler { 138 | return ^id(id obj) { 139 | self.tableRow.shouldHighlightHandler = obj; 140 | return self; 141 | }; 142 | } 143 | - (HoloTableRowMaker *(^)(SEL))shouldHighlightSEL { 144 | return ^id(SEL s) { 145 | self.tableRow.shouldHighlightSEL = s; 146 | return self; 147 | }; 148 | } 149 | 150 | - (HoloTableRowMaker *(^)(BOOL))canEdit { 151 | return ^id(BOOL b) { 152 | self.tableRow.canEdit = b; 153 | return self; 154 | }; 155 | } 156 | - (HoloTableRowMaker * (^)(BOOL (^)(id)))canEditHandler { 157 | return ^id(id obj) { 158 | self.tableRow.canEditHandler = obj; 159 | return self; 160 | }; 161 | } 162 | 163 | - (HoloTableRowMaker *(^)(BOOL))canMove { 164 | return ^id(BOOL b) { 165 | if (b) self.tableRow.canEdit = YES; 166 | self.tableRow.canMove = b; 167 | return self; 168 | }; 169 | } 170 | - (HoloTableRowMaker * (^)(BOOL (^)(id)))canMoveHandler { 171 | return ^id(id obj) { 172 | self.tableRow.canMoveHandler = obj; 173 | return self; 174 | }; 175 | } 176 | 177 | - (HoloTableRowMaker *(^)(NSArray *))leadingSwipeActions { 178 | return ^id(NSArray *a) { 179 | if (a.count > 0) self.tableRow.canEdit = YES; 180 | if (@available(iOS 11.0, *)) { 181 | self.tableRow.leadingSwipeActions = a; 182 | } 183 | return self; 184 | }; 185 | } 186 | - (HoloTableRowMaker * (^)(NSArray *(^)(id)))leadingSwipeActionsHandler { 187 | return ^id(id obj) { 188 | if (@available(iOS 11.0, *)) { 189 | self.tableRow.leadingSwipeActionsHandler = obj; 190 | } 191 | return self; 192 | }; 193 | } 194 | 195 | - (HoloTableRowMaker *(^)(void (^)(id, NSInteger, void(^)(BOOL))))leadingSwipeHandler { 196 | return ^id(id obj) { 197 | self.tableRow.leadingSwipeHandler = obj; 198 | return self; 199 | }; 200 | } 201 | 202 | - (HoloTableRowMaker *(^)(NSArray *))trailingSwipeActions { 203 | return ^id(NSArray *a) { 204 | if (a.count > 0) self.tableRow.canEdit = YES; 205 | self.tableRow.trailingSwipeActions = a; 206 | return self; 207 | }; 208 | } 209 | - (HoloTableRowMaker * (^)(NSArray *(^)(id)))trailingSwipeActionsHandler { 210 | return ^id(id obj) { 211 | self.tableRow.trailingSwipeActionsHandler = obj; 212 | return self; 213 | }; 214 | } 215 | 216 | - (HoloTableRowMaker *(^)(void (^)(id, NSInteger, void(^)(BOOL))))trailingSwipeHandler { 217 | return ^id(id obj) { 218 | self.tableRow.trailingSwipeHandler = obj; 219 | return self; 220 | }; 221 | } 222 | 223 | - (HoloTableRowMaker *(^)(NSString *))editingDeleteTitle { 224 | return ^id(id obj) { 225 | self.tableRow.editingDeleteTitle = obj; 226 | return self; 227 | }; 228 | } 229 | - (HoloTableRowMaker * (^)(NSString * (^)(id)))editingDeleteTitleHandler { 230 | return ^id(id obj) { 231 | self.tableRow.editingDeleteTitleHandler = obj; 232 | return self; 233 | }; 234 | } 235 | 236 | - (HoloTableRowMaker * (^)(UITableViewCellEditingStyle))editingStyle { 237 | return ^id(UITableViewCellEditingStyle editingStyle) { 238 | self.tableRow.editingStyle = editingStyle; 239 | return self; 240 | }; 241 | } 242 | - (HoloTableRowMaker * (^)(UITableViewCellEditingStyle (^)(id)))editingStyleHandler { 243 | return ^id(id obj) { 244 | self.tableRow.editingStyleHandler = obj; 245 | return self; 246 | }; 247 | } 248 | 249 | - (HoloTableRowMaker * (^)(void (^)(id)))willSelectHandler { 250 | return ^id(id obj) { 251 | self.tableRow.willSelectHandler = obj; 252 | return self; 253 | }; 254 | } 255 | - (HoloTableRowMaker *(^)(SEL))willSelectSEL { 256 | return ^id(SEL s) { 257 | self.tableRow.willSelectSEL = s; 258 | return self; 259 | }; 260 | } 261 | 262 | - (HoloTableRowMaker * (^)(void (^)(id)))willDeselectHandler { 263 | return ^id(id obj) { 264 | self.tableRow.willDeselectHandler = obj; 265 | return self; 266 | }; 267 | } 268 | - (HoloTableRowMaker *(^)(SEL))willDeselectSEL { 269 | return ^id(SEL s) { 270 | self.tableRow.willDeselectSEL = s; 271 | return self; 272 | }; 273 | } 274 | 275 | - (HoloTableRowMaker * (^)(void (^)(id)))didDeselectHandler { 276 | return ^id(id obj) { 277 | self.tableRow.didDeselectHandler = obj; 278 | return self; 279 | }; 280 | } 281 | - (HoloTableRowMaker *(^)(SEL))didDeselectSEL { 282 | return ^id(SEL s) { 283 | self.tableRow.didDeselectSEL = s; 284 | return self; 285 | }; 286 | } 287 | 288 | - (HoloTableRowMaker * (^)(void (^)(id)))didSelectHandler { 289 | return ^id(id obj) { 290 | self.tableRow.didSelectHandler = obj; 291 | return self; 292 | }; 293 | } 294 | - (HoloTableRowMaker *(^)(SEL))didSelectSEL { 295 | return ^id(SEL s) { 296 | self.tableRow.didSelectSEL = s; 297 | return self; 298 | }; 299 | } 300 | 301 | - (HoloTableRowMaker *(^)(void (^)(UITableViewCell *, id)))willDisplayHandler { 302 | return ^id(id obj) { 303 | self.tableRow.willDisplayHandler = obj; 304 | return self; 305 | }; 306 | } 307 | - (HoloTableRowMaker *(^)(SEL))willDisplaySEL { 308 | return ^id(SEL s) { 309 | self.tableRow.willDisplaySEL = s; 310 | return self; 311 | }; 312 | } 313 | 314 | - (HoloTableRowMaker *(^)(void (^)(UITableViewCell *, id)))didEndDisplayingHandler { 315 | return ^id(id obj) { 316 | self.tableRow.didEndDisplayingHandler = obj; 317 | return self; 318 | }; 319 | } 320 | - (HoloTableRowMaker *(^)(SEL))didEndDisplayingSEL { 321 | return ^id(SEL s) { 322 | self.tableRow.didEndDisplayingSEL = s; 323 | return self; 324 | }; 325 | } 326 | 327 | - (HoloTableRowMaker *(^)(void (^)(id)))didHighlightHandler { 328 | return ^id(id obj) { 329 | self.tableRow.didHighlightHandler = obj; 330 | return self; 331 | }; 332 | } 333 | - (HoloTableRowMaker *(^)(SEL))didHighlightSEL { 334 | return ^id(SEL s) { 335 | self.tableRow.didHighlightSEL = s; 336 | return self; 337 | }; 338 | } 339 | 340 | - (HoloTableRowMaker *(^)(void (^)(id)))didUnHighlightHandler { 341 | return ^id(id obj) { 342 | self.tableRow.didUnHighlightHandler = obj; 343 | return self; 344 | }; 345 | } 346 | - (HoloTableRowMaker *(^)(SEL))didUnHighlightSEL { 347 | return ^id(SEL s) { 348 | self.tableRow.didUnHighlightSEL = s; 349 | return self; 350 | }; 351 | } 352 | 353 | - (HoloTableRowMaker *(^)(void (^)(id)))accessoryButtonTappedHandler { 354 | return ^id(id obj) { 355 | self.tableRow.accessoryButtonTappedHandler = obj; 356 | return self; 357 | }; 358 | } 359 | - (HoloTableRowMaker *(^)(SEL))accessoryButtonTappedSEL { 360 | return ^id(SEL s) { 361 | self.tableRow.accessoryButtonTappedSEL = s; 362 | return self; 363 | }; 364 | } 365 | 366 | - (HoloTableRowMaker *(^)(void (^)(id)))willBeginEditingHandler { 367 | return ^id(id obj) { 368 | self.tableRow.willBeginEditingHandler = obj; 369 | return self; 370 | }; 371 | } 372 | - (HoloTableRowMaker *(^)(SEL))willBeginEditingSEL { 373 | return ^id(SEL s) { 374 | self.tableRow.willBeginEditingSEL = s; 375 | return self; 376 | }; 377 | } 378 | 379 | - (HoloTableRowMaker *(^)(void (^)(id)))didEndEditingHandler { 380 | return ^id(id obj) { 381 | self.tableRow.didEndEditingHandler = obj; 382 | return self; 383 | }; 384 | } 385 | - (HoloTableRowMaker *(^)(SEL))didEndEditingSEL { 386 | return ^id(SEL s) { 387 | self.tableRow.didEndEditingSEL = s; 388 | return self; 389 | }; 390 | } 391 | 392 | - (HoloTableRowMaker *(^)(NSIndexPath *(^)(NSIndexPath *, NSIndexPath *)))targetMoveHandler { 393 | return ^id(id obj) { 394 | self.tableRow.targetMoveHandler = obj; 395 | return self; 396 | }; 397 | } 398 | 399 | - (HoloTableRowMaker *(^)(void (^)(NSIndexPath *, NSIndexPath *, void(^)(BOOL))))moveHandler { 400 | return ^id(id obj) { 401 | if (obj) { 402 | self.tableRow.canEdit = YES; 403 | self.tableRow.canMove = YES; 404 | } 405 | self.tableRow.moveHandler = obj; 406 | return self; 407 | }; 408 | } 409 | 410 | - (HoloTableRowMaker * (^)(void (^)(id, void (^)(BOOL))))editingDeleteHandler { 411 | return ^id(id obj) { 412 | if (obj) { 413 | self.tableRow.canEdit = YES; 414 | self.tableRow.editingStyle = UITableViewCellEditingStyleDelete; 415 | } 416 | self.tableRow.editingDeleteHandler = obj; 417 | return self; 418 | }; 419 | } 420 | 421 | - (HoloTableRowMaker *(^)(void (^)(id)))editingInsertHandler { 422 | return ^id(id obj) { 423 | if (obj) { 424 | self.tableRow.canEdit = YES; 425 | self.tableRow.editingStyle = UITableViewCellEditingStyleInsert; 426 | } 427 | self.tableRow.editingInsertHandler = obj; 428 | return self; 429 | }; 430 | } 431 | 432 | - (HoloTableRow *)fetchTableRow { 433 | return self.tableRow; 434 | } 435 | 436 | - (void)giveTableRow:(HoloTableRow *)tableRow { 437 | self.tableRow = tableRow; 438 | } 439 | 440 | #pragma mark - getter 441 | - (HoloTableRow *)tableRow { 442 | if (!_tableRow) { 443 | _tableRow = [HoloTableRow new]; 444 | } 445 | return _tableRow; 446 | } 447 | 448 | @end 449 | 450 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/Row/HoloTableViewRowMaker.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewRowMaker.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/7/28. 6 | // 7 | 8 | #import 9 | @class HoloTableRow, HoloTableRowMaker; 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface HoloTableViewRowMaker : NSObject 14 | 15 | /** 16 | * Make a HoloTableRow object and set the cell class. 17 | */ 18 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^row)(Class row); 19 | 20 | - (NSArray *)install; 21 | 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/Row/HoloTableViewRowMaker.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewRowMaker.m 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/7/28. 6 | // 7 | 8 | #import "HoloTableViewRowMaker.h" 9 | #import "HoloTableRow.h" 10 | #import "HoloTableRowMaker.h" 11 | 12 | @interface HoloTableViewRowMaker () 13 | 14 | @property (nonatomic, strong) NSMutableArray *holoRows; 15 | 16 | @end 17 | 18 | @implementation HoloTableViewRowMaker 19 | 20 | - (HoloTableRowMaker * (^)(Class))row { 21 | return ^id(Class cls) { 22 | HoloTableRowMaker *rowMaker = [HoloTableRowMaker new]; 23 | HoloTableRow *tableRow = [rowMaker fetchTableRow]; 24 | tableRow.cell = cls; 25 | 26 | [self.holoRows addObject:tableRow]; 27 | return rowMaker; 28 | }; 29 | } 30 | 31 | - (NSArray *)install { 32 | return self.holoRows; 33 | } 34 | 35 | #pragma mark - getter 36 | - (NSMutableArray *)holoRows { 37 | if (!_holoRows) { 38 | _holoRows = [NSMutableArray new]; 39 | } 40 | return _holoRows; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/Section/HoloTableSectionMaker.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableSectionMaker.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2020/6/2. 6 | // 7 | 8 | #import 9 | @class HoloTableSection, HoloTableViewRowMaker, HoloTableViewUpdateRowMaker; 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface HoloTableSectionMaker : NSObject 14 | 15 | /** 16 | * Make a headerwith class. 17 | */ 18 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^header)(Class header); 19 | 20 | /** 21 | * Make a footer with class. 22 | */ 23 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footer)(Class footer); 24 | 25 | /** 26 | * Set the reuse identifier for the header using the `headerReuseId` property. 27 | * 28 | * If the `headerReuseIdHandler` property is nil, then use the `headerReuseId` property. 29 | */ 30 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^headerReuseId)(NSString *headerReuseId); 31 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^headerReuseIdHandler)(NSString *(^)(id _Nullable model)); 32 | 33 | /** 34 | * Set the reuse identifier for the footer using the `footerReuseId` property. 35 | * 36 | * If the `footerReuseIdHandler` property is nil, then use the `footerReuseId` property. 37 | */ 38 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footerReuseId)(NSString *footerReuseId); 39 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footerReuseIdHandler)(NSString *(^)(id _Nullable model)); 40 | 41 | /** 42 | * Set the header title for the section using the `headerTitle` property. 43 | * 44 | * If you set 'header', the `headerTitleHandler` property and `headerTitle` property will be invalid. 45 | * 46 | * If the `headerTitleHandler` property is nil, then use the `headerTitle` property. 47 | */ 48 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^headerTitle)(NSString *headerTitle); 49 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^headerTitleHandler)(NSString *(^)(void)); 50 | 51 | /** 52 | * Set the footer title for the section using the `footerTitle` property. 53 | * 54 | * If you set 'footer', the `footerTitleHandler` property and `footerTitle` property will be invalid. 55 | * 56 | * If the `footerTitleHandler` property is nil, then use the `footerTitle` property. 57 | */ 58 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footerTitle)(NSString *footerTitle); 59 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footerTitleHandler)(NSString *(^)(void)); 60 | 61 | /** 62 | * Set the data for the header using the `headerModel` property. 63 | * 64 | * If the `headerModelHandler` property is nil, then use the `headerModel` property. 65 | */ 66 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^headerModel)(id headerModel); 67 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^headerModelHandler)(id (^)(void)); 68 | 69 | /** 70 | * Set the data for the footer using the `footerModel` property. 71 | * 72 | * If the `footerModelHandler` property is nil, then use the `footerModel` property. 73 | */ 74 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footerModel)(id footerModel); 75 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footerModelHandler)(id (^)(void)); 76 | 77 | /** 78 | * The header must implement the `headerConfigSEL` property setting method in order for the HoloTableView to pass the model for the header. 79 | */ 80 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^headerConfigSEL)(SEL headerConfigSEL); 81 | 82 | /** 83 | * The footer must implement the `footerConfigSEL` property setting method in order for the HoloTableView to pass the model for the footer. 84 | */ 85 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footerConfigSEL)(SEL footerConfigSEL); 86 | 87 | /** 88 | * Set the height for the header using the `headerHeight` property. 89 | * 90 | * If the `headerHeightSEL` property is nil or the header don't implement the `headerHeightSEL` property setting method, then use the `headerHeightHandler` property. 91 | * If the `headerHeightHandler` property is nil, then use the `headerHeight` property. 92 | */ 93 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^headerHeight)(CGFloat headerHeight); 94 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^headerHeightHandler)(CGFloat (^)(id _Nullable model)); 95 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^headerHeightSEL)(SEL headerHeightSEL); 96 | 97 | /** 98 | * Set the height for the footer using the `footerHeight` property. 99 | * 100 | * If the `footerHeightSEL` property is nil or the footer don't implement the `footerHeightSEL` property setting method, then use the `footerHeightHandler` property. 101 | * If the `footerHeightHandler` property is nil, then use the `footerHeight` property. 102 | */ 103 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footerHeight)(CGFloat footerHeight); 104 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footerHeightHandler)(CGFloat (^)(id _Nullable model)); 105 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footerHeightSEL)(SEL footerHeightSEL); 106 | 107 | /** 108 | * Set the estimated height for the header using the `headerEstimatedHeight` property. 109 | * 110 | * If the `headerEstimatedHeightSEL` property is nil or the header don't implement the `headerEstimatedHeightSEL` property setting method, then use the `headerEstimatedHeightHandler` property. 111 | * If the `headerEstimatedHeightHandler` property is nil, then use the `headerEstimatedHeight` property. 112 | */ 113 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^headerEstimatedHeight)(CGFloat headerEstimatedHeight); 114 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^headerEstimatedHeightHandler)(CGFloat (^)(id _Nullable model)); 115 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^headerEstimatedHeightSEL)(SEL headerEstimatedHeightSEL); 116 | 117 | /** 118 | * Set the estimated height for the footer using the `footerEstimatedHeight` property. 119 | * 120 | * If the `footerEstimatedHeightSEL` property is nil or the footer don't implement the `footerEstimatedHeightSEL` property setting method, then use the `footerEstimatedHeightHandler` property. 121 | * If the `footerEstimatedHeightHandler` property is nil, then use the `footerEstimatedHeight` property. 122 | */ 123 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footerEstimatedHeight)(CGFloat footerEstimatedHeight); 124 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footerEstimatedHeightHandler)(CGFloat (^)(id _Nullable model)); 125 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^footerEstimatedHeightSEL)(SEL footerEstimatedHeightSEL); 126 | 127 | /** 128 | * If the header will display, the `willDisplayHeaderHandler` will be called. 129 | * 130 | * If the `willDisplayHeaderSEL` property is nil or the header don't implement the `willDisplayHeaderSEL` property setting method, then use the `willDisplayHeaderHandler` property. 131 | */ 132 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^willDisplayHeaderHandler)(void(^)(UIView *header, id _Nullable model)); 133 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^willDisplayHeaderSEL)(SEL willDisplayHeaderSEL); 134 | 135 | /** 136 | * If the footer will display, the `willDisplayFooterSEL` will be called. 137 | * 138 | * If the `willDisplayFooterSEL` property is nil or the footer don't implement the `willDisplayFooterSEL` property setting method, then use the `willDisplayFooterHandler` property. 139 | */ 140 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^willDisplayFooterHandler)(void(^)(UIView *footer, id _Nullable model)); 141 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^willDisplayFooterSEL)(SEL willDisplayFooterSEL); 142 | 143 | /** 144 | * If the header did end displaying, the `didEndDisplayingHeaderHandler` will be called. 145 | * 146 | * If the `didEndDisplayingHeaderSEL` property is nil or the header don't implement the `didEndDisplayingHeaderSEL` property setting method, then use the `didEndDisplayingHeaderHandler` property. 147 | */ 148 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^didEndDisplayingHeaderHandler)(void(^)(UIView *header, id _Nullable model)); 149 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^didEndDisplayingHeaderSEL)(SEL didEndDisplayingHeaderSEL); 150 | 151 | /** 152 | * If the footer did end displaying, the `didEndDisplayingFooterHandler` will be called. 153 | * 154 | * If the `didEndDisplayingFooterSEL` property is nil or the footer don't implement the `didEndDisplayingFooterSEL` property setting method, then use the `didEndDisplayingFooterHandler` property. 155 | */ 156 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^didEndDisplayingFooterHandler)(void(^)(UIView *footer, id _Nullable model)); 157 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^didEndDisplayingFooterSEL)(SEL didEndDisplayingFooterSEL); 158 | 159 | /** 160 | * Creates a HoloTableViewRowMaker in the callee for current UITableView. 161 | * Append these rows in the callee to current section. 162 | * 163 | * @param block Scope within which you can create some rows which you wish to apply to current UITableView. 164 | */ 165 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^makeRows)(void(NS_NOESCAPE ^)(HoloTableViewRowMaker *make)); 166 | 167 | /** 168 | * Creates a HoloTableViewUpdateRowMaker in the callee for current UITableView. 169 | * Update these rows in the callee for current section. 170 | * If current section don't contain these rows, ignore them. 171 | * 172 | * @param block Scope within which you can update some rows which you wish to apply to current UITableView. 173 | */ 174 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^updateRows)(void(NS_NOESCAPE ^)(HoloTableViewUpdateRowMaker *make)); 175 | 176 | /** 177 | * Creates a HoloTableViewUpdateRowMaker in the callee for current UITableView. 178 | * Re-create these rows in the callee for current section. 179 | * If current section don't contain these rows, ignore them. 180 | * 181 | * @param block Scope within which you can re-create some rows which you wish to apply to current UITableView. 182 | */ 183 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^remakeRows)(void(NS_NOESCAPE ^)(HoloTableViewUpdateRowMaker *make)); 184 | 185 | 186 | - (HoloTableSection *)fetchTableSection; 187 | 188 | - (void)giveTableSection:(HoloTableSection *)section; 189 | 190 | @end 191 | 192 | NS_ASSUME_NONNULL_END 193 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/Section/HoloTableSectionMaker.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableSectionMaker.m 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2020/6/2. 6 | // 7 | 8 | #import "HoloTableSectionMaker.h" 9 | #import "HoloTableSection.h" 10 | #import "HoloTableViewRowMaker.h" 11 | #import "HoloTableViewUpdateRowMaker.h" 12 | 13 | @interface HoloTableSectionMaker () 14 | 15 | @property (nonatomic, strong) HoloTableSection *section; 16 | 17 | @end 18 | 19 | @implementation HoloTableSectionMaker 20 | 21 | - (HoloTableSectionMaker * (^)(Class))header { 22 | return ^id(Class cls) { 23 | self.section.header = cls; 24 | return self; 25 | }; 26 | } 27 | 28 | - (HoloTableSectionMaker * (^)(Class))footer { 29 | return ^id(Class cls) { 30 | self.section.footer = cls; 31 | return self; 32 | }; 33 | } 34 | 35 | - (HoloTableSectionMaker *(^)(NSString *))headerReuseId { 36 | return ^id(id obj) { 37 | self.section.headerReuseId = obj; 38 | return self; 39 | }; 40 | } 41 | - (HoloTableSectionMaker * (^)(NSString * (^)(id)))headerReuseIdHandler { 42 | return ^id(id obj) { 43 | self.section.headerReuseIdHandler = obj; 44 | return self; 45 | }; 46 | } 47 | 48 | - (HoloTableSectionMaker *(^)(NSString *))footerReuseId { 49 | return ^id(id obj) { 50 | self.section.footerReuseId = obj; 51 | return self; 52 | }; 53 | } 54 | - (HoloTableSectionMaker * (^)(NSString * (^)(id)))footerReuseIdHandler { 55 | return ^id(id obj) { 56 | self.section.footerReuseIdHandler = obj; 57 | return self; 58 | }; 59 | } 60 | 61 | - (HoloTableSectionMaker *(^)(NSString *))headerTitle { 62 | return ^id(id obj) { 63 | self.section.headerTitle = obj; 64 | return self; 65 | }; 66 | } 67 | - (HoloTableSectionMaker * (^)(NSString * (^)(void)))headerTitleHandler { 68 | return ^id(id obj) { 69 | self.section.headerTitleHandler = obj; 70 | return self; 71 | }; 72 | } 73 | 74 | - (HoloTableSectionMaker *(^)(NSString *))footerTitle { 75 | return ^id(id obj) { 76 | self.section.footerTitle = obj; 77 | return self; 78 | }; 79 | } 80 | - (HoloTableSectionMaker * (^)(NSString * (^)(void)))footerTitleHandler { 81 | return ^id(id obj) { 82 | self.section.footerTitleHandler = obj; 83 | return self; 84 | }; 85 | } 86 | 87 | - (HoloTableSectionMaker * (^)(id))headerModel { 88 | return ^id(id obj) { 89 | self.section.headerModel = obj; 90 | return self; 91 | }; 92 | } 93 | - (HoloTableSectionMaker * (^)(id (^)(void)))headerModelHandler { 94 | return ^id(id obj) { 95 | self.section.headerModelHandler = obj; 96 | return self; 97 | }; 98 | } 99 | 100 | - (HoloTableSectionMaker * (^)(id))footerModel { 101 | return ^id(id obj) { 102 | self.section.footerModel = obj; 103 | return self; 104 | }; 105 | } 106 | - (HoloTableSectionMaker * (^)(id (^)(void)))footerModelHandler { 107 | return ^id(id obj) { 108 | self.section.footerModelHandler = obj; 109 | return self; 110 | }; 111 | } 112 | 113 | - (HoloTableSectionMaker *(^)(SEL))headerConfigSEL { 114 | return ^id(SEL s) { 115 | self.section.headerConfigSEL = s; 116 | return self; 117 | }; 118 | } 119 | 120 | - (HoloTableSectionMaker *(^)(SEL))footerConfigSEL { 121 | return ^id(SEL s) { 122 | self.section.footerConfigSEL = s; 123 | return self; 124 | }; 125 | } 126 | 127 | - (HoloTableSectionMaker *(^)(CGFloat))headerHeight { 128 | return ^id(CGFloat f) { 129 | self.section.headerHeight = f; 130 | return self; 131 | }; 132 | } 133 | - (HoloTableSectionMaker * (^)(CGFloat (^)(id)))headerHeightHandler { 134 | return ^id(id obj) { 135 | self.section.headerHeightHandler = obj; 136 | return self; 137 | }; 138 | } 139 | - (HoloTableSectionMaker *(^)(SEL))headerHeightSEL { 140 | return ^id(SEL s) { 141 | self.section.headerHeightSEL = s; 142 | return self; 143 | }; 144 | } 145 | 146 | - (HoloTableSectionMaker *(^)(CGFloat))footerHeight { 147 | return ^id(CGFloat f) { 148 | self.section.footerHeight = f; 149 | return self; 150 | }; 151 | } 152 | - (HoloTableSectionMaker * (^)(CGFloat (^)(id)))footerHeightHandler { 153 | return ^id(id obj) { 154 | self.section.footerHeightHandler = obj; 155 | return self; 156 | }; 157 | } 158 | - (HoloTableSectionMaker *(^)(SEL))footerHeightSEL { 159 | return ^id(SEL s) { 160 | self.section.footerHeightSEL = s; 161 | return self; 162 | }; 163 | } 164 | 165 | - (HoloTableSectionMaker *(^)(CGFloat))headerEstimatedHeight { 166 | return ^id(CGFloat f) { 167 | self.section.headerEstimatedHeight = f; 168 | return self; 169 | }; 170 | } 171 | - (HoloTableSectionMaker * (^)(CGFloat (^)(id)))headerEstimatedHeightHandler { 172 | return ^id(id obj) { 173 | self.section.headerEstimatedHeightHandler = obj; 174 | return self; 175 | }; 176 | } 177 | - (HoloTableSectionMaker *(^)(SEL))headerEstimatedHeightSEL { 178 | return ^id(SEL s) { 179 | self.section.headerEstimatedHeightSEL = s; 180 | return self; 181 | }; 182 | } 183 | 184 | - (HoloTableSectionMaker *(^)(CGFloat))footerEstimatedHeight { 185 | return ^id(CGFloat f) { 186 | self.section.footerEstimatedHeight = f; 187 | return self; 188 | }; 189 | } 190 | - (HoloTableSectionMaker * (^)(CGFloat (^)(id)))footerEstimatedHeightHandler { 191 | return ^id(id obj) { 192 | self.section.footerEstimatedHeightHandler = obj; 193 | return self; 194 | }; 195 | } 196 | - (HoloTableSectionMaker *(^)(SEL))footerEstimatedHeightSEL { 197 | return ^id(SEL s) { 198 | self.section.footerEstimatedHeightSEL = s; 199 | return self; 200 | }; 201 | } 202 | 203 | - (HoloTableSectionMaker *(^)(void (^)(UIView *, id)))willDisplayHeaderHandler { 204 | return ^id(id obj) { 205 | self.section.willDisplayHeaderHandler = obj; 206 | return self; 207 | }; 208 | } 209 | - (HoloTableSectionMaker *(^)(SEL))willDisplayHeaderSEL { 210 | return ^id(SEL s) { 211 | self.section.willDisplayHeaderSEL = s; 212 | return self; 213 | }; 214 | } 215 | 216 | - (HoloTableSectionMaker *(^)(void (^)(UIView *, id)))willDisplayFooterHandler { 217 | return ^id(id obj) { 218 | self.section.willDisplayFooterHandler = obj; 219 | return self; 220 | }; 221 | } 222 | - (HoloTableSectionMaker *(^)(SEL))willDisplayFooterSEL { 223 | return ^id(SEL s) { 224 | self.section.willDisplayFooterSEL = s; 225 | return self; 226 | }; 227 | } 228 | 229 | - (HoloTableSectionMaker *(^)(void (^)(UIView *, id)))didEndDisplayingHeaderHandler { 230 | return ^id(id obj) { 231 | self.section.didEndDisplayingHeaderHandler = obj; 232 | return self; 233 | }; 234 | } 235 | - (HoloTableSectionMaker *(^)(SEL))didEndDisplayingHeaderSEL { 236 | return ^id(SEL s) { 237 | self.section.didEndDisplayingHeaderSEL = s; 238 | return self; 239 | }; 240 | } 241 | 242 | - (HoloTableSectionMaker *(^)(void (^)(UIView *, id)))didEndDisplayingFooterHandler { 243 | return ^id(id obj) { 244 | self.section.didEndDisplayingFooterHandler = obj; 245 | return self; 246 | }; 247 | } 248 | - (HoloTableSectionMaker *(^)(SEL))didEndDisplayingFooterSEL { 249 | return ^id(SEL s) { 250 | self.section.didEndDisplayingFooterSEL = s; 251 | return self; 252 | }; 253 | } 254 | 255 | 256 | - (HoloTableSectionMaker * (^)(void (NS_NOESCAPE ^)(HoloTableViewRowMaker *)))makeRows { 257 | return ^id(void(^block)(HoloTableViewRowMaker *make)) { 258 | HoloTableViewRowMaker *maker = [HoloTableViewRowMaker new]; 259 | if (block) block(maker); 260 | 261 | NSMutableArray *array = [NSMutableArray arrayWithArray:self.section.rows]; 262 | [array addObjectsFromArray:[maker install]]; 263 | self.section.rows = array.copy; 264 | return self; 265 | }; 266 | } 267 | 268 | - (HoloTableSectionMaker * (^)(void (NS_NOESCAPE ^)(HoloTableViewUpdateRowMaker *)))updateRows { 269 | return ^id(void(^block)(HoloTableViewUpdateRowMaker *make)) { 270 | HoloTableViewUpdateRowMaker *maker = [[HoloTableViewUpdateRowMaker alloc] initWithProxyDataSections:@[self.section] 271 | makerType:HoloTableViewUpdateRowMakerTypeUpdate 272 | targetSection:NO 273 | sectionTag:nil]; 274 | if (block) block(maker); 275 | 276 | return self; 277 | }; 278 | } 279 | 280 | - (HoloTableSectionMaker * (^)(void (NS_NOESCAPE ^)(HoloTableViewUpdateRowMaker *)))remakeRows { 281 | return ^id(void(^block)(HoloTableViewUpdateRowMaker *make)) { 282 | HoloTableViewUpdateRowMaker *maker = [[HoloTableViewUpdateRowMaker alloc] initWithProxyDataSections:@[self.section] 283 | makerType:HoloTableViewUpdateRowMakerTypeRemake 284 | targetSection:NO 285 | sectionTag:nil]; 286 | if (block) block(maker); 287 | 288 | return self; 289 | }; 290 | } 291 | 292 | 293 | - (HoloTableSection *)fetchTableSection { 294 | return self.section; 295 | } 296 | 297 | - (void)giveTableSection:(HoloTableSection *)section { 298 | self.section = section; 299 | } 300 | 301 | #pragma mark - getter 302 | - (HoloTableSection *)section { 303 | if (!_section) { 304 | _section = [HoloTableSection new]; 305 | } 306 | return _section; 307 | } 308 | 309 | @end 310 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/Section/HoloTableViewSectionMaker.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewSectionMaker.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/7/28. 6 | // 7 | 8 | #import 9 | @class HoloTableSection, HoloTableSectionMaker; 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef NS_ENUM(NSInteger, HoloTableViewSectionMakerType) { 14 | HoloTableViewSectionMakerTypeMake, 15 | HoloTableViewSectionMakerTypeInsert, 16 | HoloTableViewSectionMakerTypeUpdate, 17 | HoloTableViewSectionMakerTypeRemake 18 | }; 19 | 20 | 21 | @interface HoloTableViewSectionMakerModel : NSObject 22 | 23 | @property (nonatomic, strong, nullable) HoloTableSection *operateSection; 24 | 25 | @property (nonatomic, strong, nullable) NSNumber *operateIndex; 26 | 27 | @end 28 | 29 | 30 | @interface HoloTableViewSectionMaker : NSObject 31 | 32 | /** 33 | * Make a HoloTableSection object and set the section tag. 34 | */ 35 | @property (nonatomic, copy, readonly) HoloTableSectionMaker *(^section)(NSString *tag); 36 | 37 | - (instancetype)initWithProxyDataSections:(NSArray *)sections 38 | makerType:(HoloTableViewSectionMakerType)makerType; 39 | 40 | - (NSArray *)install; 41 | 42 | @end 43 | 44 | NS_ASSUME_NONNULL_END 45 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/Section/HoloTableViewSectionMaker.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewSectionMaker.m 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/7/28. 6 | // 7 | 8 | #import "HoloTableViewSectionMaker.h" 9 | #import "HoloTableSection.h" 10 | #import "HoloTableSectionMaker.h" 11 | 12 | @implementation HoloTableViewSectionMakerModel 13 | 14 | @end 15 | 16 | 17 | @interface HoloTableViewSectionMaker () 18 | 19 | @property (nonatomic, copy) NSArray *dataSections; 20 | 21 | @property (nonatomic, assign) HoloTableViewSectionMakerType makerType; 22 | 23 | @property (nonatomic, strong) NSMutableArray *makerModels; 24 | 25 | @end 26 | 27 | @implementation HoloTableViewSectionMaker 28 | 29 | - (instancetype)initWithProxyDataSections:(NSArray *)sections 30 | makerType:(HoloTableViewSectionMakerType)makerType { 31 | self = [super init]; 32 | if (self) { 33 | _dataSections = sections; 34 | _makerType = makerType; 35 | } 36 | return self; 37 | } 38 | 39 | - (HoloTableSectionMaker *(^)(NSString *))section { 40 | return ^id(NSString *tag) { 41 | HoloTableSectionMaker *sectionMaker = [HoloTableSectionMaker new]; 42 | HoloTableSection *makerSection = [sectionMaker fetchTableSection]; 43 | makerSection.tag = tag; 44 | 45 | __block NSNumber *operateIndex = nil; 46 | if (self.makerType == HoloTableViewSectionMakerTypeUpdate || self.makerType == HoloTableViewSectionMakerTypeRemake) { 47 | [self.dataSections enumerateObjectsUsingBlock:^(HoloTableSection * _Nonnull section, NSUInteger idx, BOOL * _Nonnull stop) { 48 | if ([section.tag isEqualToString:tag] || (!section.tag && !tag)) { 49 | operateIndex = @(idx); 50 | 51 | if (self.makerType == HoloTableViewSectionMakerTypeUpdate) { 52 | // update: set the row object to maker from datasource 53 | [sectionMaker giveTableSection:section]; 54 | } 55 | 56 | *stop = YES; 57 | } 58 | }]; 59 | } 60 | 61 | HoloTableViewSectionMakerModel *makerModel = [HoloTableViewSectionMakerModel new]; 62 | makerModel.operateSection = [sectionMaker fetchTableSection]; 63 | makerModel.operateIndex = operateIndex; 64 | [self.makerModels addObject:makerModel]; 65 | 66 | return sectionMaker; 67 | }; 68 | } 69 | 70 | - (NSArray *)install { 71 | return self.makerModels.copy; 72 | } 73 | 74 | #pragma mark - getter 75 | - (NSMutableArray *)makerModels { 76 | if (!_makerModels) { 77 | _makerModels = [NSMutableArray new]; 78 | } 79 | return _makerModels; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/TableView/HoloTableViewMaker.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewMaker.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2020/1/30. 6 | // 7 | 8 | #import 9 | #import "HoloTableViewProtocol.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef NSInteger (^HoloTableViewSectionForSectionIndexTitleHandler)(NSString *title, NSInteger index); 14 | 15 | 16 | @interface HoloTableViewModel : NSObject 17 | 18 | @property (nonatomic, copy, nullable) NSArray *indexTitles; 19 | 20 | @property (nonatomic, copy, nullable) HoloTableViewSectionForSectionIndexTitleHandler indexTitlesHandler; 21 | 22 | @property (nonatomic, weak, nullable) id delegate; 23 | 24 | @property (nonatomic, weak, nullable) id dataSource; 25 | 26 | @property (nonatomic, weak, nullable) id scrollDelegate; 27 | 28 | @end 29 | 30 | 31 | @interface HoloTableViewMaker : NSObject 32 | 33 | /** 34 | * Return list of section titles to display in section index view (e.g. "ABCD...Z#"). 35 | */ 36 | @property (nonatomic, copy, readonly) HoloTableViewMaker *(^sectionIndexTitles)(NSArray *sectionIndexTitles); 37 | 38 | /** 39 | * Tell table which section corresponds to section title/index (e.g. "B",1)). 40 | */ 41 | @property (nonatomic, copy, readonly) HoloTableViewMaker *(^sectionForSectionIndexTitleHandler)(NSInteger (^handler)(NSString *title, NSInteger index)); 42 | 43 | /** 44 | * The delegate of the scroll-view object. 45 | */ 46 | @property (nonatomic, copy, readonly) HoloTableViewMaker *(^scrollDelegate)(id scrollDelegate); 47 | 48 | @property (nonatomic, copy, readonly) HoloTableViewMaker *(^delegate)(id delegate); 49 | 50 | @property (nonatomic, copy, readonly) HoloTableViewMaker *(^dataSource)(id dataSource); 51 | 52 | - (HoloTableViewModel *)install; 53 | 54 | @end 55 | 56 | NS_ASSUME_NONNULL_END 57 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/TableView/HoloTableViewMaker.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewMaker.m 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2020/1/30. 6 | // 7 | 8 | #import "HoloTableViewMaker.h" 9 | 10 | @implementation HoloTableViewModel 11 | 12 | @end 13 | 14 | 15 | @interface HoloTableViewMaker () 16 | 17 | @property (nonatomic, strong) HoloTableViewModel *tableViewModel; 18 | 19 | @end 20 | 21 | @implementation HoloTableViewMaker 22 | 23 | - (HoloTableViewMaker * (^)(NSArray *))sectionIndexTitles { 24 | return ^id(id obj) { 25 | self.tableViewModel.indexTitles = obj; 26 | return self; 27 | }; 28 | } 29 | 30 | - (HoloTableViewMaker * (^)(NSInteger (^)(NSString *, NSInteger)))sectionForSectionIndexTitleHandler { 31 | return ^id(id obj) { 32 | self.tableViewModel.indexTitlesHandler = obj; 33 | return self; 34 | }; 35 | } 36 | 37 | - (HoloTableViewMaker * (^)(id))scrollDelegate { 38 | return ^id(id obj) { 39 | self.tableViewModel.scrollDelegate = obj; 40 | return self; 41 | }; 42 | } 43 | 44 | - (HoloTableViewMaker * (^)(id))delegate { 45 | return ^id(id obj) { 46 | self.tableViewModel.delegate = obj; 47 | return self; 48 | }; 49 | } 50 | 51 | - (HoloTableViewMaker * (^)(id))dataSource { 52 | return ^id(id obj) { 53 | self.tableViewModel.dataSource = obj; 54 | return self; 55 | }; 56 | } 57 | 58 | - (HoloTableViewModel *)install { 59 | return self.tableViewModel; 60 | } 61 | 62 | #pragma mark - getter 63 | - (HoloTableViewModel *)tableViewModel { 64 | if (!_tableViewModel) { 65 | _tableViewModel = [HoloTableViewModel new]; 66 | } 67 | return _tableViewModel; 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/Update/HoloTableViewUpdateRowMaker.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewUpdateRowMaker.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/7/29. 6 | // 7 | 8 | #import 9 | @class HoloTableRow, HoloTableRowMaker, HoloTableSection; 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef NS_ENUM(NSInteger, HoloTableViewUpdateRowMakerType) { 14 | HoloTableViewUpdateRowMakerTypeUpdate, 15 | HoloTableViewUpdateRowMakerTypeRemake 16 | }; 17 | 18 | @interface HoloTableViewUpdateRowMaker : NSObject 19 | 20 | /** 21 | * Fetch a HoloTableRow object with the tag. 22 | */ 23 | @property (nonatomic, copy, readonly) HoloTableRowMaker *(^tag)(NSString *tag); 24 | 25 | - (instancetype)initWithProxyDataSections:(NSArray *)sections 26 | makerType:(HoloTableViewUpdateRowMakerType)makerType 27 | targetSection:(BOOL)targetSection 28 | sectionTag:(NSString * _Nullable)sectionTag; 29 | 30 | - (NSArray *)install; 31 | 32 | @end 33 | 34 | NS_ASSUME_NONNULL_END 35 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Maker/Update/HoloTableViewUpdateRowMaker.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoloTableViewUpdateRowMaker.m 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/7/29. 6 | // 7 | 8 | #import "HoloTableViewUpdateRowMaker.h" 9 | #import "HoloTableRow.h" 10 | #import "HoloTableRowMaker.h" 11 | #import "HoloTableSection.h" 12 | #import "HoloTableViewMacro.h" 13 | 14 | @interface HoloTableViewUpdateRowMaker () 15 | 16 | @property (nonatomic, copy) NSArray *dataSections; 17 | 18 | @property (nonatomic, assign) HoloTableViewUpdateRowMakerType makerType; 19 | 20 | @property (nonatomic, strong) NSMutableArray *updateIndexPaths; 21 | 22 | // has target section or not 23 | @property (nonatomic, assign) BOOL targetSection; 24 | // target section tag 25 | @property (nonatomic, copy) NSString *sectionTag; 26 | 27 | @end 28 | 29 | @implementation HoloTableViewUpdateRowMaker 30 | 31 | - (instancetype)initWithProxyDataSections:(NSArray *)sections 32 | makerType:(HoloTableViewUpdateRowMakerType)makerType 33 | targetSection:(BOOL)targetSection 34 | sectionTag:(NSString * _Nullable)sectionTag { 35 | self = [super init]; 36 | if (self) { 37 | _dataSections = sections; 38 | _makerType = makerType; 39 | _targetSection = targetSection; 40 | _sectionTag = sectionTag; 41 | } 42 | return self; 43 | } 44 | 45 | - (HoloTableRowMaker *(^)(NSString *))tag { 46 | return ^id(NSString *tag) { 47 | HoloTableRowMaker *rowMaker = [HoloTableRowMaker new]; 48 | HoloTableRow *makerRow = [rowMaker fetchTableRow]; 49 | makerRow.tag = tag; 50 | 51 | __block NSIndexPath *operateIndexPath = nil; 52 | [self.dataSections enumerateObjectsUsingBlock:^(HoloTableSection * _Nonnull section, NSUInteger sectionIdx, BOOL * _Nonnull sectionStop) { 53 | if (self.targetSection && !([section.tag isEqualToString:self.sectionTag] || (!section.tag && !self.sectionTag))) { 54 | return; 55 | } 56 | [section.rows enumerateObjectsUsingBlock:^(HoloTableRow * _Nonnull row, NSUInteger rowIdx, BOOL * _Nonnull rowStop) { 57 | if ([row.tag isEqualToString:tag] || (!row.tag && !tag)) { 58 | operateIndexPath = [NSIndexPath indexPathForRow:rowIdx inSection:sectionIdx]; 59 | 60 | if (self.makerType == HoloTableViewUpdateRowMakerTypeUpdate) { 61 | // update: set the row object to maker from datasource 62 | [rowMaker giveTableRow:row]; 63 | } else if (self.makerType == HoloTableViewUpdateRowMakerTypeRemake) { 64 | // remake: set the row object to datasource from maker 65 | NSMutableArray *rows = [NSMutableArray arrayWithArray:section.rows]; 66 | [rows replaceObjectAtIndex:operateIndexPath.row withObject:makerRow]; 67 | section.rows = rows.copy; 68 | } 69 | 70 | *rowStop = YES; 71 | *sectionStop = YES; 72 | } 73 | }]; 74 | }]; 75 | 76 | if (operateIndexPath) { 77 | [self.updateIndexPaths addObject:operateIndexPath]; 78 | } else { 79 | HoloLog(@"[HoloTableView] No row found with the tag: `%@`.", tag); 80 | } 81 | 82 | return rowMaker; 83 | }; 84 | } 85 | 86 | - (NSArray *)install { 87 | return self.updateIndexPaths.copy; 88 | } 89 | 90 | #pragma mark - getter 91 | - (NSMutableArray *)updateIndexPaths { 92 | if (!_updateIndexPaths) { 93 | _updateIndexPaths = [NSMutableArray new]; 94 | } 95 | return _updateIndexPaths; 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Responder Event/UIResponder+HoloEvent.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIResponder+HoloEvent.h 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/8/24. 6 | // 7 | 8 | #import 9 | 10 | @interface UIResponder (HoloEvent) 11 | 12 | - (void)holo_event:(NSString *)event params:(NSDictionary *)params; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /HoloTableView/Classes/Responder Event/UIResponder+HoloEvent.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIResponder+HoloEvent.m 3 | // HoloTableView 4 | // 5 | // Created by 与佳期 on 2019/8/24. 6 | // 7 | 8 | #import "UIResponder+HoloEvent.h" 9 | 10 | @implementation UIResponder (HoloEvent) 11 | 12 | - (void)holo_event:(NSString *)event params:(NSDictionary *)params { 13 | [self.nextResponder holo_event:event params:params]; 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 gonghonglou 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HoloTableView 2 | 3 | [![CI Status](https://img.shields.io/travis/HoloFoundation/HoloTableView.svg?style=flat)](https://travis-ci.org/HoloFoundation/HoloTableView) 4 | [![Version](https://img.shields.io/cocoapods/v/HoloTableView.svg?style=flat)](https://cocoapods.org/pods/HoloTableView) 5 | [![License](https://img.shields.io/cocoapods/l/HoloTableView.svg?style=flat)](https://cocoapods.org/pods/HoloTableView) 6 | [![Platform](https://img.shields.io/cocoapods/p/HoloTableView.svg?style=flat)](https://cocoapods.org/pods/HoloTableView) 7 | 8 | 9 | `HoloTableView` provides chained syntax calls that encapsulate delegate methods for `UITableView`. The delegate methods for `UITableView` are distributed to each `cell`, each `cell` having its own method for setting Class, model, height, and click event, etc. 10 | 11 | 12 | ## Features 13 | 14 | - [x] Provide section and row maker to handle proxy events of `UITableVIew`. 15 | - [x] Provide protocols, implemented in cells, headers and footers to handle proxy events of `UITableVIew`. 16 | - [x] Provide left-slide and right-slide actions for `cell`. 17 | - [x] Passing events through the responder chain. 18 | - [x] [HoloTableViewMGPlugin](https://github.com/HoloFoundation/HoloTableViewMGPlugin) to support `MGSwipeTableCell`, add swip actions for `cell`. 19 | - [x] Diff reload data. [HoloTableViewDiffPlugin](https://github.com/HoloFoundation/HoloTableViewDiffPlugin) to support `DeepDiff` 20 | - [x] Support to reload a table view by setting datasource with `HoloTableSection` and `HoloTableRow`. 21 | - [ ] Modern Objective-C and better Swift support. 22 | 23 | 24 | ## Example 25 | 26 | To run the example project, clone the repo, and run `pod install` from the Example directory first. 27 | 28 | 29 | ## Integration with 3rd party libraries 30 | 31 | - [HoloTableViewMGPlugin](https://github.com/HoloFoundation/HoloTableViewMGPlugin) - plugin to support [MGSwipeTableCell](https://github.com/MortimerGoro/MGSwipeTableCell), add swip actions for `cell`. `MGSwipeTableCell` is an easy to use `UITableViewCell` subclass that allows to display swipeable buttons with a variety of transitions. 32 | - [HoloTableViewDiffPlugin](https://github.com/HoloFoundation/HoloTableViewDiffPlugin) - plugin to support [DeepDiff](https://github.com/onmyway133/DeepDiff), diff reload a section of `UITableView`. `DeepDiff` tells the difference between 2 collections and the changes as edit steps. 33 | 34 | ## Usage 35 | 36 | [中文介绍](https://github.com/HoloFoundation/HoloTableView/blob/master/README_CN.md)、[文章介绍](http://gonghonglou.com/2020/08/10/HoloTableView-HoloCollectionView/) 37 | 38 | ### 1. Make a simple cell list 39 | 40 | ```objc 41 | UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 42 | [self.view addSubview:tableView]; 43 | 44 | [tableView holo_makeRows:^(HoloTableViewRowMaker * _Nonnull make) { 45 | // make a cell 46 | make.row(ExampleTableViewCell.class).model(NSDictionary.new).height(44); 47 | 48 | // make a list 49 | for (NSObject *obj in NSArray.new) { 50 | make.row(ExampleTableViewCell.class).model(obj).didSelectHandler(^(id _Nullable model) { 51 | NSLog(@"did select row : %@", model); 52 | }); 53 | } 54 | }]; 55 | 56 | [tableView reloadData]; 57 | 58 | // etc. 59 | ``` 60 | 61 | The `holo_makeRows:` method is used to create a list of rows **with a default section**. Each `row` is a `cell`. **More properties provided for row see: [HoloTableViewRowMaker.h](https://github.com/HoloFoundation/HoloTableView/blob/master/HoloTableView/Classes/Maker/Row/HoloTableViewRowMaker.h) and [HoloTableRowMaker.h](https://github.com/HoloFoundation/HoloTableView/blob/master/HoloTableView/Classes/Maker/Row/HoloTableRowMaker.h)** 62 | 63 | 64 | #### Requirements for cell 65 | 66 | Conforms to protocol `HoloTableViewCellProtocol`, `HoloTableView` will automatically identify `cell` whether implement these methods and calls, the commonly used two methods: 67 | 68 | ```objc 69 | @required 70 | 71 | // set the model to cell 72 | // the model is the object passed in by make.model() 73 | - (void)holo_configureCellWithModel:(id)model; 74 | 75 | 76 | @optional 77 | 78 | // return cell height( Priority is higher than: 'heightHandler' and 'height' of maker) 79 | // the model is the object passed in by make.model() 80 | + (CGFloat)holo_heightForCellWithModel:(id)model; 81 | ``` 82 | 83 | **See `HoloTableViewCellProtocol` more methods: [HoloTableViewCellProtocol](https://github.com/HoloFoundation/HoloTableView/blob/master/HoloTableView/Classes/Core/Protocol/HoloTableViewCellProtocol.h)** 84 | 85 | You can also call your own methods by configuring properties such as `configSEL`, `heightSEL`, etc. More properties can find in [HoloTableRowMaker.h](https://github.com/HoloFoundation/HoloTableView/blob/master/HoloTableView/Classes/Maker/Row/HoloTableRowMaker.h). 86 | 87 | Note that attributes such as `height`, `estimatedHeight`, etc. that exist `SEL` have priority: 88 | 1. First judge whether `cell` implements `heightSEL` method 89 | 2. Secondly, verify the implementation of the `heightHandler` block 90 | 3. Finally, determine whether the property `height` is assigned 91 | 92 | 93 | ### 2. Make a section list (contain header, footer, row) 94 | 95 | ```objc 96 | UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 97 | [self.view addSubview:tableView]; 98 | 99 | [tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 100 | make.section(TAG) 101 | .header(ExampleHeaderView.class) 102 | .headerModel(NSDictionary.new) 103 | .footer(ExampleFooterView.class) 104 | .footerModel(NSDictionary.new) 105 | .makeRows(^(HoloTableViewRowMaker * _Nonnull make) { 106 | // make a cell 107 | make.row(ExampleTableViewCell.class).model(NSDictionary.new).height(44); 108 | 109 | // make a list 110 | for (NSObject *obj in NSArray.new) { 111 | make.row(ExampleTableViewCell.class).model(obj).didSelectHandler(^(id _Nullable model) { 112 | NSLog(@"did select row : %@", model); 113 | }); 114 | } 115 | }); 116 | }]; 117 | 118 | [tableView reloadData]; 119 | ``` 120 | 121 | The `holo_makeSections:` method is used to create a list of `section`. **More properties provided for section see: [HoloTableViewSectionMaker.h](https://github.com/HoloFoundation/HoloTableView/blob/master/HoloTableView/Classes/Maker/Section/HoloTableViewSectionMaker.h) and [HoloTableSectionMaker.h](https://github.com/HoloFoundation/HoloTableView/blob/master/HoloTableView/Classes/Maker/Section/HoloTableSectionMaker.h)** 122 | 123 | 124 | #### Requirements for header and footer 125 | 126 | 1. header: conforms to protocol `HoloTableViewHeaderProtocol` , implement these methods, the commonly used two methods: 127 | 128 | ```objc 129 | @required 130 | 131 | // set the model to header 132 | // the model is the object passed in by make.headerModel() 133 | - (void)holo_configureHeaderWithModel:(id)model; 134 | 135 | @optional 136 | 137 | // return header height( Priority is higher than: 'headerHeightHandler' and 'headerHeight' of maker) 138 | // the model is the object passed in by make.headerModel() 139 | + (CGFloat)holo_heightForHeaderWithModel:(id)model; 140 | ``` 141 | 142 | 2. Footer: conforms to protocol `HoloTableViewFooterProtocol` , implement these methods, the commonly used two methods: 143 | 144 | ```objc 145 | @required 146 | 147 | // set the model to footer 148 | // the model is the object passed in by make.footerModel() 149 | - (void)holo_configureFooterWithModel:(id)model; 150 | 151 | @optional 152 | 153 | // return footer height( Priority is higher than: 'footerHeightHandler' and 'footerHeight' of maker) 154 | // the model is the object passed in by make.footerModel() 155 | + (CGFloat)holo_heightForFooterWithModel:(id)model; 156 | ``` 157 | 158 | **See `HoloTableViewHeaderProtocol` and `HoloTableViewFooterProtocol` more methods: [HoloTableViewHeaderProtocol](https://github.com/HoloFoundation/HoloTableView/blob/master/HoloTableView/Classes/Core/Protocol/HoloTableViewHeaderProtocol.h) and [HoloTableViewFooterProtocol](https://github.com/HoloFoundation/HoloTableView/blob/master/HoloTableView/Classes/Core/Protocol/HoloTableViewFooterProtocol.h)** 159 | 160 | You can also call your own methods by configuring properties such as `headerConfigSEL`, `footerConfigSEL`, etc. More properties can find in [HoloTableSectionMaker.h](https://github.com/HoloFoundation/HoloTableView/blob/master/HoloTableView/Classes/Maker/Section/HoloTableSectionMaker.h). 161 | 162 | Like `cell`, properties that contain `SEL` also have a priority. 163 | 164 | 165 | ### 3. Methods for section 166 | 167 | ```objc 168 | // adding 169 | [self.tableView holo_makeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 170 | make.section(TAG); 171 | }]; 172 | 173 | // inserting at index 174 | [self.tableView holo_insertSectionsAtIndex:0 block:^(HoloTableViewSectionMaker * _Nonnull make) { 175 | make.section(TAG); 176 | }]; 177 | 178 | // updating with tag value by maker 179 | [self.tableView holo_updateSections:^(HoloTableViewSectionMaker * _Nonnull make) { 180 | make.section(TAG); 181 | }]; 182 | 183 | // resetting with tag value by maker 184 | [self.tableView holo_remakeSections:^(HoloTableViewSectionMaker * _Nonnull make) { 185 | make.section(TAG); 186 | }]; 187 | 188 | // deleting 189 | [self.tableView holo_removeAllSections]; 190 | 191 | // deleting with tag value 192 | [self.tableView holo_removeSections:@[TAG]]; 193 | 194 | 195 | // reloadData 196 | [self.tableView reloadData]; 197 | ``` 198 | 199 | `UITableView+HoloTableView.h` provides a series of methods for manipulating `sections`, including adding, inserting, updating, resetting, deleting, etc. 200 | **More methods provided for section see: [UITableView+HoloTableView.h (about section)](https://github.com/HoloFoundation/HoloTableView/blob/master/HoloTableView/Classes/Maker/UITableView%2BHoloTableView.h#L24-L144)** 201 | 202 | 203 | ### 4. Methods for row 204 | 205 | ```objc 206 | // adding 207 | [self.tableView holo_makeRows:^(HoloTableViewRowMaker * _Nonnull make) { 208 | make.row(ExampleTableViewCell.class); 209 | }]; 210 | 211 | // adding to section with tag value 212 | [self.tableView holo_makeRowsInSection:TAG block:^(HoloTableViewRowMaker * _Nonnull make) { 213 | make.row(ExampleTableViewCell.class); 214 | }]; 215 | 216 | // inserting at index 217 | [self.tableView holo_insertRowsAtIndex:0 block:^(HoloTableViewRowMaker * _Nonnull make) { 218 | make.row(ExampleTableViewCell.class); 219 | }]; 220 | 221 | // inserting at index to section with tag value 222 | [self.tableView holo_insertRowsAtIndex:0 inSection:TAG block:^(HoloTableViewRowMaker * _Nonnull make) { 223 | make.row(ExampleTableViewCell.class); 224 | }]; 225 | 226 | // updating 227 | [self.tableView holo_updateRows:^(HoloTableViewUpdateRowMaker * _Nonnull make) { 228 | make.tag(TAG).height(120); 229 | }]; 230 | 231 | // resetting 232 | [self.tableView holo_remakeRows:^(HoloTableViewUpdateRowMaker * _Nonnull make) { 233 | make.tag(TAG).model(NSDictionary.new).height(120); 234 | }]; 235 | 236 | // deleting 237 | [self.tableView holo_removeAllRowsInSections:@[TAG]]; 238 | 239 | // deleting 240 | [self.tableView holo_removeRows:@[TAG]]; 241 | 242 | 243 | // reloadData 244 | [self.tableView reloadData]; 245 | ``` 246 | 247 | `UITableView+HoloTableView.h` provides a series of methods for manipulating rows, including adding, inserting, updating, resetting, deleting, etc. 248 | **More methods provided for row see: [UITableView+HoloTableView.h (about row)](https://github.com/HoloFoundation/HoloTableView/blob/master/HoloTableView/Classes/Maker/UITableView%2BHoloTableView.h#L146-L328)** 249 | 250 | 251 | ### 5. Retrieve Delegate 252 | 253 | You can retrieve the delegate of `UITableView` at any time, such as: 254 | 255 | ```objc 256 | // first way 257 | self.tableView.holo_proxy.dataSource = self; 258 | self.tableView.holo_proxy.delegate = self; 259 | self.tableView.holo_proxy.scrollDelegate = self; 260 | 261 | // second way 262 | [self.tableView holo_makeTableView:^(HoloTableViewMaker * _Nonnull make) { 263 | make.dataSource(self).delegate(self).scrollDelegate(self); 264 | }]; 265 | ``` 266 | 267 | Once you set up `dataSource`, `delegate`, `scrollDelegate` and implement some of their methods, `HoloTableView` will use your methods and return values first. For specific logic, please refer to: [HoloTableViewProxy.m](https://github.com/HoloFoundation/HoloTableView/blob/master/HoloTableView/Classes/Core/HoloTableViewProxy.m) 268 | 269 | ### 6. Reload a table view by setting datasource with `HoloTableSection` and `HoloTableRow` 270 | 271 | Make a section list with `HoloTableSection` and `HoloTableRow`: 272 | 273 | ```objc 274 | HoloTableSection *section = [HoloTableSection new]; 275 | section.tag = TAG; 276 | 277 | section.header = ExampleHeaderView.class; 278 | section.headerModel = @{@"title":@"header"}; 279 | 280 | section.footer = ExampleFooterView.class; 281 | section.footerModel = @{@"title":@"footer"}; 282 | section.footerHeight = 100; 283 | 284 | NSMutableArray *rows = [NSMutableArray new]; 285 | for (NSDictionary *dict in self.modelArray) { 286 | HoloTableRow *row = [HoloTableRow new]; 287 | row.cell = ExampleTableViewCell.class; 288 | row.model = dict; 289 | [rows addObject:row]; 290 | } 291 | section.rows = rows; 292 | 293 | self.tableView.holo_sections = @[section]; 294 | [self.tableView reloadData]; 295 | ``` 296 | 297 | 298 | ## Installation 299 | 300 | HoloTableView is available through [CocoaPods](https://cocoapods.org). To install 301 | it, simply add the following line to your Podfile: 302 | 303 | ```ruby 304 | pod 'HoloTableView' 305 | ``` 306 | 307 | ## Author 308 | 309 | gonghonglou, gonghonglou@icloud.com 310 | 311 | ## License 312 | 313 | HoloTableView is available under the MIT license. See the LICENSE file for more info. 314 | 315 | 316 | --------------------------------------------------------------------------------