一、uitableview簡單介紹
1.tableview是一個用戶可以滾動的多行單列列表,在表視圖中,每一行都是一個uitableviewcell對象,表視圖有兩種風格可選
typedef ns_enum(nsinteger, uitableviewstyle) {
uitableviewstyleplain, // regular table view
uitableviewstylegrouped // preferences style table view
};
2.表視圖還可為其添加索引值,比如通訊錄中右側索引列表,每一個索引項對應其節頭標題
這兩種形式的列表下面還會介紹到。
3.最簡單的一種表視圖是一個選擇列表,可以限制選擇一列或多列,如上圖右邊。
4.頁眉和頁腳,可以根據自己的需要,對tableview設置頁眉和頁腳的內容
二、uitableviewcell
1. uitableviewcell是表視圖的單元格,系統會緩存可見的行。通過完成uitableviewdatasource協議中必須完成的代理方法cellforrowatindexpath方法來填充表視圖上單元格數據。
2. uitableviewcell有四種樣式可選
uitableviewcellstyledefault, // 簡單包含一個可選的imageview和一個label顯示文本
uitableviewcellstylevalue1, // 包含可選的imageview,一個textlabel和一個detaillabel,其中detaillabel位置在最左,右對齊,文本顏色為藍色
uitableviewcellstylevalue2, //包含一個textlabel和一個detaillabel,textlabel默認為藍色文本,右對齊,detaillabel的位置緊挨著textlabel右邊,默認文本左對齊,顏色為黑色
uitableviewcellstylesubtitle // 包含可選的imageview,一個textlabel,一個detaillabel,其中detaillabel在textlabel下方,字體較小,默認顏色為黑色,左對齊
三、創建簡單tableview
1. 先給出效果圖
2. 創建方式及代碼(本文只講述代碼創建)
a) 創建一個single view application,命名為"tableview"
b) 新建一個繼承自uitableview的類,關于tableview的實現將全部寫在這個類中(當然也可直接在對 應所需要用得viewcontroller中創建,分離出來的好處是可以在將tableview的方法單獨放在一個類中,當viewcontroller的代碼量比較大或者這個table需要在多個地方使用時推薦使用),命名為general_table_view.
c) 代碼
①在general_table_view.h文件中,添加幾個屬性
@interface general_table_view : uitableview
// tableview的坐標
@property (nonatomic, assign) cgrect tableviewframe;
// 存放cell上各行textlabel值
@property (nonatomic, copy)nsmutablearray * textlabel_marray;
// 存放cell上各行imageview上圖片
@property (nonatomic, copy)nsmutablearray * images_marray;
// 存放cell上各行detaillabel值
@property (nonatomic, copy)nsmutablearray * subtitle_marray;
@end
②在general_table_view.m的interface中聲明代理
@interface general_table_view ()<uitableviewdatasource,uitableviewdelegate>
@end
③在.m中的initwithframe方法內部設置table的代理
// initialization code
self.delegate = self;
self.datasource = self;
以及添加tableviewframe的set方法
-(void)settableviewframe:(cgrect)tableviewframe
{
self.frame = tableviewframe;// 設置tableview的frame為所傳值
}
④接下來實現tableview的datasource和delegate方法
必須實現的方法有兩個
// tableview每個分區的行數,可以為各個分區設置不同的行數,根據section的值判斷即可
-(nsinteger)tableview:(uitableview *)tableview numberofrowsinsection:(nsinteger)section
{
return [_textlabel_marray count];
}
// 實現每一行cell的內容,tableview重用機制
-(uitableviewcell *)tableview:(uitableview *)tableview cellforrowatindexpath:(nsindexpath *)indexpath
{
// 為其定義一個標識符,在重用機制中,標識符非常重要,這是系統用來匹配table各行cell的判斷標準,在以后的學習中會體會到
static nsstring *cellidentifier = @"cellidentifier";
// 從緩存隊列中取出復用的cell
uitableviewcell *cell = [tableview dequeuereusablecellwithidentifier:cellidentifier];
// 如果隊列中cell為空,即無復用的cell,則對其進行初始化
if (cell==nil) {
// 初始化
cell = [[uitableviewcell alloc] initwithstyle:uitableviewcellstyledefault reuseidentifier:cellidentifier];
// 定義其輔助樣式
cell.accessorytype = uitableviewcellaccessorynone;
}
// 設置cell上文本內容
cell.textlabel.text = [_textlabel_marray objectatindex:indexpath.row];
return cell;
}
⑤還有其他輔助方法,根據需要添加
// tableview分區數量,默認為1,可為其設置為多個分區
-(nsinteger)numberofsectionsintableview:(uitableview *)tableview
{
return 1;
}
// tableview頁眉的值,同理,可為不同的分區設置不同的頁眉,也可不寫此方法
-(nsstring *)tableview:(uitableview *)tableview titleforheaderinsection:(nsinteger)section
{
return @"頁眉";
}
// 頁腳
-(nsstring *)tableview:(uitableview *)tableview titleforfooterinsection:(nsinteger)section
{
return @"頁腳";
}
⑥在所需要添加的viewcontroller中添加tableview,在viewcontroller.m方法中
#import "general_table_view.h"
@interface viewcontroller ()
{
general_table_view *table;// 聲明table
}
@end
并在viewdidload方法中對其進行初始化
// 初始化
table = [[general_table_view alloc] initwithframe:cgrectmake(0, 20, 320, self.view.frame.size.height-20) style:uitableviewstyleplain];
// 設置數據源
table.textlabel_marray = [[nsmutablearray alloc] initwithobjects:@"南京市",@"南通市",@"淮安市",@"鎮江市",@"揚州市",@"常州市", nil];
[self.view addsubview:table];// 添加到當前view
⑦運行即可得到圖5的效果,將初始化時的style改為uitableviewstylegrouped即可得到圖6的效果
// 初始化
table = [[general_table_view alloc] initwithframe:cgrectmake(0, 20, 320, self.view.frame.size.height-20) style:uitableviewstylegrouped];
四、為每一行添加圖片
在viewcontroller.m的viewdidload方法中設置數據源時,在addsubview之前,初始化一個存放圖片的數組,這里我添加的是同一張圖片,如果想為每一行設置不同的圖片,添加不同的圖片到數組中即可
nsmutablearray *images = [nsmutablearray array];
for(nsinteger index = 0;index<[table.textlabel_marray count];index++){
uiimage *image = [uiimage imagenamed:@"2"];
[images addobject:image];
}
table.images_marray = [[nsmutablearray alloc] initwitharray:images];
在cellforrowatindexpath方法中設置textlabel值部分添加
// 設置cell上文本內容
cell.textlabel.text = [_textlabel_marray objectatindex:indexpath.row];
// 設置每一行的圖片
cell.imageview.image = [_images_marray objectatindex:indexpath.row];
五、列表的其他樣式
在cellforrowatindexpath方法中,初始化cell時改變cell的style和accessorytype,style,style默認有四種可選。
在viewcontroller的viewdidload方法中添加圖片的for循環中為數組添加值
nsmutablearray *subtitle= [nsmutablearray array];
for(nsinteger index = 0;index<[table.textlabel_marray count];index++){
uiimage *image = [uiimage imagenamed:@"2"];
nsstring *detail = [nsstring stringwithformat:@"detail text %d",index+1];
[images addobject:image];
[subtitle addobject:detail];
}
table.subtitle_marray = [[nsmutablearray alloc] initwitharray:subtitle];
并在cellforrowatindexpath方法初始化時將
uitableviewcellstyledefault改變成其他三種樣式,并添加代碼
// 設置小標題
cell.detailtextlabel.text = [_subtitle_marray objectatindex:indexpath.row];
效果圖如下:
六、列表中行的操作
1.選中行
實現代理方法
// 選中行
-(void)tableview:(uitableview *)tableview didselectrowatindexpath:(nsindexpath *)indexpath
{
nslog(@"您點擊了第%d分區第%d行",indexpath.section, indexpath.row);
// 取消選中狀態
// [tableview deselectrowatindexpath:indexpath animated:yes];
}
2.刪除行
要對行進行操作,首先要實現代理方法
- (bool)tableview:(uitableview *)tableview caneditrowatindexpath:(nsindexpath *)indexpath
{
return yes;
}
先講述單獨刪除一行數據,即左滑出現刪除按鈕,并刪除行的操作,后文會介紹多選批量刪除
可重置刪除按鈕的標題,默認為"delete"
// 設置刪除按鈕標題
- (nsstring *)tableview:(uitableview *)tableview titlefordeleteconfirmationbuttonforrowatindexpath:(nsindexpath *)indexpath
{
return @"刪除";
}
點擊刪除后
- (void)tableview:(uitableview *)tableview commiteditingstyle:(uitableviewcelleditingstyle)editingstyle forrowatindexpath:(nsindexpath *)indexpath
{
// 從數據源中刪除
[self.dataarray removeobjectatindex:indexpath.row];
// 從列表中刪除
[tableview deleterowsatindexpaths:@[indexpath] withrowanimation:uitableviewrowanimationfade];
}
3.插入行
①這時我將插入行和刪除行都以一個按鈕動作來觸發,點擊后tableview進入編輯模式,先上效果圖
②在viewdidload中添加代碼,其中self.addbutton和self.deletebarbuttonitem均在storyboard中創建,下文中的按鈕也是這種情況
nsarray *leftbarbuttons = [nsarray arraywithobjects:self.addbutton,self.deletebarbuttonitem, nil];
self.navigationitem.leftbarbuttonitems = leftbarbuttons;//設置導航欄左邊按鈕為添加和刪除按鈕
③在@interface中聲明一個變量
uitableviewcelleditingstyle selecteditingstyle;
④兩個按鈕的點擊事件
// 更新導航欄按鈕
-(void) updatebarbuttons
{
if (self.tableview.editing==yes) {
self.navigationitem.rightbarbuttonitem = self.donebarbuttonitem;
}
}
// 點擊添加按鈕
- (ibaction)addbuttonclicked:(id)sender {
selecteditingstyle = uitableviewcelleditingstyleinsert;
[self.tableview setediting:yes animated:yes];
[self updatebarbuttons];
}
// 點擊刪除按鈕
- (ibaction)deletebuttonclicked:(id)sender {
selecteditingstyle = uitableviewcelleditingstyledelete;
[self.tableview setediting:yes animated:yes];
[self updatebarbuttons];
}
⑤實現相應的代理方法
// 是否可編輯
- (bool)tableview:(uitableview *)tableview caneditrowatindexpath:(nsindexpath *)indexpath
{
return yes;
}
// 編輯模式
-(uitableviewcelleditingstyle)tableview:(uitableview *)tableview editingstyleforrowatindexpath:(nsindexpath *)indexpath
{
return selecteditingstyle;
}
- (void)tableview:(uitableview *)tableview commiteditingstyle:(uitableviewcelleditingstyle)editingstyle forrowatindexpath:(nsindexpath *)indexpath
{
// 刪除模式
if (editingstyle==uitableviewcelleditingstyledelete) {
// 從數據源中刪除
[self.dataarray removeobjectatindex:indexpath.row];
// 刪除行
[tableview deleterowsatindexpaths:@[indexpath] withrowanimation:uitableviewrowanimationfade];
}
// 添加模式
else if(editingstyle == uitableviewcelleditingstyleinsert){
// 從數據源中添加
[self.dataarray insertobject:@"new iphone" atindex:indexpath.row];
// 添加行
[self.tableview insertrowsatindexpaths:@[indexpath] withrowanimation:uitableviewrowanimationautomatic ];
}
}
// 點擊完成按鈕
- (ibaction)donebuttonclicked:(id)sender {
[self.tableview setediting:no animated:yes];
[self updatebarbuttons];
}
4.移動行
①效果圖
②在tableview進入編輯模式時,可以對行進行移動操作,通過方法
// 是否支持移動
- (bool)tableview:(uitableview *)tableview canmoverowatindexpath:(nsindexpath *)indexpath
{
return yes;
}
③設置行可移動,并完成移動行方法,改變數據源
// 移動行操作-(void)tableview:(uitableview *)tableview moverowatindexpath:(nsindexpath *)sourceindexpath toindexpath:(nsindexpath *)destinationindexpath{// 這里其實就是數組中兩個變量交換位置的過程 id object = [self.dataarray objectatindex:fromindexpath.row];
[self.dataarray removeobjectatindex:fromindexpath.row];
[self.dataarray insertobject:object atindex:toindexpath.row];
}
5、批量刪除行
①即完成可以選擇多個行之后批量刪除,如圖
②在viewdidload中添加代碼
self.navigationitem.rightbarbuttonitem = self.editbarbuttonitem;// 在右導航欄中添加編輯按鈕
③現在需要達到,點擊編輯按鈕在右上角出現取消按鈕,左上角出現刪除按鈕。并在選擇時,能出現刪除行的數量,修改updatebarbuttons方法,并添加一個方法來根據條件修改刪除按鈕的標題
// 更新導航欄按鈕
-(void) updatebarbuttons
{
// 如果是允許多選的狀態,即進入批量刪除模式
if (self.tableview.allowsselectionduringediting == yes) {
//更新刪除按鈕
[self updatedeletebuttontitle];
// 導航欄左邊按鈕設置為空
self.navigationitem.leftbarbuttonitems = nil;
// 將左邊按鈕設置為'批量刪除'按鈕
self.navigationitem.leftbarbuttonitem = self.multideletebarbutton;
// 導航欄右鍵設置為'取消'鍵
self.navigationitem.rightbarbuttonitem = self.cancelbarbuttonitem;
return;
}
if (self.tableview.editing==yes) {// 如果是編輯狀態,且不屬于批量刪除狀態
// 導航欄右鍵設置為'取消'鍵
self.navigationitem.rightbarbuttonitem = self.donebarbuttonitem;
}
else {// 如果不是編輯狀態,將導航欄設置為初始狀態的樣式,即左欄為'添加','刪除'按鈕,右欄為'編輯'按鈕
nsarray *leftbarbuttons = [nsarray arraywithobjects:self.addbutton,self.deletebarbuttonitem, nil];
self.navigationitem.leftbarbuttonitems = leftbarbuttons;
self.navigationitem.rightbarbuttonitem = self.editbarbuttonitem;
}
}
// 更新刪除按鈕的標題
-(void)updatedeletebuttontitle
{
nsarray *selectedrows = [self.tableview indexpathsforselectedrows];//得到選中行
bool allitemsareselected = selectedrows.count == self.dataarray.count;// 是否全選
bool noitemsareselected = selectedrows.count == 0;// 選中行數是否為零
if (allitemsareselected || noitemsareselected)
{// 如果是全選或者未選,則刪除鍵為刪除全部
self.multideletebarbutton.title = @"刪除全部";
}
else
{// 否則 刪除鍵為刪除(選中行數量)
self.multideletebarbutton.title = [nsstring stringwithformat:@"刪除 (%d)", selectedrows.count];
}
}
④在
-(void)tableview:(uitableview *)tableview didselectrowatindexpath:(nsindexpath *)indexpath
- (void)tableview:(uitableview *)tableview diddeselectrowatindexpath:(nsindexpath *)indexpath
兩個方法中調用updatedeletebuttontitle方法
⑤點擊編輯按鈕時
// 編輯按鈕
- (ibaction)editbuttonclicked:(id)sender {
self.tableview.allowsmultipleselectionduringediting = yes;// 進入可多選刪除狀態
[self.tableview setediting:yes animated:yes];// 將table設置為可編輯
[self updatebarbuttons]; //更改導航欄的導航按鈕
}
⑥點擊刪除多個按鈕時
- (ibaction)multideleteclicked:(id)sender {
// 選中的行
nsarray *selectedrows = [self.tableview indexpathsforselectedrows];
// 是否刪除特定的行
bool deletespecificrows = selectedrows.count > 0;
// 刪除特定的行
if (deletespecificrows)
{
// 將所選的行的索引值放在一個集合中進行批量刪除
nsmutableindexset *indicesofitemstodelete = [nsmutableindexset new];
for (nsindexpath *selectionindex in selectedrows)
{
[indicesofitemstodelete addindex:selectionindex.row];
}
// 從數據源中刪除所選行對應的值
[self.dataarray removeobjectsatindexes:indicesofitemstodelete];
//刪除所選的行
[self.tableview deleterowsatindexpaths:selectedrows withrowanimation:uitableviewrowanimationautomatic];
}
else
{
// 刪除全部
[self.dataarray removeallobjects];
[self.tableview reloadsections:[nsindexset indexsetwithindex:0] withrowanimation:uitableviewrowanimationautomatic];
}
// 刪除完成,退出編輯狀態,并退出多選狀態,同時更新導航欄的按鈕
[self.tableview setediting:no animated:yes];
self.tableview.allowsmultipleselectionduringediting = no;
[self updatebarbuttons];
}