Table Views(中)UITableViewCell定製

我們繼續學習Table View的內容,這次主要是針對UITableViewCell,在前一篇的例子中我們已經使用過UITableViewCell,一個默認的UITableViewCell包含imageView、textLabel、detailTextLabel等屬性,但是很多時候這些默認的屬性並不能滿足需要,其實更多的時候我們想自己制定UITableViewCell的內容,這篇學習的就是制定自己的UITableViewCell。

UITableViewCell繼承自UIView,因此它可以加載任意的subView在上面,基於這一點,我們就可以定製自己的UITableViewCell了。制定UITableViewCell有2種方法,一種是寫代碼生成UITableViewCell控件上的內容,另一種是拖控件到一個UITableViewCell控件上,這兩種方法都會用一個例子來進行說明。

首先我們使用code的方法,來定製自己的UITableViewCell

1)創建一個新的項目,template選擇Single View Application,命名爲Cells

2)添加Table View,連接delegate和data source到File's Owner
選中BIDController.xib文件,從Object Library中拖一個Table View到view上,然後選中view中的table view,打開Connections Inspector,拖動dataSource和delegate右邊的小圓圈到File's Owner上

3)添加Cell
在Project navigator中選中Cells文件夾,然後command+N,添加一個新的文件。在彈出的對話框中,左邊選擇Cocoa Touch,右邊選擇Objective-C,然後點擊Next

在下一個對話框中把Class命名爲BIDNameAndColorCell,Subclass of選擇UITableViewCell,然後點擊Next

在下一個對話框中選擇Create,完成創建

BIDNameAndColor文件繼承自UITableViewCell,我們將先對其進行定製,添加一些我們需要的控件,當BIDViewController中調用table cell的時候,就直接調用這個文件即可。

4)添加BIDNameAndColorCell代碼
打開BIDNameAndColorCell.h文件,添加如下代碼

複製代碼
#import <UIKit/UIKit.h>

@interface BIDNameAndColorCell : UITableViewCell

@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *color;

@end
複製代碼

我們將在table view cell中顯示2個字符串,一個是name,另一個是color,顯示的內容會從之後定義的NSArray中讀取。(注意,我們這裏使用的是copy,而不是通常使用的strong,使用copy的好處是不會改變原有的字符串中的內容,當然在這裏我們也不會改變字符串的內容,你如果使用了strong也問題不大,不過書上的建議是如果一個property是NSString,最好使用copy)

接着編輯BIDNameAndColorCell.m文件,添加下面的code

複製代碼
#import "BIDNameAndColorCell.h"

#define kNameValueTag 1
#define kColorValueTag 2

@implementation BIDNameAndColorCell
@synthesize name;
@synthesize color;
複製代碼

首先添加2個常量kNameValueTag和kColorValueTag,這2個常量用來標識table view cell中的name和color。接着就是name和color的synthesize了,和之前例子中的一樣。

下面修改BIDNameAndColorCell.m中已存在的initWithStyle:reuseIdentifier:方法

複製代碼
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
        CGRect nameLabelRect = CGRectMake(0, 5, 70, 15);
        UILabel *nameLabel = [[UILabel alloc] initWithFrame:nameLabelRect];
        nameLabel.textAlignment = UITextAlignmentRight;
        nameLabel.text = @"Name:";
        nameLabel.font = [UIFont boldSystemFontOfSize:12];
        [self.contentView addSubview:nameLabel];
        
        CGRect colorLabelRect = CGRectMake(0, 26, 70, 15);
        UILabel *colorLabel = [[UILabel alloc] initWithFrame:colorLabelRect];
        colorLabel.textAlignment = UITextAlignmentRight;
        colorLabel.text = @"Color:";
        colorLabel.font = [UIFont boldSystemFontOfSize:12];
        [self.contentView addSubview:colorLabel];
        
        CGRect nameValueRect = CGRectMake(80, 5, 200, 15);
        UILabel *nameValue = [[UILabel alloc]initWithFrame:nameValueRect];
        
        nameValue.tag = kNameValueTag;
        [self.contentView addSubview:nameValue];
        
        CGRect colorValueRect = CGRectMake(80, 25, 200, 15);
        UILabel *colorValue = [[UILabel alloc]initWithFrame:colorValueRect];
        
        colorValue.tag = kColorValueTag;
        [self.contentView addSubview:colorValue];
    }
    return self;
}
複製代碼

上面的代碼應該還是比較容易理解的吧,創建了4個UILabel,設置完UILabel的屬性後,把他們加入到UITableViewCell中,table view cell有一個默認的view叫做contentView,contenView負責容納其他的subView,因此上面code中所創建的4個UILabel都會添加到contentView中,使用的語句是[self.contentView addSubview:colorValue]

再說一下上面創建的4個UILabel在這個例子中的作用,nameLabel和colorLabel的作用是純粹的Label,它們的值不會在改變,在這隻它們屬性的使用已經分別爲它們賦值了。nameValue和colorValue這2個label是用來顯示NSArray中的值的,這也是爲什麼只有這2個label會有property,因爲它們需要改變值。另外在code中還未這2個label制定了tag,這個tag的具體作用是通過它來標識具體的label,添加下面的code,就會有所瞭解。

複製代碼
- (void)setName:(NSString *)n {
    if(![n isEqualToString:name]) {
        name = [n copy];
        UILabel *nameLabel = (UILabel *)[self.contentView viewWithTag:kNameValueTag];
        nameLabel.text = name;
    }
}

- (void)setColor:(NSString *)c {
    if(![c isEqualToString:color]) {
        color = [c copy];
        UILabel *colorLabel = (UILabel *)[self.contentView viewWithTag:kColorValueTag];
        colorLabel.text = color;
    }
}
複製代碼

@synthesize會幫我們自動創建get和set方法,但在這裏我們需要自己寫set方法,因此通過上面的code來覆蓋系統自動爲我們生成的set方法。2個set方法的實現是一樣的。首先比較新賦值的字符串和舊的字符串是否一樣,如果不一樣就進行賦值。然後需要解釋的就是這句話
UILabel *colorLabel = (UILabel *)[self.contentView viewWithTag:kColorValueTag];
如果找到table view cell中的控件?即使使用剛纔我們創建的2個常量,因爲每一個控件的tag值都是不一樣的,因此根據tag值就可以很方便的找到我們需要的控件,viewWithTag返回的類型是(UIView *),所以我們將類型強制轉換成(UILable *),就可以得到我們需要的Label了,然後對Label進行賦值。

5)添加BIDViewController代碼
打開BIDViewController.h,添加如下代碼

複製代碼
#import <UIKit/UIKit.h>

@interface BIDViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

@property (strong, nonatomic) NSArray *computers;

@end
複製代碼

很簡單,不解釋。

打開BIDViewController.m,添加如下代碼

複製代碼
#import "BIDViewController.h"
#import "BIDNameAndColorCell.h"

@implementation BIDViewController
@synthesize computers;

......

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSDictionary *row1 = [[NSDictionary alloc] initWithObjectsAndKeys:
                          @"MacBook", @"Name", @"White", @"Color", nil];
    NSDictionary *row2 = [[NSDictionary alloc] initWithObjectsAndKeys:
                          @"MacBook Pro", @"Name", @"Silver", @"Color", nil];
    NSDictionary *row3 = [[NSDictionary alloc] initWithObjectsAndKeys:
                          @"iMac", @"Name", @"Silver", @"Color", nil];
    NSDictionary *row4 = [[NSDictionary alloc] initWithObjectsAndKeys:
                          @"Mac Mini", @"Name", @"Silver", @"Color", nil];
    NSDictionary *row5 = [[NSDictionary alloc] initWithObjectsAndKeys:
                          @"Mac Pro", @"Name", @"Silver", @"Color", nil];
    
    self.computers = [[NSArray alloc] initWithObjects:row1, row2, row3, row4, row5, nil];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    self.computers = nil;
}
複製代碼

首先我們引入BIDNameAndColor的頭文件,之後我們將會創建它的實例,在viewDidLoad中,創建了5個NSDictionary,用於保存name和color名值對,使用的方法是initWithObjectsAndKeys,就是說下面的內容前一個作爲object,後一個作爲key,舉個例子,最後一個NSDictionary中,@"Mac Pro"就是object,@"Name"就是key。最後將5個NSDictionary保存到NSArray中(computers中)

在添加下面的code

複製代碼
#pragma mark -
#pragma mark Table Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.computers count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellTableIdentifier = @"CellTableIdentifier";
    
    BIDNameAndColorCell *cell = [tableView dequeueReusableCellWithIdentifier:CellTableIdentifier];
    if(cell == nil) {
        cell = [[BIDNameAndColorCell alloc]
                initWithStyle:UITableViewCellStyleDefault
                reuseIdentifier:CellTableIdentifier];
    }
    
    NSUInteger row = [indexPath row];
    NSDictionary *rowData = [self.computers objectAtIndex:row];
    
    cell.name = [rowData objectForKey:@"Name"];
    cell.color = [rowData objectForKey:@"Color"];
    
    return cell;
}
複製代碼

tableView:numberOfRowsInSection: 返回section中的行數
tableView:cellForRowAtIndexPath: 這個方法稍微有些不同,它吃創建了一個BIDNameAndColorCell的對象,而不是創建默認的UITableViewCell,這樣就可以直接使用我們自己定義的cell了,這裏雖然也指定了UITableViewCellStyleDefault,但是不會起作用,因爲我們自己定義了cell

之後的代碼應該很好理解,很直觀。

6)編譯運行

Cells

7)使用UITableViewCell控件,創建項目,添加table view,連接File's Owner
現在我們使用第二種方法來定製UITableViewCell,最終的效果和上面的例子一樣,創建一個新的項目,同樣選擇Single View Application,命名爲Cells2

添加Table View,連接delegate和data source到File's Owner

8)添加BIDNameAndColorCell文件並編輯
和上面的例子一樣,添加BIDNameAndColorCell文件

打開BIDNameAndColorCell.h文件,添加如下代碼

複製代碼
#import <UIKit/UIKit.h>

@interface BIDNameAndColorCell : UITableViewCell <UITableViewDelegate, UITableViewDataSource>
@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *color;

@property (strong, nonatomic) IBOutlet UILabel *nameLabel;
@property (strong, nonatomic) IBOutlet UILabel *colorLabel;

@end
複製代碼

和之前有所不同的是,我們多添加了2個Outlet,因爲之後要添加xib,因此這2個outlet會指向xib上了2個UILabel

打開BIDNameAndColorCell.m文件,添加如下代碼

複製代碼
#import "BIDNameAndColorCell.h"

@implementation BIDNameAndColorCell

@synthesize name;
@synthesize color;
@synthesize nameLabel;
@synthesize colorLabel;

- (void)setName:(NSString *)n {
    if(![n isEqualToString:name]) {
        name = [n copy];
        nameLabel.text = name;
    }
}

- (void)setColor:(NSString *)c {
    if(![c isEqualToString:color]) {
        color = [c copy];
        colorLabel.text = color;
    }
}
複製代碼

我們重新定義了setName和setColor,這裏不需要使用tag,因爲我們直接使用outlet就可以找到我們需要的UILabel,另外我們也沒在initWithStyle:reuseIdentifier中創建4個Label,因爲我們會在之後UITableViewCell控件中添加。

9)添加xib
在Project navigator中鼠標右鍵單擊Cells2文件夾,然後選擇New File...,在填出的對話框中左邊選擇User Interface,右邊選擇Empty,點擊Next

之後的Device Family中選擇iphone,點擊Next

命名爲BIDNameAndColorCell.xib,點擊Create

在Project navigator中選中BIDNameAndColorCell.xib文件,因爲我們創建的是Empy,因此GUI中什麼都沒有,在Object library中找到Table View Cell

拖到GUI中

選中view中的table view cell,打開Attributes inspector,找到Identifier,並設置爲CellTableIdentifier

這個Identifier就是之前我們code中用到過的Identifier

10)向table view cell中添加控件
往table view cell中拖4個UILable

將左上方的UILabel命名爲"Name:",然後設置爲粗體(在attribute inspector中設置)

將左下方的UILabel命名爲"Color:",然後設置爲粗體(在attribute inspector中設置)
將右上方的UILabel拉到右邊出現輔助線的位置
將右下方的UILabel拉到右邊出現輔助線的位置
設置完成後的樣子如下

(不必將右邊2個Label的文字去掉,程序運行是會爲它們重新賦值)

11)關聯
接着我們將BIDNameAndColorCell.xib和BIDNameAndColorCell文件關聯起來,選中GUI中的view,打開Identify inspector,將Class指定爲BIDNameAndColorCell

還是選中view,切換到connections inspector,裏面有colorLabel和nameLabel

將colorLabel和nameLabel拖到view中對應的UILabel上,關聯起來(最右邊的2個label)

12)寫代碼
打開BIDViewController.h文件,添加如下代碼

複製代碼
#import <UIKit/UIKit.h>

@interface BIDViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

@property (strong, nonatomic) NSArray *computers;

@end
複製代碼

這個和上一個例子一樣,不解釋了,打開BIDViewController.m文件,添加如下代碼

複製代碼
#import "BIDViewController.h"
#import "BIDNameAndColorCell.h"

@implementation BIDViewController
@synthesize computers;
......
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSDictionary *row1 = [[NSDictionary alloc] initWithObjectsAndKeys:
                          @"MacBook Air", @"Name", @"Silver", @"Color", nil];
    NSDictionary *row2 = [[NSDictionary alloc] initWithObjectsAndKeys:
                          @"MacBook Pro", @"Name", @"Silver", @"Color", nil];
    NSDictionary *row3 = [[NSDictionary alloc] initWithObjectsAndKeys:
                          @"iMac", @"Name", @"Silver", @"Color", nil];
    NSDictionary *row4 = [[NSDictionary alloc] initWithObjectsAndKeys:
                          @"Mac Mini", @"Name", @"Silver", @"Color", nil];
    NSDictionary *row5 = [[NSDictionary alloc] initWithObjectsAndKeys:
                          @"Mac Pro", @"Name", @"Silver", @"Color", nil];
    
    self.computers = [[NSArray alloc] initWithObjects:row1, row2,
                      row3, row4, row5, nil];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    self.computers = nil;
}

#pragma mark -
#pragma mark Table View Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section {
    return [self.computers count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellTableIdentifier = @"CellTableIdentifier";
    static BOOL nibsRegistered = NO;
    if(!nibsRegistered) {
        UINib *nib = [UINib nibWithNibName:@"BIDNameAndColorCell" bundle:nil];
        [tableView registerNib:nib forCellReuseIdentifier:CellTableIdentifier];
        nibsRegistered = YES;
    }
    
    BIDNameAndColorCell *cell = [tableView dequeueReusableCellWithIdentifier:CellTableIdentifier];
    
    NSUInteger row = [indexPath row];
    NSDictionary *rowData = [self.computers objectAtIndex:row];
    
    cell.name = [rowData objectForKey:@"Name"];
    cell.color = [rowData objectForKey:@"Color"];
    
    return cell;
}
複製代碼

我們所要關心的就是tableView:cellForRowAtIndexPath這個方法中的if語句這段代碼:

if(!nibsRegistered) {
    UINib *nib = [UINib nibWithNibName:@"BIDNameAndColorCell" bundle:nil];
    [tableView registerNib:nib forCellReuseIdentifier:CellTableIdentifier];
    nibsRegistered = YES;
}

UINib通過xib文件的名字找到xib文件,然後tableView會調用這個xib文件,nibsRegistered保證只有第一次調用這個方法的時候會去尋找並載入xib,之後則不會。

13)編譯運行
編譯運行程序,得到的結果和之前的一個程序應該是一樣的

14)總結
這篇文章使用2種方式定製了UITableViewCell,一種是代碼實現,另一種是傳統的拖控件實現,2種方法應該說各有利弊,不一定拖控件就是好的,我應該已經預感到以後的界面佈局應該都使用寫代碼來實現,已經有好幾個博友通過我的例子學習但是得到的界面上面控件的佈局出現了差錯,目前的原因是他們使用的模擬器和我的不一樣,我使用的是iPhone 5.0 Simulator,他們可以是用其他的模擬器,但是我覺得照成差錯的原因是因爲學習到現在我們都是使用拖控件的方法來佈局的,這個會造成差錯,如果都是用code來實現佈局,那麼情況應該會變得一致。

發佈了19 篇原創文章 · 獲贊 17 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章