https://github.com/melvin7/MYTableViewManager
https://github.com/TimeFaceCoder/TFTableViewDataSource
TFTableViewDataSource 包含以下幾個基本類
- TFTableViewDataSourceConfig : 用于配置列表數據獲取接口,處理函數,分頁記錄數等
- TFTableViewDataSource : TableView數據源處理類,通過繼承TFTableViewDataSource 可以重載下拉刷新,列表展示等方法來實現自定義
- TFTableViewDataManager 列表數據處理工具,所有的列表數據處理都需要繼承TFTableViewDataManager來處理
- TFTableViewItem 單行列表數據源與事件處理類,所有的列表數據源都需要繼承TFTableViewItem來處理
- TFTableViewItemCell 單行列表UI,所有的列表UI都需要繼承TFTableViewItemCell來處理
1、回頭看看,這框架還是很模糊啊;
DCSwitchTableViewItem
處理item點擊事件有,onViewClickHandler,selectionHandler等;
2、DCManegerDataManeger,
TFTableViewDataManager初始化時initWithDataSource,會設置下_cellViewClickHandler;會先處理代理VC的事件
if ([strongSelf.tableViewDataSource.delegate respondsToSelector:@selector(actionOnView:actionType:)])
3、tableView Cell 響應事件;
DCManagerTableViewItem setSelectionHandler:)
tableView:didSelectRowAtIndexPath:
調用 MYTableViewItem 的 selectionHandler
TFTableViewItem : MYTableViewItem
單行列表數據源和事件處理類; 所有的列表數據源都要繼承TFTableViewItem
來處理;
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
__weak typeof(self) weakself = self;
self.selectionHandler = ^(id item){
if (weakself.onViewClickHandler) {
weakself.onViewClickHandler(item, -1);
}
};
return self;
}
在TFTableViewItem的init
方法中初始化了父類MYTableViewItem的selectionHandler;
里面調用自己的屬性onViewClickHandler;而其初始化在temWithModel:clickHandler:中;
@property (nonatomic ,copy) void (^onViewClickHandler)(TFTableViewItem *item,NSInteger actionType);
???selectionHandler、onViewClickHandler在哪里調用的;
TFTableViewItemCell : MYTableViewCell
單行列表UI,所有的列表UI都繼承自TFTableViewItemCell
來處理;
沒有code, 主要看其父類MYTableViewCell : ASCellNode
- (instancetype)initWithTableViewItem:(MYTableViewItem *)tableViewItem {
self = [super init];
if(self) {
self.tableViewItem = tableViewItem;
// hairline cell separator
if (self.tableViewItem.separatorStyle != UITableViewCellSeparatorStyleNone) {
_dividerNode = [[ASDisplayNode alloc] init];
_dividerNode.backgroundColor = self.tableViewItem.dividerColor;
[self addSubnode:_dividerNode];
}
[self initCell];
}
return self;
}
MYTableViewCell繼承自ASCellNode;整體基于ASTableView實現;
在initWithTableViewItem方法中設置列表數據源self.tableViewItem;調用initCell方法;
所以在我們自定義的cell中,在initCell中初始化UI;
ASDisplayKit中layout相當于layoutSubviews;重新布局;分為自動布局、手動布局;
TFTableViewDataManager : NSObject<TFTableViewDataManagerProtocol>
列表數據處理工具,所有的列表數據處理都需要繼承TFTableViewDataManager
來處理;
管理類,管理cell數據源item,cell的UI-cell;
@interface TFTableViewDataManager : NSObject<TFTableViewDataManagerProtocol>
@property (nonatomic ,weak) TFTableViewDataSource *tableViewDataSource;
/**
* 列表內點擊事件 block
*/
@property (nonatomic ,copy) CellViewClickHandler cellViewClickHandler;
/**
* 列表刪除事件 block
*/
@property (nonatomic ,copy) DeletionHandlerWithCompletion deleteHanlder;
/**
* 當前cell的索引indexPath
*/
@property (nonatomic ,strong) NSIndexPath *currentIndexPath;
/**
* 對應的listType,綁定url
*/
@property (nonatomic ,assign) NSInteger listType;
/**
* 清除上面的block
*/
- (void)clearCompletionBlock;
@end
查看TFTableViewDataManager的實現;發現其initWithDataSource在dataSource中調用;
manager對dataSource弱引用;dataSource中對manager強引用;避免循環引用;
@implementation TFTableViewDataManager
- (instancetype)initWithDataSource:(TFTableViewDataSource *)tableViewDataSource
listType:(NSInteger)listType {
self = [super init];
if (!self) {
return nil;
}
_tableViewDataSource = tableViewDataSource;
_listType = listType;
__weak __typeof(self)weakSelf = self;
_cellViewClickHandler = ^ (TFTableViewItem *item ,NSInteger actionType) {
__typeof(&*weakSelf) strongSelf = weakSelf;
strongSelf.currentIndexPath = item.indexPath;
[item deselectRowAnimated:YES];
if ([strongSelf.tableViewDataSource.delegate respondsToSelector:@selector(actionOnView:actionType:)]) {
[strongSelf.tableViewDataSource.delegate actionOnView:item actionType:actionType];
}
[strongSelf cellViewClickHandler:item actionType:actionType];
};
_deleteHanlder = ^(TFTableViewItem *item ,Completion completion) {
__typeof(&*weakSelf) strongSelf = weakSelf;
[strongSelf deleteHanlder:item completion:completion];
};
return self;
}
/**
* 顯示列表數據
*
* @param result 數據字典
* @param completionBlock 回調block
*/
- (void)reloadView:(NSDictionary *)result block:(TableViewReloadCompletionBlock)completionBlock {
}
/**
* 列表內View事件處理
*
* @param item
* @param actionType
*/
- (void)cellViewClickHandler:(TFTableViewItem *)item actionType:(NSInteger)actionType {
self.currentIndexPath = item.indexPath;
}
/**
* 列表刪除事件處理
*
* @param item
*/
- (void)deleteHanlder:(TFTableViewItem *)item completion:(void (^)(void))completion {
self.currentIndexPath = item.indexPath;
}
/**
* 刷新指定Cell
*
* @param actionType
* @param dataId
*/
- (void)refreshCell:(NSInteger)actionType identifier:(NSString *)identifier {
}
- (void)clearCompletionBlock {
self.cellViewClickHandler = nil;
self.deleteHanlder = nil;
}
@end
在)initWithDataSource:listType:中初始化了cellViewClickHandler、deleteHanlder;
其中cellViewClickHandler中會回調datasource的代理類(通常為TFTableViewController的子類);這樣就將cell的事件回傳到ViewController了;
_cellViewClickHandler = ^ (TFTableViewItem *item ,NSInteger actionType) {
__typeof(&*weakSelf) strongSelf = weakSelf;
strongSelf.currentIndexPath = item.indexPath;
[item deselectRowAnimated:YES];
if ([strongSelf.tableViewDataSource.delegate respondsToSelector:@selector(actionOnView:actionType:)]) {
[strongSelf.tableViewDataSource.delegate actionOnView:item actionType:actionType];
}
[strongSelf cellViewClickHandler:item actionType:actionType];
};
看看協議接口TFTableViewDataManagerProtocol
有哪些東西;
ifndef TFTableViewDataManagerProtocol_h
#define TFTableViewDataManagerProtocol_h
#import "TFTableViewDataSource.h"
#import <TFNetwork/TFNetwork.h>
@class TFTableViewItem;
@class MYTableViewSection;
typedef void (^Completion)(void);
typedef void (^CellViewClickHandler)(__kindof TFTableViewItem *item ,NSInteger actionType);
typedef void (^DeletionHandlerWithCompletion)(__kindof TFTableViewItem *item, void (^)(void));
typedef void (^TableViewReloadCompletionBlock)(BOOL finished,id object,NSError *error, NSArray <MYTableViewSection *> *sections);
@protocol TFTableViewDataManagerProtocol <NSObject>
@required
/**
* 列表業務類初始化
*
* @param tableViewDataSource 列表數據源
* @param listType 列表類型
*
* @return TFTableDataSourceManager
*/
- (instancetype)initWithDataSource:(TFTableViewDataSource *)tableViewDataSource
listType:(NSInteger)listType;
/**
* 顯示列表數據
*
* @param result 數據字典
* @param completionBlock 回調block
*/
- (void)reloadView:(NSDictionary *)result block:(TableViewReloadCompletionBlock)completionBlock;
/**
* 列表內View事件處理
*
* @param item
* @param actionType
*/
- (void)cellViewClickHandler:(TFTableViewItem *)item actionType:(NSInteger)actionType;
/**
* 列表刪除事件處理
*
* @param item
*/
- (void)deleteHanlder:(TFTableViewItem *)item completion:(void (^)(void))completion;
/**
* 刷新指定Cell
*
* @param actionType
* @param dataId
*/
- (void)refreshCell:(NSInteger)actionType identifier:(NSString *)identifier;
@end
#endif
TFTableViewDataSource : NSObject
TabelView數據源處理類,通過繼承TFTableViewDataSource
可以重載下拉刷新、列表展示等方法來實現自定義;
具體使用可以查看TFTableViewController;總體的邏輯參考RETableViewManager;兩步:
- 綁定tableView到MYTableViewManager;
- 給tableViewManager手動設置item和itemCell;
_tableViewManager = [[MYTableViewManager alloc] initWithTableView:self.tableView delegate:nil];
_tableViewManager[@"TFTableviewDefaultItem"] = @"TFTableviewDefaultItemCell";
查看頭文件
@protocol TFTableViewDataSourceDelegate <NSObject>
@required
/**
* 列表及其控件點擊事件回調
*
* @param item
* @param actionType 事件類型
*/
- (void)actionOnView:(TFTableViewItem *)item actionType:(NSInteger)actionType;
/**
* 開始加載
*/
- (void)didStartLoad;
/**
* 加載完成
*
* @param loadPolicy 加載類型
* @param object 返回數據
* @param error 錯誤
*/
- (void)didFinishLoad:(TFDataLoadPolicy)loadPolicy object:(id)object error:(NSError *)error;
@optional
- (BOOL)showPullRefresh;
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
- (void)scrollViewDidScrollUp:(CGFloat)deltaY;
- (void)scrollViewDidScrollDown:(CGFloat)deltaY;
- (void)scrollFullScreenScrollViewDidEndDraggingScrollUp;
- (void)scrollFullScreenScrollViewDidEndDraggingScrollDown;
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(ASTableView *)tableView willDisplayNodeForRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(ASTableView *)tableView didEndDisplayingNode:(ASCellNode *)node forRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath;
@end
@interface TFTableViewDataSource : NSObject
@property (nonatomic ,weak) id<TFTableViewDataSourceDelegate> delegate;
@property (nonatomic ,strong ,readonly ,getter = manager) MYTableViewManager *manager;
@property (nonatomic ,weak) ASTableView *tableView;
@property (nonatomic ,assign) TFDataSourceState dataSourceState;
/**
* 總頁數
*/
@property (nonatomic ,assign) NSInteger totalPage;
/**
* 當前頁碼
*/
@property (nonatomic ,assign) NSInteger currentPage;
/**
* 對應的listType,綁定url
*/
@property (nonatomic ,assign) NSInteger listType;
/**
* 列表數據緩存時間
*/
@property (nonatomic ,assign) NSInteger cacheTimeInSeconds;
/**
* 初始化化方法,用于綁定manager和tableview;item和itemCell;
*
*/
- (instancetype)initWithTableView:(ASTableView *)tableView
listType:(NSInteger)listType
params:(NSDictionary *)params
delegate:(id /*<TFTableViewDataSourceDelegate>*/)delegate;
/**
* 開始加載,沒有url參數
*/
- (void)startLoading;
/**
* 開始加載列表數據,帶url參數
*
* @param params GET 請求參數
*/
- (void)startLoadingWithParams:(NSDictionary *)params;
/**
* 停止加載
*/
- (void)stopLoading;
/**
* 刷新指定Cell
*
* @param actionType 刷新動作
* @param identifier Cell唯一標示
*/
- (void)refreshCell:(NSInteger)actionType identifier:(NSString *)identifier;
/**
* 下拉刷新相關
*/
- (void)initTableViewPullRefresh;
- (void)startTableViewPullRefresh;
- (void)stopTableViewPullRefresh;
@end
查看實現方法:
一. 初始化init開始;
- (instancetype)initWithTableView:(ASTableView *)tableView
listType:(NSInteger)listType
params:(NSDictionary *)params
delegate:(id /*<TFTableViewDataSourceDelegate>*/)delegate {
self = [super init];
if (!self) {
return nil;
}
_delegate = delegate;
_tableView = tableView;
_listType = listType;
_requestArgument = [NSMutableDictionary dictionaryWithDictionary:params];
_manager = [[MYTableViewManager alloc] initWithTableView:tableView delegate:self];
[self initTableViewPullRefresh];
[self setupDataSource];
return self;
}
初始化請求參數requestArgument,MYTableViewManager;調用initTableViewPullRefresh初始化下拉刷新;調用setupDataSource方法,進行一些初始化配置,根據listType獲取對應的url和dataManager;
#pragma mark - 初始化數據加載方法
- (void)setupDataSource {
_downThresholdY = 200.0;
_upThresholdY = 25.0;
NSString *requestURL = [[TFTableViewDataSourceConfig sharedInstance] requestURLByListType:_listType];
NSString *className = [[TFTableViewDataSourceConfig sharedInstance] classNameByListType:_listType];
_dataRequest = [[TFTableViewDataRequest alloc] initWithRequestURL:requestURL params:_requestArgument];
if (className) {
Class class = NSClassFromString(className);
_tableViewDataManager = [[class alloc] initWithDataSource:self listType:_listType];
}
//registerClass
NSArray *itemClassList = [TFTableViewClassList subclassesOfClass:[MYTableViewItem class]];
for (Class itemClass in itemClassList) {
NSString *itemName = NSStringFromClass(itemClass);
self.manager[itemName] = [itemName stringByAppendingString:@"Cell"];
}
}
在RouteManager中setupMap配置信息如下;
[self mapWithListType:ListTypeManagerCreateList
dataManagerClass:@"DCManegerDataManeger"
url:kDCInterfaceManagerRoot];
看看mapWithListType怎么實現的;最后調用TFTableViewDataSourceConfig方法;
+ (void)mapWithListType:(ListType)listType dataManagerClass:(NSString *)className url:(NSString *)url {
[[TFTableViewDataSourceConfig sharedInstance]
mapWithListType:listType
mappingInfo:@{ kTFTableViewDataManagerClassKey : className,
kTFTableViewDataRequestURLKey : url }];
}
返回查看setupDataSource方法;就獲取到相應的requestURL和ViewDataManager類名;
對DataManager進行實例化;通過TFTableViewClassList獲取所有MYTableViewItem的子類,這是通過runtime實現的,之后給manger配置item和itemCell,像下面這樣;
_tableViewManager = [[MYTableViewManager alloc] initWithTableView:self.tableView delegate:nil];
_tableViewManager[@"TFTableviewDefaultItem"] = @"TFTableviewDefaultItemCell";
二. 數據加載loading;
// 開始加載,
- (void)startLoading {
[self startLoadingWithParams:_requestArgument];
}
// 帶參數 加載;
- (void)startLoadingWithParams:(NSDictionary *)params {
if (_requestArgument) {
[_requestArgument addEntriesFromDictionary:params];
}
else {
_requestArgument = [NSMutableDictionary dictionaryWithDictionary:params];
}
[self load:TFDataLoadPolicyNone context:nil];
}
???疑問,這樣調用,參數會重復嗎;
[self.requestParams setObject:@(model.id) forKey:@"city"];
[self.dataSource startLoadingWithParams:self.requestParams];
數據加載核心方法
// 數據加載
- (void)load:(TFDataLoadPolicy)loadPolicy context:(ASBatchContext *)context {
//當前正在加載數據
if (_dataSourceState == TFDataSourceStateLoading) {
return;
}
if (loadPolicy == TFDataLoadPolicyMore) {
//加載下一頁數據
if (_currentPage == _totalPage) {
//加載完所有頁碼
_dataSourceState = TFDataSourceStateFinished;
return;
}
_currentPage++;
} else {
_currentPage = 1;
_totalPage = 1;
}
[_requestArgument setObject:[NSNumber numberWithInteger:[TFTableViewDataSourceConfig pageSize]]
forKey:@"pageSize"];
[_requestArgument setObject:[NSNumber numberWithInteger:_currentPage] forKey:@"currentPage"];
_dataRequest.requestArgument = _requestArgument;
// 設置緩存時間
_dataRequest.cacheTimeInSeconds = _cacheTimeInSeconds;
// 設置操作標示
_dataSourceState = TFDataSourceStateLoading;
// 加載第一頁時候使用緩存數據
if ([_dataRequest cacheResponseObject] && !_firstLoadOver) {
// 使用緩存數據繪制UI
TFTableViewLogDebug(@"use cache data for %@",_dataRequest.requestURL);
[self handleResultData:[_dataRequest cacheResponseObject]
dataLoadPolicy:TFDataLoadPolicyCache
context:context
error:nil];
}
else {
// 請求網絡數據
[_dataRequest startWithCompletionBlockWithSuccess:^(__kindof TFBaseRequest *request) {
TFTableViewLogDebug(@"get data from server %@ page:%@",request.requestUrl,@(_currentPage));
[self handleResultData:request.responseObject dataLoadPolicy:loadPolicy context:context error:nil];
} failure:^(__kindof TFBaseRequest *request) {
TFTableViewLogDebug(@"get data from %@ error :%@ userinfo:%@",request.requestUrl,request.error,request.userInfo);
// 網絡請求出錯,存在緩存,先獲取緩存
if ([request cacheResponseObject]) {
[self handleResultData:[request cacheResponseObject]
dataLoadPolicy:loadPolicy
context:context
error:nil];
}
else {
[self handleResultData:nil
dataLoadPolicy:loadPolicy
context:context
error:request.error];
}
}];
}
}
設置請求參數、請求緩存時間;有緩存先用緩存繪制UI,不然網絡請求數據;網絡請求出現錯誤的時候,也會先使用緩存;
// 處理返回數據并繪制UI
- (void)handleResultData:(NSDictionary *)result
dataLoadPolicy:(TFDataLoadPolicy)dataLoadPolicy
context:(ASBatchContext *)context
error:(NSError *)error {
TFTableViewLogDebug(@"%s",__func__);
NSError *hanldeError = nil;
NSInteger lastSectionIndex = [[self.manager sections] count] - 1;
if (!result || [[result objectForKey:@"dataList"] count] <= 0) {
//數據為空
hanldeError = [NSError errorWithDomain:@"" code:1 userInfo:@{}];
}
if (dataLoadPolicy == TFDataLoadPolicyMore) {
//加載下一頁,移除loading item
[self.manager removeLastSection];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:lastSectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
});
}
[self setTotalPage:[[result objectForKey:@"totalPage"] integerValue]];
if (_totalPage == 0) {
//數據邊界檢查
_totalPage = 1;
_currentPage = 1;
}
// 調用tableViewManager 的 reloadView:block方法 顯示列表數據;
// 在這里將數據傳給DataManager的子類;調用block
__weak __typeof(self)weakSelf = self;
[self.tableViewDataManager reloadView:result
block:^(BOOL finished, id object, NSError *error, NSArray <MYTableViewSection *> *sections)
{
typeof(self) strongSelf = weakSelf;
if (finished) {
if (dataLoadPolicy == TFDataLoadPolicyReload || dataLoadPolicy == TFDataLoadPolicyNone) {
// 重新加載列表數據
[strongSelf.manager removeAllSections];
}
NSInteger rangelocation = [strongSelf.manager.sections count];
[strongSelf.manager addSectionsFromArray:sections];
NSInteger rangelength = 1;
// 需要在主線程執行
if (_currentPage < _totalPage) {
// 存在下一頁數據,在列表尾部追加loading item
MYTableViewSection *section = [MYTableViewSection section];
// loading item
[section addItem:[MYTableViewLoadingItem itemWithTitle:NSLocalizedString(@"正在加載...", nil)]];
[strongSelf.manager addSection:section];
rangelength += sections.count;
}
dispatch_async(dispatch_get_main_queue(), ^{
if (dataLoadPolicy == TFDataLoadPolicyMore) {
[strongSelf.tableView insertSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(rangelocation, rangelength)]
withRowAnimation:UITableViewRowAnimationFade];
if (context) {
[context completeBatchFetching:YES];
}
}
else {
[strongSelf reloadTableView];
strongSelf.firstLoadOver = YES;
if (dataLoadPolicy == TFDataLoadPolicyReload) {
[strongSelf stopTableViewPullRefresh];
}
if (dataLoadPolicy == TFDataLoadPolicyCache) {
//第一次從緩存加載數據后延遲觸發下拉刷新重新加載
[strongSelf performSelector:@selector(startTableViewPullRefresh)
withObject:nil
afterDelay:0.75];
}
}
// 數據加載完成
if (strongSelf.delegate && [strongSelf.delegate respondsToSelector:@selector(didFinishLoad:object:error:)]) {
[strongSelf.delegate didFinishLoad:dataLoadPolicy object:object error:error?error:hanldeError];
}
});
strongSelf.dataSourceState = TFDataSourceStateFinished;
}
}];
}
調用tableViewManager 的 reloadView:block方法 顯示列表數據;在這里將數據傳給DataManager的子類;調用block;
// 重新加載列表數據;remove所有section了;
[strongSelf.manager removeAllSections];
最后數據加載完成,回調dataSource的代理(通常為TFTableView的子類);
didFinishLoad:object:error:
通過源碼看到,reloadView中將數據通過block傳過去,在VC中didFinishLoad才能進行判斷;
DataManager 給 ViewController 傳數據;
??? 那反過來呢;
typedef void (^TableViewReloadCompletionBlock)(BOOL finished,id object,NSError *error, NSArray <MYTableViewSection *> *sections);
- (void)reloadView:(NSDictionary *)result block:(TableViewReloadCompletionBlock)completionBlock
completionBlock(YES, list, nil, @[section]);
- (void)didFinishLoad:(TFDataLoadPolicy)loadPolicy object:(id)object error:(NSError *)error
{
[super didFinishLoad:loadPolicy object:object error:error];
if (!object)
{
[self showStateView:kTFViewStateNoData];
}
}
MYTableViewManager
最終tableView的cell繪制都在這個MYTableViewManager中;
MYTableViewManager的整體邏輯可以參考RETableViewManager;只是將RE里的UITableView
換成ASTableView;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
// 返回對應的cell;ASTableView中稱為node;
- (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSIndexPath *)indexPath
// tableView的側邊IndexTitles
- (NSArray *)sectionIndexTitlesForTableView:(ASTableView *)tableView
// tableView尾視圖Header 的 title
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
// tableView尾視圖Footer 的 title
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
// tableView移動move
// 可以看到moveHandler、moveCompletionHandler功能;怎么用的
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
// 看到給item添加editingStyle,就能實現左劃刪除等;
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(ASTableView *)tableView willDisplayNodeForRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(ASTableView *)tableView didEndDisplayingNode:(ASCellNode *)node forRowAtIndexPath:(NSIndexPath *)indexPath
tableView如何實現刪除,
// tableView如何實現刪除; section刪掉,tableView刪掉,還要修改后面
[section removeItemAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
for (NSInteger i = indexPath.row; i < section.items.count; i++) {
MYTableViewItem *afterItem = [[section items] objectAtIndex:i];
MYTableViewCell *cell = (MYTableViewCell *)[(ASTableView *)tableView nodeForRowAtIndexPath:afterItem.indexPath];
cell.rowIndex--;
}
Tableview delegate
// Header、Footer
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section
- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section
// header、Footer的高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)sectionIndex
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)sectionIndex
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)sectionIndex
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)sectionIndex
// Accessories (disclosures).
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
// Selection
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath
tableView 事件處理
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
- (NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
// Editing
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
// 左滑刪除、標題;
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath
// Moving/reordering
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
// Indentation
- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
// Copy/Paste. All three methods must be implemented by the delegate.
// 復制/粘貼;
- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath
- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender
其他的代理不看了;分析下tableView的事件處理;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[_tableView deselectRowAtIndexPath:indexPath animated:YES];
[_tableView beginUpdates];
MYTableViewSection *section = [self.mutableSections objectAtIndex:indexPath.section];
id item = [section.items objectAtIndex:indexPath.row];
if ([item respondsToSelector:@selector(setSelectionHandler:)]) {
MYTableViewItem *actionItem = (MYTableViewItem *)item;
if (actionItem.selectionHandler)
actionItem.selectionHandler(item);
}
// Forward to UITableView delegate
//
if ([self.delegate conformsToProtocol:@protocol(UITableViewDelegate)] && [self.delegate respondsToSelector:@selector(tableView:didSelectRowAtIndexPath:)])
[self.delegate tableView:tableView didSelectRowAtIndexPath:indexPath];
[_tableView endUpdates];
}
獲取相應的section,獲取item;調用item的selectionHandler,并將item作為block參數回傳過去;
TFTableViewItem 在初始化會設置selectionHandler
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
__weak typeof(self) weakself = self;
self.selectionHandler = ^(id item){
if (weakself.onViewClickHandler) {
weakself.onViewClickHandler(item, -1);
}
};
return self;
}
+ (instancetype)itemWithModel:(NSObject *)model
clickHandler:(void(^)(TFTableViewItem *item,NSInteger actionType))clickHandler {
TFTableViewItem *item = [[[self class] alloc] init];
item.model = model;
item.onViewClickHandler = clickHandler;
return item;
}
在init中將actionType設為-1;作為整個cell的點擊;其他非零值可以為cell上的按鈕;并且將item值回傳給onViewClickHandler;
TFTableViewDataManager中會初始化cellViewClickHandler;其中的item是TFTableViewItem傳過來的;
- (instancetype)initWithDataSource:(TFTableViewDataSource *)tableViewDataSource
listType:(NSInteger)listType {
self = [super init];
if (!self) {
return nil;
}
_tableViewDataSource = tableViewDataSource;
_listType = listType;
__weak __typeof(self)weakSelf = self;
_cellViewClickHandler = ^ (TFTableViewItem *item ,NSInteger actionType) {
__typeof(&*weakSelf) strongSelf = weakSelf;
strongSelf.currentIndexPath = item.indexPath;
[item deselectRowAnimated:YES];
if ([strongSelf.tableViewDataSource.delegate respondsToSelector:@selector(actionOnView:actionType:)]) {
[strongSelf.tableViewDataSource.delegate actionOnView:item actionType:actionType];
}
[strongSelf cellViewClickHandler:item actionType:actionType];
};
_deleteHanlder = ^(TFTableViewItem *item ,Completion completion) {
__typeof(&*weakSelf) strongSelf = weakSelf;
[strongSelf deleteHanlder:item completion:completion];
};
return self;
}
cellViewClickHandler中,
首先會調用tableViewDataSource.delegate
的方法actionOnView:actionType:
; 一般為TFTableViewController
的子類;
然后再調用對應TFTableViewDataManager
子類的cellViewClickHandler:actionType: