前言:
框架對於UITableView、UITableViewCell 封裝了不少功能,下面開始介紹。
1、UITableView 基本定義。
@interface UITableView(ST) #pragma mark 核心擴展 typedef void(^OnAddTableCell)(UITableViewCell *cell,NSIndexPath *indexPath); typedef BOOL(^OnDelTableCell)(UITableViewCell *cell,NSIndexPath *indexPath); typedef void(^OnAddTableCellAction)(STUITableViewCellAction *cellAction, NSIndexPath *indexPath); typedef void(^OnAddTableSectionHeaderView)(UIView *sectionHeaderView,NSInteger section);
typedef void(^OnAddTableSectionFooterView)(UIView *sectionFooterView,NSInteger section);
typedef void(^OnAfterTableReloadData)(UITableView *tableView);
//!用於為Table追加每一行的Cell @property (nonatomic,copy) OnAddTableCell addCell; //!用於為Table追加每一行的Cell的滑動菜單 @property (nonatomic,copy) OnAddTableCellAction addCellAction; //!用於為Table追加每一組Section的標題View @property (nonatomic,copy) OnAddTableSectionHeaderView addSectionHeaderView;
//!用於為Table追加每一組Section的Bottom View
@property (nonatomic,copy) OnAddTableSectionFooterView addSectionFooterView;
//!用於為Table移除行的Cell @property (nonatomic,copy) OnDelTableCell delCell; //!用於為Table reloadData 加載完數據后觸發 @property (nonatomic,copy) OnAfterTableReloadData afterReload; //!獲取Table的數據源 @property (nonatomic,strong) NSMutableArray<id> *source; //!設置Table的數據源 -(UITableView*)source:(NSMutableArray<id> *)dataSource; //!存檔所有Cell的高度(由系統控制)[存檔格式為:section key,[row Array]] @property (readonly,nonatomic,retain) NSMutableDictionary *heightForCells; //!是否重用Cell(默認Yes) -(BOOL)reuseCell; -(BOOL)reuseCell:(BOOL)yesNo; //!是否自動控制Table的高度 -(BOOL)autoHeight; //!設置是否自動控制Table的高度 -(UITableView*)autoHeight:(BOOL)yesNo; //!獲取默認的UITableViewCellStyle -(UITableViewCellStyle)cellStyle; //!設置默認的UITableViewCellStyle -(UITableView*)cellStyle:(UITableViewCellStyle)style; //!獲取是否允許編輯【刪除】屬性 -(BOOL)allowEdit; //!設置是否允許編輯【刪除】 -(UITableView*)allowEdit:(BOOL)yesNo; //!移除數據源和數據行(並重新計算且刷新高度) -(UITableView*)afterDelCell:(NSIndexPath*)indexPath; #pragma mark 擴展屬性 -(UITableView*)scrollEnabled:(BOOL)yesNo; //!分組數(默認1) -(UITableView*)sectionCount:(NSInteger)count; //!每個Section的num數:參數可以傳遞:@[@"1",@"2",@"2",@"1"] 或者:@"1,2,2,1" -(UITableView*)rowCountInSections:(id)nums; @end
2、UITableViewCell 基本定義:
@interface UITableViewCell(ST) //!獲取當前所在的table,(weak,不能造成雙strong引用) @property (readonly,nonatomic,weak) UITableView *table; //!獲取Cell的數據源 @property (nonatomic,strong) id source; //!Cell是否重用的Cell,如果是,就不要再添加子控制,避免重復添加。 //@property (readonly,nonatomic,assign) BOOL isReused; //!設置Cell的數據源 -(UITableViewCell *)source:(id)dataSource; //!創建或復用Cell + (instancetype)reuseCell:(UITableView *)tableView index:(NSIndexPath *)index; //!獲取Cell所在的行數 -(NSIndexPath*)indexPath; -(UITableViewCell*)indexPath:(NSIndexPath*)indexPath; //!獲取是否允許刪除屬性 -(BOOL)allowDelete; //!設置是否允許刪除 -(UITableView*)allowDelete:(BOOL)yesNo; //!數據源中的第一個字段,系統自動設置 -(NSString*)firstValue; -(UITableViewCell*)firstValue:(NSString*)value; //當Cell的高度在綁定后,需要動態根據子內容高度變化,再次刷新高度時使用。 -(UITableViewCell*)resetHeightCache; #pragma mark 擴展屬性 -(UITableViewCell*)accessoryType:(UITableViewCellAccessoryType)type; -(UITableViewCell*)selectionStyle:(UITableViewCellSelectionStyle)style;
#pragma mark 擴展
//!獲取Cell的滑動菜單項。
@property (nonatomic,strong) STUITableViewCellAction *action;
@end
UITableView 基本用法示例一:
[[[[[sagit addTableView:nil] autoHeight:YES] width:610] toCenter] block:^(UITableView* table) { [table relate:TopBottom v:60 v2:60]; [table backgroundColor:ColorClear]; table.backgroundView=[[[[UIImageView new] image:@"answer_bg_rank"]stretch] width:1 height:1]; table.separatorColor = [ColorWhite alpha:0.2]; table.separatorInset=UIEdgeInsetsMake(0,26, 0, 26); table.addCell = ^(UITableViewCell *cell, NSIndexPath *indexPath) { [cell width:1 height:140]; // 1 代表 100% <=1 被處理成百分比。 cell.accessoryType=UITableViewCellAccessoryNone; cell.backgroundColor=ColorClear; //數據 AnswerUserRankModel *model=[[AnswerUserRankModel new] initWithObject:cell.source]; NSString *score=[[@(model.Score) stringValue] append:@" 分"]; [cell.contentView block:^(UIView* view) { [view width:1 height:1]; if(indexPath.row!=table.source.count-1) { [[[[view addLine:nil color:@"#81F0D7"] width:2 height:30]y:140-15] relate:Right v:26]; [[[[view addLine:nil color:@"#81F0D7"] width:30 height:2] y:140] relate:Right v:26]; } [view addLabel:nil text:STNumString(model.Rank) font:30 color:ColorWhite]; [[STLastView x:50] toCenter:Y]; [[[[view addImageView:nil] url:model.PhotoPath] width:80 height:80] corner:YES]; [[STLastView x:122] toCenter:Y]; [[[[view addLabel:nil text:model.NickName font:30 color:@"#FB8107"] onRight:STPreView x:42] toCenter:Y] width:72*2]; [[[view addImageView:nil img:@"answer_bg_rankscore"] width:196 height:20] block:^(UIImageView* scoreView) { [[scoreView x:192*2] toCenter:Y]; //[[scoreView relate:Right v:160] toCenter:Y]; [[scoreView addLabel:nil text:score font:30 color:@"#81F0D7"] toCenter]; //[scoreView stSizeToFit]; }]; [view onClick:^(id view) { [self stPush:[STNew(@"User") key:@"uid" value:model.UserID]]; }]; }]; }; }];
效果:
UITableView 基本用法示例二:
[[[[sagit addTableView:@"tableView" style:UITableViewStyleGrouped] autoHeight:YES] onBottom:STPreView y:20] block:nil on:^(UITableView* table) { [table reuseCell:NO]; table.addCell = ^(UITableViewCell *cell, NSIndexPath *indexPath) { NSString *name=cell.source[@"name"]; NSString *title=cell.source[@"title"]; NSString *holder=cell.source[@"holder"]; if(holder==nil){holder=title;} NSString *pick=cell.source[@"pick"]; NSString *maxLength=cell.source[@"maxLength"]; [[[cell.contentView addLabel:nil text:title font:30] relate:Left v:50] toCenter:Y];//label是固定的。 UIView *textView; if([title isEqualToString:@"簡介"]) { textView=[[[[[cell.contentView addTextView:name placeholder:holder font:30] maxRow:3] maxLength:100] textAlignment:NSTextAlignmentLeft] height:0.8]; UIEdgeInsets inset=textView.asTextView.textContainerInset; inset.left-=5; textView.asTextView.textContainerInset=inset; } else { textView=[[cell.contentView addTextField:name placeholder:holder font:30] height:0.8]; if(maxLength!=nil) { [STLastTextField maxLength:[maxLength integerValue]]; } } [[[textView onRight:STPreView x:50] relate:Right v:0] toCenter:Y]; if(pick==nil) { cell.accessoryType=UITableViewCellAccessoryNone; } else { [[STLastView addClick:@"pick"] key:@"pick" value:pick]; } }; table.afterReload = ^(UITableView *tableView) { if(!self.hasLoaded) { self.hasLoaded=YES; [self setToAll:Sagit.Global.User.user]; } }; }];
效果:
數據源設置:
-(void)initData { [super initData];//加載子UI的數據。 UITableView *table=STFirstTable; table.source=@[@{@"title":@"姓名",@"name":@"NickName",@"maxLength":@"15"}, @{@"title":@"簡介",@"name":@"Description",@"holder":@"請簡單介紹一下自己!"}, @{@"title":@"公司",@"name":@"Company",@"holder":@"所在公司!",@"maxLength":@"20"}, @{@"title":@"年齡",@"name":@"Age",@"pick":@"年齡"}, @{@"title":@"學歷",@"name":@"Edu",@"pick":@"學歷"}, @{@"title":@"身高",@"name":@"Height",@"pick":@"身高"}, @{@"title":@"星座",@"name":@"Constellation",@"pick":@"星座"}, @{@"title":@"婚姻",@"name":@"MarrStatus",@"pick":@"婚姻"}, @{@"title":@"職業",@"name":@"Profession",@"pick":@"職業"}, @{@"title":@"收入",@"name":@"Wages",@"pick":@"月薪"}]; [[table sectionCount:2] rowCountInSections:@"3,7"]; //table.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f,1, 0.01f)]; table.sectionFooterHeight=0.2; // table.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f,1, 1.0f)]; //self.automaticallyAdjustsScrollViewInsets = NO; [table reloadData]; }
UITableView 基本用法示例三:循環嵌套[2021-11-11更新]
-(void)initUI { [[[[sagit addTableView:nil]relate:TopBottom v:100 v2:200] backgroundColor:ColorRed] block:^(UITableView* table) { table.addCell = ^(UITableViewCell *cell, NSIndexPath *indexPath) { [cell backgroundColor:ColorGreen]; [[cell addLabel:nil text:cell.firstValue] toCenter]; [[[cell addSwitch:nil on:NO] onSwitch:^(UISwitch *view) { if(view.on) { [self addTable:cell]; } else { [cell.lastSubView removeFromSuperview]; [cell refleshTableHeight]; } }] relate:Right v:50]; }; table.source=@[@{@"a":@"aa"},@{@"a":@"bb"},@{@"a":@"cc"}]; }]; } -(void)addTable:(UITableViewCell*)cell { [[[[cell addTableView:nil] autoHeight:YES] backgroundColor:ColorBlack] block:^(UITableView* cellTable) { [[cellTable onBottom:cell.lastSubView.preView] x:0]; cellTable.addCell = ^(UITableViewCell *childCell, NSIndexPath *indexPath) { childCell.accessoryType=UITableViewCellAccessoryNone; [[childCell backgroundColor:ColorRandom] width:1 height:100]; NSString * value=childCell.firstValue; [[childCell addLabel:nil text:value] toCenter]; }; cellTable.afterReload = ^(UITableView *tableView) { [cell refleshTableHeight]; }; cellTable.source=@[@{@"b":@"aaaa"},@{@"b":@"bb"},@{@"b":@"cc"}]; }]; }
代碼細節說明:
Table循環嵌套時,由於表格加載,有延后時,所以,需要在子表格的afterReolad事件(即加載完后)處理。
單元格新增了:refleshTableHeight:刷新表格高度。該方法僅會刷新單元格和表格的高度(不觸發table的reload事件)。
循環效果圖:
UICollectionView、UICollectionViewCell 基本定義
@interface UICollectionView(ST) #pragma mark 核心擴展 typedef void(^AddCollectionCell)(UICollectionViewCell *cell,NSIndexPath *indexPath); typedef BOOL(^DelCollectionCell)(UICollectionViewCell *cell,NSIndexPath *indexPath); //!用於為Table追加每一行的Cell @property (nonatomic,copy) AddCollectionCell addCell; //!用於為Table移除行的Cell @property (nonatomic,copy) DelCollectionCell delCell; //!獲取Table的數據源 @property (nonatomic,strong) NSMutableArray<id> *source; //!設置Table的數據源 -(UITableView*)source:(NSMutableArray<id> *)dataSource; @end
---------------------------------------------
@interface UICollectionViewCell(ST) //!獲取Cell的數據源 @property (nonatomic,strong) NSMutableDictionary<NSString*,id> *source; //!設置Cell的數據源 -(UICollectionViewCell *)source:(NSMutableDictionary<NSString*,id> *)dataSource; //!創建或復用Cell + (instancetype)reuseCell:(UICollectionView *)tableView index:(NSIndexPath *)index; //!獲取當前所在的table -(UICollectionView*)table; //!獲取是否允許刪除屬性 //-(BOOL)allowDelete; //!設置是否允許刪除 //-(UITableView*)allowDelete:(BOOL)yesNo; //!數據源中的第一個字段,系統自動設置 -(NSString*)firstValue; -(UICollectionViewCell*)firstValue:(NSString*)value; @end
這兩個和上面兩個的用法基本一致,功能比上面的還少,就不過多介紹了。
3、左滑菜單說明
如果左滑的菜單只有刪除,那么只需要設置:
[table allowEdit:YES]
刪除點擊的事件:
table.delCell = ^BOOL(UITableViewCell *cell, NSIndexPath *indexPath) { [Sagit.RongYun removeFromBlacklist:cell.firstValue success:^{ [this.http get:UrlSetBlacklist paras:@{@"blackUserID":cell.firstValue, @"blackFlag":@"2"} success:^(STHttpModel *result) { if (result.success) { [cell.table afterDelCell:indexPath]; } } ]; } error:^(RCErrorCode status) { }]; return false; };
默認是處理完業務,return true;(之后框架會調用 afterDelCell 移除行並重繪高度)。
如果有異步操作,也可以先return false; 再根據結果自己調用 afterDelCell 方法。
如果涉及到添加多個菜單:
原生事件:
-(NSArray<UITableViewRowAction*>*)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath { RCConversationModel *model = self.conversationListDataSource[indexPath.row]; UITableViewRowAction *del = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@"刪除" handler:^(UITableViewRowAction * _Nonnull action,NSIndexPath * _Nonnull indexPath) { ...... }]; UITableViewRowAction *top = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"置頂" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) { ...... }]; top.backgroundColor = STColor(@"#fe9d00"); return @[del, top]; }
框架用法 [2020-09-17更新]
table.addCellAction = ^(STUITableViewCellAction *actions, NSIndexPath *indexPath) { [actions addAction:@"置頂" bgColor:ColorRed onAction:nil]; [actions addAction:@"刪除2" bgColor:ColorBlack onAction:^(UITableViewCell *cell, NSIndexPath *indexPath) { //點擊事件。 }]; };
結果圖:
如果需要自定義滑動菜單:
【原生的方法:可以改變樣式,但改變不了坐標,所以在原生的基礎上添加自己的視圖即可】
- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell=[tableView cellForRowAtIndexPath:indexPath]; if(cell!=nil) { UIView *uiSwipeActionPullView=cell.superview.subviews[0]; //UISwipeActionPullView if([uiSwipeActionPullView isKindOfClass:[UITableViewCell class]]) { //IOS 13 以下。 for (UIView *view in tableView.subviews) { if([view isKindOfClass:NSClassFromString(@"UISwipeActionPullView")]) { uiSwipeActionPullView=view; break; } } } //uiSwipeActionPullView=>UISwipeActionStandardButton => UIView,UIButtonLabel for (UIView * btnView in uiSwipeActionPullView.subviews) { [btnView backgroundColor:STDeviceColor]; [btnView removeAllSubViews]; [[[[[[btnView addButton:nil title:@"click" font:24 color:ColorGreen img:nil] width:120 height:0.8] layerCornerRadius:24] toCenter:Y] backgroundColor:ColorBlue] x:20]; } } }
滑動后的布級層級:(IOS 13) 【IOS13以下的View層級是在UITableView下】
框架用法 [2020-09-17更新]
table.addCellAction = ^(STUITableViewCellAction *actions, NSIndexPath *indexPath) { [actions addAction:^(UIView *cellSwipeView, NSIndexPath *indexPath) { [[[[[[cellSwipeView addButton:nil title:@"click" font:24 color:ColorGreen img:nil] width:120 height:0.8] layerCornerRadius:24] toCenter:Y] backgroundColor:ColorBlue] x:20]; } onAction:nil]; };
效果圖:
PS:addAction 有兩個重載方法,一個用於原生的文字和背景色調整;另一個用於自定樣式。
4、分區標題
原生用法:
// 設置表頭的高度。如果使用自定義表頭,該方法必須要實現,否則自定義表頭無法執行,也不會報錯 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 80*Ypt; } - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { UIView *view=[[[UIView new] width:1 height:80] backgroundColor:[ColorBlue alpha:0.5]]; [[[view addLabel:nil text:@"title"] toCenter] sizeToFit]; [[view stSizeToFit] layerCornerRadius:20 byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight]; return view; }
框架用法: [2021-11-11更新]
table.addSectionHeaderView = ^(UIView *sectionView, NSInteger section) { [sectionView backgroundColor:[ColorBlue alpha:0.5]]; [[[sectionView addLabel:nil text:@"title"] toCenter] sizeToFit]; [[sectionView stSizeToFit] layerCornerRadius:20 byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight]; };
結果圖片: