三十而立,從零開始學ios開發(十二):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來實現布局,那么情況應該會變得一致。

下一篇的內容會講到Table View的Section、index、搜索欄等等,內容比較多也比較實用,實現的效果如下

我會盡快寫完放上來的,謝謝大家的關注,有任何問題大家留言吧,如果我知道的話,我會盡量回答,謝謝!

 

 Cells2

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM