iPhone Programming VIIII : Table View ( Part 4) Custom Cell

เห็นถามกันมาหลายคนครับ โปรแกรมหลายๆโปรแกรมใน iphone นั้นมีตารางที่มีทั้ง ปุ่ม ทั้งอะไรมากมาย ยกตัวอย่าง เช่น Setting ที่อยู่ในเครื่องอยู่แล้ว ลองกด เข้าไปดูครับจะเห็นว่า ในแต่ละ cell น้ันมีทั้ง switch on-off ทั้งตัวหนังสือ เค้าทำกันได้ยังไง ? คำตอบคือ Custom Cell ครับ

วันนี้เราจะเขียน custom cell แบบง่ายๆกันครับ เพื่อเป็นแนวทางให้ไปประยุกต์ใช้กันต่อไป เอาละครับ เริ่มจากสร้างโปรเจคแบบ view base กันก่อน อย่างตัวอย่างนี้ผมตั้งชื่อว่า DemoCustomCell ครับ

1

แล้วเราก็ เพิ่ม class ที่ชื่อว่า StudentData เข้าไปยังโปรเจค ส่วน code interface ก็ประมาณนี้ครับ

@interface StudentData : NSObject
{
	NSString *studentName;
	NSString *studentGrade;
	UIImage *studentPicture;
 
}
@property (nonatomic, retain) NSString* studentName;
@property (nonatomic, retain) NSString* studentGrade;
@property (nonatomic, retain) UIImage *studentPicture;
 
@end

แล้วก็ส่วน implement ก็ไม่มีอะไรมากครับ

#import "StudentData.h"
 
@implementation StudentData
@synthesize studentName;
@synthesize studentGrade;
@synthesize studentPicture;
 
-(void) dealloc
{
	[studentName release];
	[studentGrade release];
	[studentPicture release];
	[super dealloc];
}
@end

จาก code ข้างบน ผมได้เขียน class ที่ชื่อว่า StudentData เพื่อที่จะเก็บ ชื่อ,เกรด และ รูปภาพ ของนักเรียน
และลำดับต่อไป เราก็ออกแบบหน้าตา interface ของโปรแกรม โดยเพิ่ม ตารางเข้ามา พร้อมทั้ง set delegate และ datasource ให้กับตารางให้เรียบร้อย

1a

หลังจากนั้น ก็มาเขียนส่วนของ code ของ DemoCustomCell กันครับ

@interface DemoCustomCellViewController : UIViewController
{
	NSMutableArray *studentArray;
	IBOutlet UITableView *studentTableView;
}
 
@end

จาก code ข้างบน เราประกาศ studentArray เพื่อเอาไว้เก็บรายชื่อนักเรียน และมี IBOutlet ที่เป็น UITableView ไว้แสดงผลครับ

ลำดับต่อไป เราจะเขียนส่วนของ implement ก็แบบนี้ครับ

#import "DemoCustomCellViewController.h"
#import "StudentData.h"
 
@implementation DemoCustomCellViewController
 
- (void)viewDidLoad
{
    [super viewDidLoad];
	[super viewDidLoad];
	studentArray = [[NSMutableArray alloc] init];
	StudentData* student_A , *student_B , *student_C , *student_D;
 
	student_A = [[StudentData alloc] init];
	student_B = [[StudentData alloc] init];
	student_C = [[StudentData alloc] init];
	student_D = [[StudentData alloc] init];
 
	student_A.studentName = [NSString stringWithString:@"น้องกระแต"];
	student_A.studentGrade = [NSString stringWithString:@"A"];
	student_A.studentPicture = [UIImage imageNamed:@"katae.png"];
 
	student_B.studentName = [NSString stringWithString:@"น้องปีใหม่"];
	student_B.studentGrade = [NSString stringWithString:@"B+"];
	student_B.studentPicture = [UIImage imageNamed:@"mai.png"];
 
	student_C.studentName = [NSString stringWithString:@"น้องแพนเค้ก"];
	student_C.studentGrade = [NSString stringWithString:@"C"];
	student_C.studentPicture = [UIImage imageNamed:@"pancake.png"];
 
	student_D.studentName = [NSString stringWithString:@"น้องเกรซ"];
	student_D.studentGrade = [NSString stringWithString:@"B"];
	student_D.studentPicture = [UIImage imageNamed:@"grace.png"];
 
	[studentArray addObject:student_A];
	[studentArray addObject:student_B];
	[studentArray addObject:student_C];
	[studentArray addObject:student_D];
 
	[student_A release];
	[student_B release];
	[student_C release];
	[student_D release];
 
}
 
- (void)viewDidUnload
{
	[studentArray release];
}
 
- (void)dealloc {
    [super dealloc];
}
 
// -----------------------------------------------------------------
//			TableView Delegate Implement
// -----------------------------------------------------------------
 
-(NSInteger) tableView:(UITableView*) tableView
numberOfRowsInSection:(NSInteger) section
{
	return [studentArray count];
}
 
- (UITableViewCell *)tableView:(UITableView *)table
		 cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
 
	static NSString *sampleIndentifier = @"My Identifier";
	UITableViewCell *cell;
        cell=[studentTableView dequeueReusableCellWithIdentifier:
			sampleIndentifier];
	if ( cell == nil )
	{
		cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
		reuseIdentifier:sampleIndentifier] autorelease];
	}
	NSUInteger row = [indexPath row];
 
	StudentData *temp = [studentArray objectAtIndex:row];
	cell.textLabel.text = temp.studentName;
 
	return cell;
}
@end

จากข้างบน ผมได้เพิ่มนักเรียนเข้าไปยัง StudentArray รวมทั้งหมด 4 คนครับ และในส่วนของ table delegate นั้นก็ ได้กำหนดให้ cell นั้นแสดง ชื่อของนักเรียน และเมื่อเราทำการ compile ก็จะได้โปรแกรมแบบนี้ครับ

3

ไม่ยากใช่ไหมครับ ต่อไปเราจะเขียน Custom Cell ครับ

Custom Cell

จากโปรแกรมข้างบน เราจะเห็นว่า ข้อจำกัดของโปรแกรมคือ ในแต่ละ cell นั้นแสดงได้แค่ ตัวหนังสือ เท่านั้นและได้เพียงแค่หนึ่งแถว ถ้าหากเราอยากจะเพิ่ม ให้ cell ของเราแสดงข้อมูลได้มากกว่านี้ เราจะต้องทำ custom cell ครับ เอาละครับ เริ่มกันเลย ก่อนอื่นเราต้องเพิ่ม xib เข้ามายังโปรเจค ครับ ดังรูป ก็ click ขวาเลือก new file แล้วก็เลือกไปที่ Empty XIB ครับ

2

แล้วก็ตั้งชื่อครับ ในตัวอย่างนี้ผมตั้งชื่อ StudentCustomCell.xib ครับ เมื่อเปิด File XIB ขึ้นมาก็จะเห็น เพียงแค่ File’s Owner กับ First Responder หลังจากนั้นให้ลาก UITableViewCell เข้ามายัง Document ของเรา ดังรูปครับ

4

เอาละครับ ก่อนที่เราจะลงมือ ออกแบบหน้าตา Custom Cell ของเรา เราต้องเขียน Class ขึ้นมาก่อน และสำหรับ Custom Cell ที่ผมจะออกแบบนี้ ผมอยากให้ มี

  1. ชื่อของนักเรียน
  2. เกรดของนักเรียน
  3. รูปถ่ายนักเรียน

เอาละครับ ต่อไปเราก็ลงมือเขียน StudentCustomCell Class ของเราเลย โดยการ Add New File อย่างที่เคยทำ นั่นเหละครับ แต่ให้เลือก SubClass  of ให้เป็น UITableViewCell แบบในรูปครับ แล้วก็ตั้งชื่อว่า StudentCustomCell

5

แล้ว code ของ StudentCustomCell.h ก็ได้แบบนี้

@interface StudentCustomCell : UITableViewCell
{
	IBOutlet UILabel* name;
	IBOutlet UILabel* grade;
	IBOutlet UIImageView* picture;
}
@property (nonatomic,retain)  UILabel* name;
@property (nonatomic,retain)  UILabel* grade;
@property (nonatomic,retain)  UIImageView* picture;
 
@end

ต่อไปก็เขียน implement ได้แบบนี้

#import "StudentCustomCell.h"
 
@implementation StudentCustomCell
 
@synthesize name;
@synthesize grade;
@synthesize picture;
 
- (id)initWithStyle:(UITableViewCellStyle)style
        reuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        // Initialization code
    }
    return self;
}
 
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
 
    [super setSelected:selected animated:animated];
}
 
- (void)dealloc
{
	[name release];
	[grade release];
	[picture release];
 
    [super dealloc];
}
 
@end

ครับเพียงเท่านี้ Class ของเราก็เกือบจะเสร็จละครับ ต่อไปเราก็กลับมายัง interface builder เพื่อที่จะออกแบบหน้าตา interface ของเราและ set link ต่างๆเข้ากับ class ที่เราได้เขียนขึ้นมา

Design Custom Cell

โดยลำดับแรกที่ต้องทำก็คือ เปิด inspector ขึ้นมาแล้วก็ set ให้ UITableViewCell ของเราเป็น Student Custom Cell ดังรูปครับ

6

หลังจากได้เปลี่ยนให้ UITableViewCell เป็น StudentCustomCell แล้ว ก็ออกแบบหน้าตาของโปรแกรม พร้อมกับเชื่อม Outlet ต่างๆให้เรียบร้อยดังรูป

7

Coding

ลำดับต่อไปเราก็จะแก้ไข code กันครับ ก่อนที่จะแก้ไขหรือเปลี่ยนแปลงอะไรใน code เราต้องเข้าใจก่อนครับว่า ที่เราได้ทำไปทั้งหมด เมื่อกี้คืออะไร สิ่งที่เราได้ทำไปทั้งหมดนั้นคือ

  • ประกาศ Custom Cell
  • ออกแบบ Custom Cell

สุดท้ายที่จะทำก็คือ เอามาใช้ครับ วิธีการที่เราจะเอา Custom Cell ของเรามาใช้ ก็ไม่ยากครับ ถ้าสังเกตดีๆ จะเห็น code ส่วนของ table delegate  ตรงนี้

- (UITableViewCell *)tableView:(UITableView *)table
		 cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
 
	static NSString *sampleIndentifier = @"My Identifier";
	UITableViewCell *cell;
	cell=[studentTableView dequeueReusableCellWithIdentifier:
						   sampleIndentifier];
	if ( cell == nil )
	{
		cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
			reuseIdentifier:sampleIndentifier] autorelease];
	}
	NSUInteger row = [indexPath row];
 
	StudentData *temp = [studentArray objectAtIndex:row];
	cell.textLabel.text = temp.studentName;
 
	return cell;
}

จากตรง code ข้างบน จะเห็นว่า เราได้ประกาศ cell ขึ้นมาให้เป็น UITableViewCell ใช่ไหมครับ ? แล้วเราก็ทำการ alloc แล้วก็ init มัน เอาละ งั้นถ้าหากว่าเราต้องการให้มันเป็น custom cell ทำยังไงละครับ คำตอบก็ไม่ยากเลย ก็คือเราก็ประกาศให้ cell ของเราเป็น custom cell ซะก็เรียบร้อย งั้นเรามาดู code กันเลย

- (UITableViewCell *)tableView:(UITableView *)table
		 cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
 
	static NSString *sampleIndentifier = @"My Identifier";
	StudentCustomCell *cell = (StudentCustomCell*)[studentTableView
		dequeueReusableCellWithIdentifier:sampleIndentifier];
	if (cell == nil)
	{
	NSArray *topLevelObjects;
	topLevelObjets = [[NSBundle mainBundle]
	loadNibNamed:@"StudentCustomCell" owner:nil options:nil];
 
	for(id currentObject in topLevelObjects)
	{
		if([currentObject isKindOfClass:[StudentCustomCell class]])
		{
			cell = (StudentCustomCell*)currentObject;
			break;
		}
	}
	}
 
	NSUInteger row = [indexPath row];
 
	StudentData *temp = [studentArray objectAtIndex:row];
	cell.name.text = temp.studentName;
	cell.grade.text = temp.studentGrade;
	cell.picture.image = temp.studentPicture;
 
	return cell;
}

อธิบายจาก ข้างบนนะครับ เราได้ประกาศ cell ให้เป็น StudentCustomCell โดยที่เราได้โหลดจาก StudentCustomCell.XIB ( ตรงส่วนของ for loop เป็นแค่ส่วนที่ใช้หาว่า object ตัวไหนใน xib ที่เป็น StudentCustomCell เท่านั้นเอง )  หลังจากนั้นเราก็ ได้ใส่รูป ใส่ชื่อ ใส่เกรด ให้กับ cell ก็เป็นอันจบ เมื่อ compile & run ก็จะเห็นผลลัพธ์ดังรูปครับ

result1

จะสังเกตเห็นว่า มันไม่พอดีกับ ตารางของเรา เราจำเป้นต้องเปลี่ยนความสูงของ cell ที่ใช้ โดยเพิ่ม

- (CGFloat)tableView:(UITableView *)tableView
	heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
	return 120;
}

เพียงเท่านี้ก็จะได้ผลลัพธ์เหมือนในรูปครับ
result_done

ลอง Download Code ไป Compile ดูได้ครับ DemoCustomCell

Technorati Tags: , , , ,


4 responses so far, want to say something?

  1. Avatar

    anuchiit says:

    ทำไมเวลา scroll bar แล้วรูปมันออกไปเลยเส้นขึ้นไปครับ มีวิธีแก้ไหมครับ ขอบคุณครับ

  2. Avatar

    admin says:

    มีครับ วิธีการแก้ ทำได้โดย ขยายให้ UIImageView มีขนาดพอดีหรือใหญ่กว่า ภาพ
    และอีกวิธีคือ ปรับ inspector ใน IB ให้ UIImageView เป็น Clip Subviews

  3. Avatar

    aomi says:

    ขอบคุณครับที่สอนครับ
    คือ อยากให้ช่วยสอนต่อจากบทนี้ได้ไหมครับ
    ผมอยากจะทำเวลาคลิกที่ cell แล้วมันจะเลื่อนไปทางขวาอ่ะคับ
    แล้วมีรายละเอียดของแต่ละคน อ่ะครับ

    ขอบคุณครับ

  4. Avatar

    mixxuptangle says:

    สวัสดีครับ
    พอดี ขอถามนอกเรื่องหน่อยนะครับ คุณพี่…
    คือ ผมอยากเขียนโปรแกรม แล้วดึงค่า GPS กับ เข็มทิศ(ที่มีอยู่ในเครื่อง)
    ออกมาใช้งาน สามารถ ทำได้หรือป่าวครับ ??

    และมีตัวอย่าง เล็กๆ น้อยๆ มั๊ย ?

    ขอบคุณครับ

Leave a Reply

You must be logged in to post a comment.