UITableView的詳細講解
1. UITableView的初始化
UITableView tableview= [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 420)];
[tableview setDelegate:self];
[tableview setDataSource:self];
[self.view addSubview: tableview];
[tableview release];
(1)在初始化UITableView的時候必須實現UITableView的是,在.h文件中要繼承UITableViewDelegate和UITableViewDataSource,並實現3個UITableView數據源方法和設置它的delegate爲self,這個是在不直接繼承UITableViewController實現的方法。
(2) 直接在XCODE生成項目的時候繼承UITableViewController的,它會幫你自動寫好UITableView必須要實現的方法。
(3)UITableView繼承自UIScrollView。
2. UITableView的數據源
(1)UITableView是依賴外部資源爲新表格單元填上內容的,我們稱爲數據源,這個數據源可以根據索引路徑提供表格單元格,在UITableView中,索引路徑是NSIndexPath的對象,可以選擇分段或者分行,即是我們編碼中的section和row。
(2)UITableView有三個必須實現的核心方法,分別如下:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
這個方法可以分段顯示或者單個列表顯示我們的數據。如下,左邊爲分段顯示,右邊爲單個列表顯示:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
這個方法返回每個分段的行數,不同分段返回不同的行數可以用switch來做,如果是單個列表就直接返回單個你想要的函數即可。
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
這個方法是返回我們調用的每一個單元格。通過我們索引的路徑的section和row來確定。
3. UITableView的委託方法
使用委託是爲了響應用戶的交互動作,比如下拉更新數據和選擇某一行單元格,在UITableView中有很大這種方法供我們選擇。
(1) 委託方法講解
//設置Section的數量
-(NSArray*)sectionIndexTitlesForTableView:(UITableView *)tableView
//設置每個section顯示的Title
//設置每個section顯示的Title
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *key = [m_titleArrayobjectAtIndex:section];
return key;
}
//指定有多少個分區(Section),默認爲1
//分區的數量
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return4;
}
//指定每個分區中有多少行,默認爲1
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
sectionArray = [myDictionary objectForKey:[m_titleArray objectAtIndex:section]];
return [sectionArray count];
}
//設置每行調用的cell
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *theSection = [m_titleArrayobjectAtIndex:indexPath.section];
//NSLog(@"theSection=%@",theSection);
//聲明一個標識符,然後使用它請求可重用單元
staticNSString *CellIdentifier =@"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//如果沒有可重用單元,則創建一個
//使用前面提到的標識符字符串手動創建一個新的表視圖單元。我們將不可避免地重複使用此處創建的單元。
if (!cell) {
cell = [[[UITableViewCellalloc]initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:CellIdentifier] autorelease];
}
sectionArray = [myDictionaryobjectForKey:theSection];
NSString *singername = [sectionArrayobjectAtIndex:indexPath.row];
cell.textLabel.text = singername;
cell.textLabel.font = [UIFontboldSystemFontOfSize:30];
cell.imageView.image = [UIImageimageNamed:[NSStringstringWithFormat:@"%@.png",singername]];//未選中cell時的圖片
cell.imageView.highlightedImage = [UIImageimageNamed:@""];//選中cell後的圖片
cell.showsReorderControl =YES;
cell.accessoryType =UITableViewCellAccessoryDetailDisclosureButton;
return cell;
}
//設置讓UITableView行縮進
//把每行的縮進級別設置爲其行號,第0號縮進級別爲0,第1行縮進級別爲1.
- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = indexPath.row;
return row;
}
//設置cell每行間隔的高度
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return75;
}
//返回當前所選cell
NSIndexPath *ip = [NSIndexPath indexPathForRow:row inSection:section];
[_tableView selectRowAtIndexPath:ipanimated:YES scrollPosition:UITableViewScrollPositionNone];
//設置UITableView的SeparatorStyle
_tableview.separatorStyle = UITableViewCellSeparatorStyleNone;
//設置選中Cell的響應事件
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[m_tableview deselectRowAtIndexPath:indexPath animated:YES];//選中後的反顯顏色即刻消失
}
//選中之前執行(阻止選中第一行)
-(NSIndexPath*)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"willSelectRowAtIndexPath");
NSUInteger row = [indexPath row];
if (row == 0) {
return nil;
}
return indexPath;
}
//設置划動cell是否出現del按鈕
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
returnYES;
}
//設置刪除時編輯狀態
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle ==UITableViewCellEditingStyleDelete)
{
[sectionArray removeObjectAtIndex:indexPath.row];
[m_tableview deleteRowsAtIndexPaths:[NSMutableArrayarrayWithObjects:indexPath,nil] withRowAnimation:UITableViewRowAnimationTop];
}
}
//右側添加一個索引表
//在表視圖右側添加一個索引
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return m_titleArray;
}
//跳到指定的row or section
[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:NO];
(2) 其他
//選中cell時的顏色,在官方文檔有如下可以選擇
//選中項的風格
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
typedef enum {
UITableViewCellSelectionStyleNone, 沒有變化
UITableViewCellSelectionStyleBlue, 默認選中項是藍色
UITableViewCellSelectionStyleGray 灰色
} UITableViewCellSelectionStyle
//cell右邊按鈕格式
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
typedef enum {
UITableViewCellAccessoryNone, //沒有附件
UITableViewCellAccessoryDisclosureIndicator, //黑色向右的箭頭
UITableViewCellAccessoryDetailDisclosureButton, //藍色附件按鈕
UITableViewCellAccessoryCheckmark //複選框,支持選擇
} UITableViewCellAccessoryType
實現多選
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"Selected section %d, cell %d",
[ indexPath indexAtPosition: 0 ], [ indexPath indexAtPosition: 1 ]);
//獲的當前選擇項
UITableViewCell *cell = [ self.tableView cellForRowAtIndexPath: indexPath ];
//顯示覆選框
if (cell.accessoryType == UITableViewCellAccessoryNone)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
}
//UITableView單元格顏色交替
由於設置單元格背景顏色只能在UITextViewDelegate代理函數willDisplayCell中有效,所以在該函數中可以設置顏色交替
//行將顯示的時候調用
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{ //方法一:
UIColor *color = ((indexPath.row %2) ==0) ? [UIColorcolorWithRed:255.0/255green:255.0/255blue:145.0/255alpha:1] : [UIColorclearColor];
cell.backgroundColor = color;
NSLog(@"willDisplaycell");
//方法二:
if (indexPath.row %2 ==1)
{
cell.backgroundColor = [UIColoryellowColor];
}
else
{
cell.backgroundColor = [UIColorredColor];
cell.selectedBackgroundView = [[UIImageViewalloc]initWithImage:[UIImageimageNamed:@"cell_1.png"]];//選中cell行變圖片
}
}
//是否加換行線
typedef enum {
UITableViewCellSeparatorStyleNone,
UITableViewCellSeparatorStyleSingleLine
} UITableViewCellSeparatorStyle
//改變換行線顏色
tableView.separatorColor= [UIColor blueColor];
4. UITableViewCell
表中的每一行都代表一個UITableViewCell。可以使用圖像、文本還有輔助的圖標等來自定義你自己的UITableViewCell。你可以自定義你自己的cell如下模型或者像appstore那樣的。
UITableViewCell爲每個Cell提供了三個可以選擇的屬性,如下:
l textLabel:填寫文本
l detailTextLable:稍微詳細的副標題
l imageView:用來顯示你cell的圖片,可以通過UIImage來加載。
(1) 顯示文本: cell.text = @"Frank's Table Cell";
(2) 對齊: cell.textAlignment = UITextAlignmentLeft;
UITextAlignmentLeft 默認是左對齊
UITextAlignmentRight 右對齊
UITextAlignmentCenter 中對齊
(3) 字體和尺寸:
#import <UIKit/UIFont.h>
UIFont *myFont = [ UIFont fontWithName: @"Arial" size: 18.0 ];
cell.font = myFont;
//系統字體
UIFont *mySystemFont = [ UIFont systemFontOfSize: 12.0 ];
UIFont *myBoldSystemFont = [ UIFont boldSystemFontOfSize: 12.0 ];
UIFont *myItalicSystemFont = [ UIFont italicSystemFontOfSize: 12.0 ];
(4) 顏色
#import <UIKit/UIColor.h>
//文本顏色
cell.textColor = [UIColor redColor];
//當前選擇cell文本的顏色
cell.selectedTextColor = [UIColor blueColor];
(5) 圖像
//從你應用程序目錄下的文件創建一個image
cell.image = [UIImage imageNamed: @"cell.png"];
//當前選中項的圖形
cell.selectedImage = [UIImage imageNamed: @"selected_cell.png" ];//選中cell後左邊圖片換
//選中後變圖片
cell.leftImageView.highlightedImage = [UIImageimageNamed:@"china_national_day-2011-hp.jpg"];
可以修改table保準行高來適應你的圖形高度
- (id)init
{
self = [ super init ];
if (self != nil) {
self.tableView.rowHeight = 65;
}
return self;
}
你也可以爲每一個cell定義不同的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([ indexPath indexAtPosition: 1 ] == 0)
return 65.0;
else
return 40.0;
}
最後給出一個官方的demo給大家學習下,多實踐,不懂的就問下,下節課講些UITableView應用中實際會出現的問題,比如自定義啊,重用單元格,單元格的數據排序等問題。歡迎大家拍磚。
附上代碼:http://www.2cto.com/uploadfile/2011/1130/20111130025401502.zip
修改cell選中後的顏色
UIView *backView = [[UIView alloc]initWithFrame:CGRectMake(0,0,320,80)];
cell.selectedBackgroundView = backView;
cell.selectedBackgroundView.backgroundColor = [UIColor orangeColor];
[backView release];
設置tableView偏移
// tableView內容的偏移值,第一個參數爲Y方向
tableView.contentInset = UIEdgeInsetsMake(64,0,0,0);
修改UITableView中Delete操作的默認按鈕
默認的刪除按鈕爲Delete,如果想顯示爲刪除的話,則需要實現UITableViewDelegate中的
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath方法。
//刪除按鈕的名字
-(NSString*)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
return@"刪除按鈕";
}
或者,最簡單的方式,將plist中的Localization native development region改爲China即可。
UITableView在didSelectRowAtIndexPath實現雙擊事件的方法
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//如果兩次點擊的時間間隔小於1秒,則斷定爲雙擊事件
NSUInteger curr = [[NSDate date] timeIntervalSince1970];
if (curr-taptime<1) {
[self doubleTap];
}
taptime = curr;
}
點擊變色再恢復
[_tableView deselectRowAtIndexPath:indexPath animated:YES];
分別是摺疊狀態的tableview和展開狀態的tableview
運行效果如下,分別是摺疊狀態的tabview和展開狀態的tabview:
一、新建UITableViewController
.h文件如下,包含了一個用於顯示的視圖tableview和用於表示模型數據的MutableArray.
@interface GDXXDetailVC :UITableViewController
<UITableViewDelegate,UITableViewDataSource,UIActionSheetDelegate>
{
UITableView* tableView;
NSMutableArray* model;
UIBarButtonItem *btnSave;
NSString *account,*pass;
NSArray* keys;
}
-(void)setModel:(NSString*)_account pass:(NSString*)_pass data:(NSArray*)_data;
-(void)save;
-(void)collapseOrExpand:(int)section;
-(Boolean)isExpanded:(int)section;
@end
.m文件如下,包含了tableview的datasource方法,和模型的處理邏輯。
#import "GDXXDetailVC.h"
@implementation GDXXDetailVC
-(id)init{
if(self=[super init]){
self.title=@"工單處理";
}
return self;
}
-(void)setModel:(NSString*)_account pass:(NSString*)_pass data:(NSArray*)_data
{
account=_account;
pass=_pass;
model=[[NSMutableArray alloc]init];
[model setArray:_data];
[_data release];
}
-(void)loadView{
self.view=[[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)];
tableView=[[UITableView alloc]initWithFrame:CGRectMake(0, 20, 320, 480) style:UITableViewStyleGrouped];
[self.view addSubview:tableView];
tableView.delegate=self;
tableView.dataSource=self;
//這個圖片中工具欄中顯示一個保存按鈕
btnSave= [[UIBarButtonItem alloc]
initWithTitle:@"處理"
style:UIBarButtonItemStyleBordered
target:self
action:@selector(save)];
self.navigationItem.rightBarButtonItem = btnSave;
[btnSave release];
}
-(void)saveData{
}
#pragma mark Actionsheet 委託方法
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{//當ActionSheet的某個按鈕被按下時觸發
if(buttonIndex == 0)//第一個按鈕表示保存按鈕
{
[self performSelector:@selector(saveData)];
}
//解散actionSheet
[actionSheet dismissWithClickedButtonIndex: buttonIndex animated:YES];
}
#pragma mark ===table view dataSource method and delegate method===
//返回分組數
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [model count];
}
//返回組標題
//-(NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
//{
// NSDictionary* d=[model objectAtIndex:section];
// if(d!=nil)
//title=[d objectForKey:@"title"];
// else return nil;
//}
//自定義section header
- (UIView *) tableView: (UITableView *) tableView
viewForHeaderInSection: (NSInteger) section
{
NSString*title=@"notitle";
NSDictionary* d=[model objectAtIndex:section];
if(d!=nil)
title=[d objectForKey:@"title"];
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
UIView* footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenRect.size.width, 44.0)];
footerView.autoresizesSubviews = YES;
footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
footerView.userInteractionEnabled = YES;
footerView.hidden = NO;
footerView.multipleTouchEnabled = NO;
footerView.opaque = NO;
footerView.contentMode = UIViewContentModeScaleToFill;
// Add the label
UILabel* footerLabel = [[UILabel alloc] initWithFrame:CGRectMake(64, 5, 120.0, 45.0)];
footerLabel.backgroundColor = [UIColor clearColor];
footerLabel.opaque = NO;
footerLabel.text = title;
footerLabel.textColor = [UIColor blackColor];
footerLabel.highlightedTextColor = [UIColor blueColor];
footerLabel.font = [UIFont boldSystemFontOfSize:17];
footerLabel.shadowColor = [UIColor whiteColor];
footerLabel.shadowOffset = CGSizeMake(0.0, 1.0);
[footerView addSubview: footerLabel];
[footerLabel release];
// Add the button
UIButton* footerButton = [[UIButton alloc] initWithFrame:CGRectMake(12, 5, 48.0, 48.0)];
//一開始小節是處於“摺疊狀態”,“+/-”按鈕顯示“+號”圖標
if ([self isExpanded:section]) {//若本節轉換到“展開”狀態,需要把圖標顯示成“-”號
[footerButton setBackgroundImage:[UIImage imageNamed:@"minus.png"] forState:UIControlStateNormal];
}else
[footerButton setBackgroundImage:[UIImage imageNamed:@"plus.png"] forState:UIControlStateNormal];
[footerButton addTarget:self action:@selector(expandButtonClicked:)
forControlEvents:UIControlEventTouchUpInside];
footerButton.tag=section;//把節號保存到按鈕tag,以便傳遞到expandButtonClicked方法
[footerView addSubview: footerButton];
[footerButton release];
// Return the footerView
return footerView;
}
//當“+/-”按鈕被點擊時觸發
-(void)expandButtonClicked:(id)sender{
UIButton* btn=(UIButton*)sender;
int section=btn.tag; //取得節號
[self collapseOrExpand:section];
//刷新tableview
[tableView reloadData];
}
//對指定的節進行“展開/摺疊”操作
-(void)collapseOrExpand:(int)section{
Boolean expanded=NO;
NSMutableDictionary* d=[model objectAtIndex:section];
//若本節model中的“expanded”屬性不爲空,則取出來
if([d objectForKey:@"expanded"]!=nil)
expanded=[[d objectForKey:@"expanded"]intValue];
//若原來是摺疊的則展開,若原來是展開的則摺疊
[d setObject:[NSNumber numberWithBool:!expanded] forKey:@"expanded"];
}
//返回指定節的“expanded”值
-(Boolean)isExpanded:(int)section{
Boolean expanded=NO;
NSMutableDictionary* d=[model objectAtIndex:section];
//若本節model中的“expanded”屬性不爲空,則取出來
if([d objectForKey:@"expanded"]!=nil)
expanded=[[d objectForKey:@"expanded"]intValue];
return expanded;
}
// 設置header的高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 60;
}
//返回分組的行數
-(NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section{
//對指定節進行“展開”判斷
if (![self isExpanded:section]) {//若本節是“摺疊”的,其行數返回爲0
return 0;
}
NSDictionary* d=[model objectAtIndex:section];
return [[d objectForKey:@"items"] count];
}
//設置行高
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 50;
}
//設置每一單元格的內容
-(UITableViewCell*)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString*cellId=@"setcell";
UITableViewCell* cell=(UITableViewCell*)[table dequeueReusableCellWithIdentifier:cellId];
if(cell==nil){
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:cellId]autorelease];
cell.selectionStyle=UITableViewCellSelectionStyleNone;
}
NSDictionary* items=[[model objectAtIndex:indexPath.section] objectForKey:@"items"];
keys=[items allKeys];
cell.textLabel.text=[items objectForKey:[keys objectAtIndex:indexPath.row]];
cell.textLabel.font=[UIFont fontWithName:@"Arial" size:18.0];
return cell;
}
//單元格選中時觸發
-(void)tableView:(UITableView *)table didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
}
-(void)save{
}
-(void)dealloc{
[model release];
[tableView release];
[super dealloc];
}
@end
二、在application的AppDelegate中實例化TableViewController
在application方法中,構造好一個Array,把要展示的數據放到其中,然後調用TableViewController的setModel方法設置tableview的model。這個Array的結構應該是這樣的:
NSArray 中的元素爲NSMutableDictionary(必須是Mutable,不能是NSDictionary)。每一個 NSMutableDictionary代表了一個小節的數據,包含若干key-value,其中Title爲小節名稱,expanded爲小節的展開/ 摺疊狀態,items爲小節中每一行的數據。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
window=[[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
GDXXDetailVC* rootController=[[GDXXDetailVC alloc]init];
NSMutableArray* items=[[NSMutableArray alloc]init];
for (int i=1; i<10; i++) {
NSDictionary *d=[NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat:@"section %d item1",i],@"1",
[NSString stringWithFormat:@"section %d item2",i],@"2",
[NSString stringWithFormat:@"section %d item3",i],@"3",
nil];
NSMutableDictionary* dic=[NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat:@"title %d",i],@"title",
d,@"items",[NSNumber numberWithBool:NO],@"expanded",
nil];
//[d release];
[items addObject:dic];
//[dic release];
}
[rootController setModel:nil pass:nil data:items];
//[items release];
[rootController setTitle:@"無線應用"];
[window addSubview:rootController.view];
//[rootController release];
[window makeKeyAndVisible];
return YES;