UITableView是最經常使用的控件,這裏整理下經常使用方法,outline以下(本文參考http://www.cnblogs.com/kenshincui/p/3931948.html,代碼下載地址爲https://github.com/zanglitao/tableviewdemo)html
1:基本介紹ios
2:數據源git
3:代理github
4:修改,刪除,添加和排序api
5:背景view數組
6:自定義cell微信
7:UITableViewController網絡
8:UISearchdisplayControlleride
9:下拉刷新flex
10:靜態tableviewcell
基本介紹
UITableView有兩種風格:UITableViewStylePlain和UITableViewStyleGrouped。這二者操做起來其實並無本質區別,只是後者按分組樣式顯示前者按照普通樣式顯示而已。你們先看一下二者的應用:
1>分組樣式
2>不分組樣式
你們能夠看到在UITableView中數據只有行的概念,並無列的概念,由於在手機操做系統中顯示多列是不利於操做的。UITableView中每行數據都是一個UITableViewCell,在這個控件中爲了顯示更多的信息,iOS已經在其內部設置好了多個子控件以供開發者使用。若是咱們查看UITableViewCell的聲明文件能夠發如今內部有一個UIView控件(contentView,做爲其餘元素的父控件)、兩個UILable控件(textLabel、detailTextLabel)、一個UIImage控件(imageView),分別用於容器、顯示內容、詳情和圖片。使用效果相似於微信、QQ信息列表:
固然,這些子控件並不必定要所有使用,具體操做時能夠經過UITableViewCellStyle進行設置,具體每一個枚舉表示的意思已經在代碼中進行了註釋:
typedef NS_ENUM(NSInteger, UITableViewCellStyle) { UITableViewCellStyleDefault, // 左側顯示textLabel(不顯示detailTextLabel),imageView可選(顯示在最左邊) UITableViewCellStyleValue1, // 左側顯示textLabel、右側顯示detailTextLabel(默認藍色),imageView可選(顯示在最左邊) UITableViewCellStyleValue2, // 左側依次顯示textLabel(默認藍色)和detailTextLabel,imageView可選(顯示在最左邊) UITableViewCellStyleSubtitle // 左上方顯示textLabel,左下方顯示detailTextLabel(默認灰色),imageView可選(顯示在最左邊) };
數據源
因爲iOS是遵循MVC模式設計的,不少操做都是經過代理和外界溝通的,但對於數據源控件除了代理還有一個數據源屬性,經過它和外界進行數據交互。 對於UITableView設置完dataSource後須要實現UITableViewDataSource協議,在這個協議中定義了多種 數據操做方法,下面經過建立一個簡單的聯繫人管理進行演示:
UserEntity包括姓名和電話兩個屬性
@interface UserEntity : NSObject @property(nonatomic,strong)NSString *name; @property(nonatomic,strong)NSString *phone; -(id)initWithName:(NSString *)name Phone:(NSString *)phone; @end @implementation UserEntity -(id)initWithName:(NSString *)name Phone:(NSString *)phone { self = [super init]; if (self) { self.name = name; self.phone = phone; } return self; } @end
UserGroup表明一個分表,包括聯繫人數組,分組代號以及分組描述
@interface UserGroup : NSObject @property(nonatomic,strong)NSMutableArray *userEntities; @property(nonatomic,strong)NSString *groupIdentifier; @property(nonatomic,strong)NSString *groupIntro; -(id)initWithEntities:(NSArray *)entities GroupIdentifier:(NSString *)groupIdentifier GroupIntro:(NSString *)groupIntro; @end @implementation UserGroup -(id)initWithEntities:(NSMutableArray *)entities GroupIdentifier:(NSString *)groupIdentifier GroupIntro:(NSString *)groupIntro { self = [super init]; if (self) { self.userEntities = entities; self.groupIdentifier = groupIdentifier; self.groupIntro = groupIntro; } return self; } @end
viewcontroller須要實現UITableViewDataSource協議,協議中包含了數據源相關方法,用來控制列表數據
@interface ZLTViewController ()<UITableViewDataSource> { UITableView *_tableView; NSMutableArray *_dataSource; } @end @implementation ZLTViewController - (void)viewDidLoad { [super viewDidLoad]; //配置列表須要展現的數據,真實項目中這部分數據每每來自文件或者網絡 [self initdata]; _tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStyleGrouped]; //設置列表數據源 _tableView.dataSource = self; [self.view addSubview:_tableView]; } - (void)initdata { UserEntity *entity1 = [[UserEntity alloc] initWithName:@"user1" Phone:@"11111111111"]; UserEntity *entity2 = [[UserEntity alloc] initWithName:@"user2" Phone:@"11111111112"]; UserGroup *group1 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity1,entity2, nil] GroupIdentifier:@"1" GroupIntro:@"this is group1"]; UserEntity *entity3 = [[UserEntity alloc] initWithName:@"user3" Phone:@"11111111113"]; UserEntity *entity4 = [[UserEntity alloc] initWithName:@"user4" Phone:@"11111111114"]; UserEntity *entity5 = [[UserEntity alloc] initWithName:@"user5" Phone:@"11111111115"]; UserGroup *group2 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity3,entity4,entity5, nil] GroupIdentifier:@"2" GroupIntro:@"this is group2"]; UserEntity *entity6 = [[UserEntity alloc] initWithName:@"user6" Phone:@"11111111116"]; UserEntity *entity7 = [[UserEntity alloc] initWithName:@"user7" Phone:@"11111111117"]; UserGroup *group3 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity6,entity7, nil] GroupIdentifier:@"3" GroupIntro:@"this is group3"]; UserEntity *entity8 = [[UserEntity alloc] initWithName:@"user8" Phone:@"11111111118"]; UserGroup *group4 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity8,nil] GroupIdentifier:@"4" GroupIntro:@"this is group4"]; UserEntity *entity9 = [[UserEntity alloc] initWithName:@"user9" Phone:@"11111111119"]; UserEntity *entity10 = [[UserEntity alloc] initWithName:@"user10" Phone:@"111111111110"]; UserEntity *entity11 = [[UserEntity alloc] initWithName:@"user11" Phone:@"111111111111"]; UserGroup *group5 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity9,entity10,entity11, nil] GroupIdentifier:@"5" GroupIntro:@"this is group5"]; _dataSource = [NSMutableArray arrayWithObjects:group1,group2,group3,group4,group5, nil]; } //返回列表分組數,默認爲1 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return [_dataSource count]; } //返回列表每一個分組section擁有cell行數 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [((UserGroup *)_dataSource[section]).userEntities count]; } //配置每一個cell,隨着用戶拖拽列表,cell將要出如今屏幕上時此方法會不斷調用返回cell - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *identifier = @"mycell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier]; } UserGroup *group = _dataSource[indexPath.section]; UserEntity *entity = group.userEntities[indexPath.row]; cell.detailTextLabel.text = entity.phone; cell.textLabel.text = entity.name; //給cell設置accessoryType或者accessoryView //也能夠不設置,這裏純粹爲了展現cell的經常使用可設置選項 if (indexPath.section == 0 && indexPath.row == 0) { cell.accessoryType = UITableViewCellAccessoryDetailButton; }else if (indexPath.section == 0 && indexPath.row == 1) { cell.accessoryView = [[UISwitch alloc] initWithFrame:CGRectZero]; } else { cell.accessoryType = UITableViewCellAccessoryNone; } //設置cell沒有選中效果 cell.selectionStyle = UITableViewCellSelectionStyleNone; return cell; } //返回列表每一個分組頭部說明 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ return [_dataSource[section] groupIdentifier]; } //返回列表每一個分組尾部說明 - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { return [_dataSource[section] groupIntro]; } @end
你們在使用iPhone通信錄時會發現右側能夠按字母檢索,使用起來很方便,其實這個功能使用UITableView實現很簡單,只要實現數據源協議的一個方法,構建一個分組標題的數組便可實現。數組元素的內容和組標題內容未必徹底一致,UITableView是按照數組元素的索引和每組數據索引順序來定位的而不是按內容查找。
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { NSMutableArray *array = [NSMutableArray array]; [_dataSource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [array addObject:[obj groupIdentifier]]; }]; return array; }
須要注意的是上面幾個重點方法的執行順序,請看下圖:
代理
數據源足以用來顯示列表數據,可是若是咱們須要改變sectionheader或者sectionfooter的高度,樣式 ,以及處理cell點擊事件還須要設置列表的代理UITableViewDelegate
@interface ZLTViewController ()<UITableViewDataSource,UITableViewDelegate> { UITableView *_tableView; NSMutableArray *_dataSource; } @end @implementation ZLTViewController - (void)viewDidLoad { [super viewDidLoad]; //配置列表須要展現的數據,真實項目中這部分數據每每來自文件或者網絡 [self initdata]; _tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStyleGrouped]; //設置列表數據源 _tableView.dataSource = self; //設置列表代理 _tableView.delegate = self; [self.view addSubview:_tableView]; } - (void)initdata { UserEntity *entity1 = [[UserEntity alloc] initWithName:@"user1" Phone:@"11111111111"]; UserEntity *entity2 = [[UserEntity alloc] initWithName:@"user2" Phone:@"11111111112"]; UserGroup *group1 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity1,entity2, nil] GroupIdentifier:@"1" GroupIntro:@"this is group1"]; UserEntity *entity3 = [[UserEntity alloc] initWithName:@"user3" Phone:@"11111111113"]; UserEntity *entity4 = [[UserEntity alloc] initWithName:@"user4" Phone:@"11111111114"]; UserEntity *entity5 = [[UserEntity alloc] initWithName:@"user5" Phone:@"11111111115"]; UserGroup *group2 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity3,entity4,entity5, nil] GroupIdentifier:@"2" GroupIntro:@"this is group2"]; UserEntity *entity6 = [[UserEntity alloc] initWithName:@"user6" Phone:@"11111111116"]; UserEntity *entity7 = [[UserEntity alloc] initWithName:@"user7" Phone:@"11111111117"]; UserGroup *group3 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity6,entity7, nil] GroupIdentifier:@"3" GroupIntro:@"this is group3"]; UserEntity *entity8 = [[UserEntity alloc] initWithName:@"user8" Phone:@"11111111118"]; UserGroup *group4 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity8,nil] GroupIdentifier:@"4" GroupIntro:@"this is group4"]; UserEntity *entity9 = [[UserEntity alloc] initWithName:@"user9" Phone:@"11111111119"]; UserEntity *entity10 = [[UserEntity alloc] initWithName:@"user10" Phone:@"111111111110"]; UserEntity *entity11 = [[UserEntity alloc] initWithName:@"user11" Phone:@"111111111111"]; UserGroup *group5 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity9,entity10,entity11, nil] GroupIdentifier:@"5" GroupIntro:@"this is group5"]; _dataSource = [NSMutableArray arrayWithObjects:group1,group2,group3,group4,group5, nil]; } //返回列表分組數,默認爲1 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return [_dataSource count]; } //返回列表每一個分組section擁有cell行數 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [((UserGroup *)_dataSource[section]).userEntities count]; } //配置每一個cell,隨着用戶拖拽列表,cell將要出如今屏幕上時此方法會不斷調用返回cell - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *identifier = @"mycell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier]; } UserGroup *group = _dataSource[indexPath.section]; UserEntity *entity = group.userEntities[indexPath.row]; cell.detailTextLabel.text = entity.phone; cell.textLabel.text = entity.name; //給cell設置accessoryType或者accessoryView //也能夠不設置,這裏純粹爲了展現cell的經常使用可設置選項 // if (indexPath.section == 0 && indexPath.row == 0) { // cell.accessoryType = UITableViewCellAccessoryDetailButton; // }else if (indexPath.section == 0 && indexPath.row == 1) { // cell.accessoryView = [[UISwitch alloc] initWithFrame:CGRectZero]; // } else { // cell.accessoryType = UITableViewCellAccessoryNone; // } //設置cell沒有選中效果 cell.selectionStyle = UITableViewCellSelectionStyleNone; return cell; } //返回列表每一個分組頭部說明 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ return [_dataSource[section] groupIdentifier]; } //返回列表每一個分組尾部說明 - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { return [_dataSource[section] groupIntro]; } - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { NSMutableArray *array = [NSMutableArray array]; [_dataSource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [array addObject:[obj groupIdentifier]]; }]; return array; } //設置cell的高度 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 60; } //設置sectionheader的高度 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { if (section == 0) { return 60; } return 40; } //設置sectionfooter的高度 - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { return 40; } //設置cell的點擊事件 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:nil cancelButtonTitle:@"肯定" otherButtonTitles:nil]; alertView.alertViewStyle = UIAlertViewStylePlainTextInput; UITextField *text = [alertView textFieldAtIndex:0]; UserGroup *group = _dataSource[indexPath.section]; NSString *phone = [group.userEntities[indexPath.row] phone]; [text setText:phone]; [alertView show]; } //自定義sectionheader顯示的view //- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { // UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; // [view setBackgroundColor:[UIColor greenColor]]; // return view; //} //自定義sectionfooter顯示的view //- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { // UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; // [view setBackgroundColor:[UIColor yellowColor]]; // return view; //} @end
因爲實現了tableView:didSelectRowAtIndexPath: ,因此點擊某個cell後會alert出聯繫人的屬性"phone"
修改,刪除,添加和排序
UITableView除了顯示數據外,每每還提供了更多的交互。
修改數據:當咱們點擊cell後彈出alertview,在alertView中能夠設置號碼屬性,修改完後調用reloadRowsAtIndexPaths對界面進行局部更新
//設置cell的點擊事件 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { _indexPath = indexPath; UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"肯定",nil]; alertView.alertViewStyle = UIAlertViewStylePlainTextInput; UITextField *text = [alertView textFieldAtIndex:0]; UserGroup *group = _dataSource[indexPath.section]; NSString *phone = [group.userEntities[indexPath.row] phone]; [text setText:phone]; [alertView show]; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { if (buttonIndex == 1) { UITextField *field = [alertView textFieldAtIndex:0]; NSString *phone = [field text]; UserGroup *group = _dataSource[_indexPath.section]; UserEntity *entity = group.userEntities[_indexPath.row]; [entity setPhone:phone]; //[_tableView reloadData]; [_tableView reloadRowsAtIndexPaths:@[_indexPath] withRowAnimation:UITableViewRowAnimationFade]; } }
除了局部indexpath的更新外,UITableview還提供了reloadData來進行整個列表的更新,可是這種更新確定比局部更新更耗資源
刪除,添加數據:經過setEditing:YES可讓列表處於編輯狀態,咱們能夠設置方法
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
的返回值肯定編輯風格是刪除仍是添加,默認狀態下該方法返回的編輯風格是刪除風格UITableViewCellEditingStyleDelete
咱們在根視圖上添加一個toolbar,toolbar上放置刪除和添加兩個按鈕,當點擊按鈕後設置相應的編輯風格,而後讓列表進入編輯狀態
@interface ZLTViewController ()<UITableViewDataSource,UITableViewDelegate> { UITableView *_tableView; NSMutableArray *_dataSource; NSIndexPath *_indexPath; UIToolbar *_toolbar; //判斷當前處於的狀態 BOOL *_isAdd; } @end @implementation ZLTViewController - (void)viewDidLoad { [super viewDidLoad]; //配置列表須要展現的數據,真實項目中這部分數據每每來自文件或者網絡 [self initdata]; _tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStyleGrouped]; //設置列表數據源 _tableView.dataSource = self; //設置列表代理 _tableView.delegate = self; //爲了避免遮擋toolbar,tableview的內容顯示區域向下移動44個像素 _tableView.contentInset = UIEdgeInsetsMake(44, 0, 0, 0); [self.view addSubview:_tableView]; [self setToolbar]; } - (void)setToolbar { _toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)]; [self.view addSubview:_toolbar]; UIBarButtonItem *deleteItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(delete)]; UIBarButtonItem *flexibleItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; UIBarButtonItem *addItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add)]; _toolbar.items = @[deleteItem,flexibleItem,addItem]; } - (void)initdata { UserEntity *entity1 = [[UserEntity alloc] initWithName:@"user1" Phone:@"11111111111"]; UserEntity *entity2 = [[UserEntity alloc] initWithName:@"user2" Phone:@"11111111112"]; UserGroup *group1 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity1,entity2, nil] GroupIdentifier:@"1" GroupIntro:@"this is group1"]; UserEntity *entity3 = [[UserEntity alloc] initWithName:@"user3" Phone:@"11111111113"]; UserEntity *entity4 = [[UserEntity alloc] initWithName:@"user4" Phone:@"11111111114"]; UserEntity *entity5 = [[UserEntity alloc] initWithName:@"user5" Phone:@"11111111115"]; UserGroup *group2 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity3,entity4,entity5, nil] GroupIdentifier:@"2" GroupIntro:@"this is group2"]; UserEntity *entity6 = [[UserEntity alloc] initWithName:@"user6" Phone:@"11111111116"]; UserEntity *entity7 = [[UserEntity alloc] initWithName:@"user7" Phone:@"11111111117"]; UserGroup *group3 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity6,entity7, nil] GroupIdentifier:@"3" GroupIntro:@"this is group3"]; UserEntity *entity8 = [[UserEntity alloc] initWithName:@"user8" Phone:@"11111111118"]; UserGroup *group4 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity8,nil] GroupIdentifier:@"4" GroupIntro:@"this is group4"]; UserEntity *entity9 = [[UserEntity alloc] initWithName:@"user9" Phone:@"11111111119"]; UserEntity *entity10 = [[UserEntity alloc] initWithName:@"user10" Phone:@"111111111110"]; UserEntity *entity11 = [[UserEntity alloc] initWithName:@"user11" Phone:@"111111111111"]; UserGroup *group5 = [[UserGroup alloc] initWithEntities:[NSMutableArray arrayWithObjects:entity9,entity10,entity11, nil] GroupIdentifier:@"5" GroupIntro:@"this is group5"]; _dataSource = [NSMutableArray arrayWithObjects:group1,group2,group3,group4,group5, nil]; } //返回列表分組數,默認爲1 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return [_dataSource count]; } //返回列表每一個分組section擁有cell行數 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [((UserGroup *)_dataSource[section]).userEntities count]; } //配置每一個cell,隨着用戶拖拽列表,cell將要出如今屏幕上時此方法會不斷調用返回cell - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *identifier = @"mycell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier]; } UserGroup *group = _dataSource[indexPath.section]; UserEntity *entity = group.userEntities[indexPath.row]; cell.detailTextLabel.text = entity.phone; cell.textLabel.text = entity.name; //給cell設置accessoryType或者accessoryView //也能夠不設置,這裏純粹爲了展現cell的經常使用可設置選項 // if (indexPath.section == 0 && indexPath.row == 0) { // cell.accessoryType = UITableViewCellAccessoryDetailButton; // }else if (indexPath.section == 0 && indexPath.row == 1) { // cell.accessoryView = [[UISwitch alloc] initWithFrame:CGRectZero]; // } else { // cell.accessoryType = UITableViewCellAccessoryNone; // } //設置cell沒有選中效果 cell.selectionStyle = UITableViewCellSelectionStyleNone; return cell; } //返回列表每一個分組頭部說明 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ return [_dataSource[section] groupIdentifier]; } //返回列表每一個分組尾部說明 - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { return [_dataSource[section] groupIntro]; } - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { NSMutableArray *array = [NSMutableArray array]; [_dataSource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [array addObject:[obj groupIdentifier]]; }]; return array; } //設置cell的高度 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 60; } //設置sectionheader的高度 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { if (section == 0) { return 60; } return 40; } //設置sectionfooter的高度 - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { return 40; } //設置cell的點擊事件 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { _indexPath = indexPath; UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"肯定",nil]; alertView.alertViewStyle = UIAlertViewStylePlainTextInput; UITextField *text = [alertView textFieldAtIndex:0]; UserGroup *group = _dataSource[indexPath.section]; NSString *phone = [group.userEntities[indexPath.row] phone]; [text setText:phone]; [alertView show]; } //自定義sectionheader顯示的view //- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { // UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; // [view setBackgroundColor:[UIColor greenColor]]; // return view; //} //自定義sectionfooter顯示的view //- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { // UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; // [view setBackgroundColor:[UIColor yellowColor]]; // return view; //} //設置編輯風格 - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { if (_isAdd) { return UITableViewCellEditingStyleInsert; } else { return UITableViewCellEditingStyleDelete; } } //處理添加和刪除的代碼 -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { UserGroup *group = _dataSource[indexPath.section]; [group.userEntities removeObjectAtIndex:indexPath.row]; [_tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; if ([group.userEntities count] == 0) { [_dataSource removeObjectAtIndex:indexPath.section]; [_tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationBottom]; } } else if(editingStyle == UITableViewCellEditingStyleInsert) { UserGroup *group = _dataSource[indexPath.section]; [group.userEntities insertObject:[[UserEntity alloc] initWithName:@"new user" Phone:@"137xxxxxxxx"] atIndex:indexPath.row]; [_tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft]; } } //刪除 - (void)delete { _isAdd = NO; [_tableView setEditing:!_tableView.isEditing animated:YES]; } //添加 - (void)add { _isAdd = YES; [_tableView setEditing:!_tableView.isEditing animated:YES]; } //修改 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { if (buttonIndex == 1) { UITextField *field = [alertView textFieldAtIndex:0]; NSString *phone = [field text]; UserGroup *group = _dataSource[_indexPath.section]; UserEntity *entity = group.userEntities[_indexPath.row]; [entity setPhone:phone]; //[_tableView reloadData]; [_tableView reloadRowsAtIndexPaths:@[_indexPath] withRowAnimation:UITableViewRowAnimationFade]; } } @end
排序:當實現- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
方法後,列表處於編輯狀態時就能夠移動cell
背景view
當咱們刪除完列表中全部的數據,或者列表中原本就沒有數據時能夠設置一個背景,好比顯示一個logo
UITableView有個屬性爲backgroundView,咱們能夠經過這個屬性設置列表的背景視圖,當加載完數據或者對數據進行了刪除添加操做後判斷數據源中有沒有數據,若是沒有則在tableview中心處顯示"暫時沒有數據",若是有則不顯示
- (void)viewDidLoad { [super viewDidLoad]; //配置列表須要展現的數據,真實項目中這部分數據每每來自文件或者網絡 [self initdata]; _tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStyleGrouped]; //設置列表數據源 _tableView.dataSource = self; //設置列表代理 _tableView.delegate = self; //爲了避免遮擋toolbar,tableview的內容顯示區域向下移動44個像素 _tableView.contentInset = UIEdgeInsetsMake(44, 0, 0, 0); UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 44)]; label.tag = 1; label.text = @"暫時沒有數據"; label.textAlignment = NSTextAlignmentCenter; [label setTextColor:[UIColor lightGrayColor]]; [view addSubview:label]; _tableView.backgroundView = view; label.center = view.center; if ([_dataSource count] != 0) { [[_tableView.backgroundView viewWithTag:1] setHidden:YES]; } [self.view addSubview:_tableView]; [self setToolbar]; } -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { UserGroup *group = _dataSource[indexPath.section]; [group.userEntities removeObjectAtIndex:indexPath.row]; [_tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; if ([group.userEntities count] == 0) { [_dataSource removeObjectAtIndex:indexPath.section]; [_tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationBottom]; } } else if(editingStyle == UITableViewCellEditingStyleInsert) { UserGroup *group = _dataSource[indexPath.section]; [group.userEntities insertObject:[[UserEntity alloc] initWithName:@"new user" Phone:@"137xxxxxxxx"] atIndex:indexPath.row]; [_tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft]; } if ([_dataSource count] == 0) { [[_tableView.backgroundView viewWithTag:1] setHidden:NO]; } else { [[_tableView.backgroundView viewWithTag:1] setHidden:YES]; } }
自定義cell
UITableViewCell是構建一個UITableView的基礎,在UITableViewCell內部有一個UIView控件做爲其餘內容的容器,它上面有一個UIImageView和兩個UILabel,經過UITableViewCellStyle屬性能夠對其樣式進行控制。其結構以下:
有時候咱們會發現不少UITableViewCell右側能夠顯示不一樣的圖標,在iOS中稱之爲訪問器,點擊能夠觸發不一樣的事件,例如設置功能:
要設置這些圖標只須要設置UITableViewCell的accesoryType屬性,這是一個枚舉類型具體含義以下:
typedef NS_ENUM(NSInteger, UITableViewCellAccessoryType) { UITableViewCellAccessoryNone, // 不顯示任何圖標 UITableViewCellAccessoryDisclosureIndicator, // 跳轉指示圖標 UITableViewCellAccessoryDetailDisclosureButton, // 內容詳情圖標和跳轉指示圖標 UITableViewCellAccessoryCheckmark, // 勾選圖標 UITableViewCellAccessoryDetailButton NS_ENUM_AVAILABLE_IOS(7_0) // 內容詳情圖標 };
顯然系統提供的幾種樣式是沒法知足各類功能繁多的應用的,咱們須要自定義本身的cell
自定義cell的方式有不少,有純代碼的實現,也有經過xib實現或者經過storyboard實現,這裏介紹使用storyboard,這也是最方便的方式
1:新建兩個文件:CustomTableCellController(繼承UIViewController) CustomTableCell(繼承UITableViewCell)
2:在storyboard中新加入一個ViewController,file owner爲CustomTableCellView
3:拖入一個tableView,設置一個prototype cell
4:在cell中拖入兩個label,而且設置cell的class爲CustomTableCell,並設置一個identifier
5:CustomTableCell
@interface CustomTableCell : UITableViewCell @property (weak, nonatomic) IBOutlet UILabel *label1; @property (weak, nonatomic) IBOutlet UILabel *label2; -(void)setContent:(NSDictionary *)dic; @end @implementation CustomTableCell - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { // Initialization code } return self; } -(void)setContent:(NSDictionary *)dic { NSString *label1 = dic[@"label1"]; NSString *lable2 = dic[@"label2"]; [_label1 setText:label1]; CGSize textSize=[lable2 boundingRectWithSize:CGSizeMake(226, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:17]} context:nil].size; _label2.frame = CGRectMake(_label2.frame.origin.x, _label2.frame.origin.y, _label2.frame.size.width, textSize.height); _label2.text = lable2; } @end
6: CustomTableCellController
@interface CustomTableCellController ()<UITableViewDelegate,UITableViewDataSource> { NSArray *_array; } @property (weak, nonatomic) IBOutlet UITableView *tableView; @end @implementation CustomTableCellController - (void)viewDidLoad { [super viewDidLoad]; _array = @[@{@"label1": @"靜夜思",@"label2":@"牀前明月光,疑是地上霜。舉頭望明月,低頭思故鄉。"},@{@"label1": @"早秋",@"label2":@"遙夜泛清瑟,西風生翠蘿。殘螢棲玉露,早雁拂金河。高樹曉還密,遠山晴更多。 淮南一葉下,自覺洞庭波。"}]; _tableView.delegate = self; _tableView.dataSource = self; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 2; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { CustomTableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"customcell" forIndexPath:indexPath]; [cell setContent:_array[indexPath.row]]; return cell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { CGSize textSize=[_array[indexPath.row][@"label2"] boundingRectWithSize:CGSizeMake(226, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:17]} context:nil].size; return textSize.height + 10; } @end
UITableViewController
不少時候一個UIViewController中只有一個UITableView,所以蘋果官方爲了方便你們開發直接提供了一個UITableViewController,這個控制器 UITableViewController實現了UITableView數據源和代理協議,內部定義了一個tableView屬性供外部訪問,同時自動鋪滿整個屏幕、自動伸縮以方便咱們的開發。固然UITableViewController也並非簡單的幫咱們定義完UITableView而且設置了數據源、代理而已,它還有其餘強大的功能,例如刷新控件、滾動過程當中固定分組標題等。
有時候一個表格中的數據特別多,檢索起來就顯得麻煩,這個時候能夠實現一個搜索功能幫助用戶查找數據,其實搜索的原理很簡單:修改模型、刷新表格。下面使用UITableViewController簡單演示一下這個功能:
@interface CustomTableViewController : UITableViewController @end @interface CustomTableViewController ()<UISearchBarDelegate> { UISearchBar *_searchBar; //數據源 NSArray *_datasource; //存放符合篩選條件的數據源 NSMutableArray *_filterdatasource; //searcbar是否處於搜索狀態,這個布爾值決定使用_datasource仍是_filterdatasource BOOL _isSearching; } @end @implementation CustomTableViewController - (void)viewDidLoad { [super viewDidLoad]; _datasource = @[@[@"zanglitao",@"zang",@"li",@"tao"],@[@"male"]]; _filterdatasource = [NSMutableArray array]; _searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)]; _searchBar.delegate = self; _searchBar.showsCancelButton = YES; _searchBar.placeholder = @"輸入關鍵字"; //_searchBar.keyboardType = UIKeyboardTypeAlphabet;//鍵盤類型 //_searchBar.autocorrectionType = UITextAutocorrectionTypeNo;//自動糾錯類型 //_searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;//哪一次shitf被自動按下 self.tableView.tableHeaderView = _searchBar; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { if (_isSearching) { return 1; } return [_datasource count]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (_isSearching) { return [_filterdatasource count]; } return [_datasource[section] count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *identifier = @"cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; } if (_isSearching) { cell.textLabel.text = _filterdatasource[indexPath.row]; } else { cell.textLabel.text = _datasource[indexPath.section][indexPath.row]; } return cell; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { if (_isSearching) { return @"搜索結果"; } return [NSString stringWithFormat:@"%d",section]; } #pragma mark - Search bar delegate //searchbar開始處於編輯狀態時調用 - (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar { [_filterdatasource removeAllObjects]; _isSearching = YES; [self.tableView reloadData]; } //searchbar內容改變時調用 - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { [_filterdatasource removeAllObjects]; [_datasource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [obj enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSString *str = [(NSString *)obj uppercaseString]; if ([str rangeOfString:[searchText uppercaseString]].location != NSNotFound) { [_filterdatasource addObject:obj]; } }]; }]; [self.tableView reloadData]; } //點擊searchbar的cancel按鈕時調用 - (void)searchBarCancelButtonClicked:(UISearchBar *) searchBar{ [searchBar resignFirstResponder]; [searchBar setText:@""]; _isSearching = NO; [self.tableView reloadData]; } //點擊搜索 - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { [searchBar resignFirstResponder]; } @end
UISearchDisplayController
在上面的搜索中每次搜索完後都須要手動刷新表格來顯示搜索結果,咱們要用一個tableView顯示兩種狀態的不一樣數據,提升了程序邏輯複雜度。爲了簡化這個過程,咱們可使用UISearchDisplayController,UISearchDisplayController內部也有一個UITableView類型的對象searchResultsTableView,若是咱們設置它的數據源代理爲當前控制器,那麼它徹底能夠像UITableView同樣加載數據。同時它自己也有搜索監聽的方法,咱們沒必要在監聽UISearchBar輸入內容,直接使用它的方法便可自動刷新其內部表格。
@interface CustomSearchBarTableViewController : UITableViewController @end @interface CustomSearchBarTableViewController ()<UISearchDisplayDelegate,UISearchBarDelegate> { //數據源 NSArray *_datasource; //存放符合篩選條件的數據源 NSMutableArray *_filterdatasource; UISearchDisplayController *_searchController; UISearchBar *_searchBar; } @end @implementation CustomSearchBarTableViewController - (void)viewDidLoad { [super viewDidLoad]; _datasource = @[@[@"zanglitao",@"zang",@"li",@"tao"],@[@"male"]]; _filterdatasource = [NSMutableArray array]; _searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)]; _searchBar.delegate = self; _searchBar.showsCancelButton = YES; _searchBar.placeholder = @"輸入關鍵字"; self.tableView.tableHeaderView = _searchBar; _searchController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar contentsController:self]; _searchController.delegate = self; //設置內部tableView的delegate _searchController.searchResultsDelegate = self; //設置內部tableview的datasource _searchController.searchResultsDataSource = self; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { if (tableView == _searchController.searchResultsTableView) { return 1; } return [_datasource count]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (tableView == _searchController.searchResultsTableView) { return [_filterdatasource count]; } return [_datasource[section] count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *identifier = @"cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; } if (tableView == _searchController.searchResultsTableView) { cell.textLabel.text = _filterdatasource[indexPath.row]; } else { cell.textLabel.text = _datasource[indexPath.section][indexPath.row]; } return cell; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { if (tableView == _searchController.searchResultsTableView) { return @"搜索結果"; } return [NSString stringWithFormat:@"%d",section]; } #pragma mark - Search bar controller delegate -(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{ [_filterdatasource removeAllObjects]; [_datasource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [obj enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSString *str = [(NSString *)obj uppercaseString]; if ([str rangeOfString:[searchString uppercaseString]].location != NSNotFound) { [_filterdatasource addObject:obj]; } }]; }]; return YES; } @end
下拉刷新
下拉刷新是列表最多見的一種交互,IOS平臺上第三方下拉刷新控件至關多,比較經常使用的有egorefresh,ios6以後新添加了UIRfreshControl控件,可是隻能用在UITableViewController中
- (void)setRefrshController { self.refreshControl = [[UIRefreshControl alloc] init]; [self.refreshControl setAttributedTitle:[[NSAttributedString alloc] initWithString:@"下拉刷新"]]; [self.refreshControl addTarget:self action:@selector(refreshViewControlEventValueChanged) forControlEvents:UIControlEventValueChanged]; } - (void)refreshViewControlEventValueChanged { //模擬從新加載數據 [NSThread sleepForTimeInterval:3]; //修改refreshControl狀態 [self.refreshControl endRefreshing]; //更新列表 [self.tableView reloadData]; }
靜態tableviewcell
有時候咱們只想簡單顯示幾行數據,這時候能夠藉助storyboard使用靜態單元格
1:在storyboard拖出一個UITableViewController(只有UITableViewController支持靜態單元格),並設置UITableView中tableView的相關屬性
2:點擊tableviewcell後能夠隨意的設置屬性,而且把控件添加上去
3:運行後直接顯示咱們設置的靜態列表
說明:使用靜態列表不須要實現代理方法和數據源方法,可是一旦實現了代理方法和數據源方法,那麼列表會與咱們代理和數據源方法中設置的一致