Table View นั้นเป็น Control ที่ค่อนข้างจะใช้งานเยอะมากๆ และทรงพลังมาก ถ้าเราดูโปรแกรมหลายๆโปรแกรมจะพบว่า ได้มีการประยุกต์ table view ใช้งานต่างๆมากมาย เช่นเปิดโปรแกรม Photos ก็เห็นแล้วว่ามี table view หรือ Contacts เป็นต้น ( ดูรูปประกอบ จะเห็นว่าทั้งหมดนี้ ล้วนแต่ใช้ table view ทั้งนั้น แต่ต่างกันในส่วนว่าจะแสดงอะไร มีรูป หรือมี control อื่นๆด้วยหรือเปล่า )
และวันนี้เราจะมาลองใช้งาน table view กันครับ
Table View ใน Cocoa touch นั้นต่างกับใน Cocoa ปกติอยู่พอสมควร แต่โครงสร้างหลักๆ และหลักการ รวมถึงวิธีการใช้งานก็เหมือนเดิม ฉนั้นแล้วคนที่เคยใช้ NSTableView มาก่อน ก็หวานหมูเลย จริงๆแล้วข้อแตกต่างที่เห็นได้ชัดๆเลยก็คือ Table View ใน Cocoa touch นั้นสามารถแสดงผลได้ทีละ 1 column เท่านั้น !!! ใน Cocoa touch นั้นจะมี Class เป็น table view ชื่อว่า UITableView และแต่ละ object ที่อยู่ในแถวจะเรียกว่า Cell ( UITableViewCell ) และเนื่องจากว่า cell นั้นเป็น subclass ของ UIView นั่นหมายความว่า เราสามารถ ใส่ control ต่างๆที่เป็น UIView หรือ subclass ของ UIView เข้าไปใน cell ได้มากมาย อาจจะใส่รูป ใส่ปุ่มกด ตัวหนังสือก็ได้ หรือแม้กระทั่งใส่ table view เข้าไปก็ยังได้ ( เห็นไหมครับว่ามันสามารถปรับแต่งได้สุดๆ )
ก่อนที่เราจะเริ่มผมอยากจะให้กลับไปทำความเข้าใจ เกี่ยวกับการทำงานของ table และ delegate ก่อน
UITableView จะมี helper object ที่ชื่อว่า data source ช่วยในการแสดงผลของข้อมูล ซึ่งการทำงานของ UITableView จะไม่ใช่ลักษณะที่ตัวโปรแกรมเป็นคนสั่งบอกกับ UITableView ว่าให้แสดงคำว่า Saved Photo ในแถวที่หนึ่ง แต่ในทางกลับกัน UITableView มันจะไปถาม helper object เองว่าในแถวที่หนึ่งมีอะไรที่ต้องแสดง ในกรณีนี้ datasource ก็จะส่ง Saved Photo(1) กลับมาให้ยัง NSTable แบบรูปข้างล่าง
และในการใช้งาน UITableView นั้นเราต้อง implement delegate method ( หากไม่เข้าใจ delegate ควรไปอ่าน cocoa programming delegate ) ด้วยกัน 2 อย่างคือ
- -(int) numberOfRowInTableView
NSTableView*) tableView;
ส่งค่าของจำนวน row กลับมา - -(id) tableView
NSTableView *) tableView
objectValueForTableColumn
NSTableColumn*) tableColumn
row
int) rowIndex;
ส่ง object ที่ต้องไปแสดงผลที่ row
เอาละครับ เมื่อเราได้เข้าพื้นฐานของ UITableView ไปบ้างแล้วลำดับต่อไปเราจะมาเขียนโปรแกรมกัน โดยโปรแกรมที่เราจะเขียนกันในวันนี้ คือโปรแกรมเก็บรายชื่อนักเรียนอย่างง่ายๆกัน โดยหน้าตาโปรแกรมจะเป็นดังรูป
อธิบายโปรแกรมกันก่อนว่าโปรแกรมเราทำอะไร คือโปรแกรมเราจะมี text field เอาไว้ใส่ชื่อนักเรียน หลังจากนั้นเมื่อเรากด Add รายชื่อนักเรียนก็จะไปปรากฎบนตารางของเรา และสามารถลบได้โดยการกด ไปที่แถวที่ต้องการลบ และกด remove
Start
ก่อนอื่นเลยเราก็สร้างโปรเจคแบบ Viewed-Base Application เหมือนๆที่เราเคยทำมาครับ โดยจะตั้งชื่ออะไรก็แล้วแต่ แต่ในโปรเจคนี้ผมตั้งชื่อว่า Student ก็แล้วกัน ก็จะได้โปรเจคหน้าตาแบบในรูป
หลังจากนั้นเราจะออกแบบหน้าตาโปรแกรมของเรา โดยเปิด StudentViewController.xib ขึ้นมาครับ แล้วเราก็วาง Control ต่างๆลงไป
จากรูปข้างบน เราได้วาง UITable , UIButton , UITextField เพียงเท่านี้ก็เป็นอันเสร็จการออกแบบ อาจจะงงว่า ทำไมไม่เอา Add , Remove ลงมาอยู่ข้างล่างตาราง เหตุผลก็เพราะว่า เมื่อ Keyboard มันโผล่ขึ้นมา มันจะบัง UITextFields ที่เราได้วางลงไป ผมเลยย้ายมันขึ้นมาไว้ข้างบน
Code
ก่อนอื่นเลยมาดูในส่วนของ Header กันก่อนว่า เราจะประกาศอะไรบ้าง
@interface StudentViewController : UIViewController { IBOutlet UITextField *m_textField; IBOutlet UITableView *m_table; NSMutableArray *m_studentList; } @property (nonatomic,retain) NSMutableArray *m_studentList; -(IBAction) delStudent:(id) sender; -(IBAction) addStudent:(id) sender; - (IBAction ) endEdit:(id) sender; @end
ดูจาก code แล้วเราได้ประกาศ outlet มาด้วยกันแค่ 2 ตัวนั่นก็คือ m_textField และ m_table เพื่อที่เราจะได้ติดต่อ UITextFieds และ UITableView ได้ สำหรับในส่วนของ UIButton นั้นเราไม่ได้ต้องการให้มันทำอะไรนอกจาก เรียก action ที่เราต้องการ ฉนั้นก็ไม่ต้องประกาศ outlet ก็ได้ และเราก็ได้ประกาศ action อีก 3 อย่าง ได้แก่ delStudent , addStudent , endEdit ก็แปลตรงๆ ตามชื่อเลยว่าแต่ละ action นั้นเราจะให้มันทำอะไร
@implementation StudentViewController @synthesize m_studentList; // ******************* Load & Unload *************************** - (void)viewDidLoad { [super viewDidLoad]; m_studentList = [[NSMutableArray alloc] init]; } - (void)dealloc { [m_studentList release]; [super dealloc]; } // ******************* Button Action ************************************* -(IBAction) addStudent:(id) sender; { NSString *text = m_textField.text; if ( [text isNotEqualTo:@""] ) { [m_studentList addObject:[NSMutableString stringWithString:text] ]; [m_table reloadData]; } } -(IBAction) delStudent:(id) sender { NSIndexPath *indexPath = [m_table indexPathForSelectedRow]; if ( indexPath != nil ) { int row = [indexPath row]; [m_studentList removeObjectAtIndex:row]; [m_table reloadData]; } } // ******************* Text Field Action ******************************** - (IBAction ) endEdit:(id) sender { [sender resignFirstResponder]; } // *************** UITableView Delegate ******************************** -(NSInteger) tableView:(UITableView*) tableView numberOfRowsInSection:(NSInteger) section { return [self.m_studentList count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; { static NSString *identifier = @"Macfeteria Cell"; UITableViewCell *cell; cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if ( cell == nil ) { cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier: identifier] autorelease]; } NSUInteger row = [indexPath row]; cell.text = [m_studentList objectAtIndex:row]; return cell; } @end
จาก code ข้างบนผมแบ่งออกเป็น 4 ส่วน นั่นก็ส่วนของ
- Load & Unload
- Button Action
- Text Field Action
- UITableView Delegate
เราจะดูในทีละส่วนก่อนเลยละกัน เริ่มจาก Load & Unload ก่อนละกัน
Load & Unload
ในส่วน code ตรงนี้ จะเห็นว่ามี viewDidLoad ซึ่งจริงๆแล้ว viewDidLoad เป็น delegate method ของ UIView ครับ นั่นแปลว่า เมื่อ UIView ของเราถูกโหลดขึ้นมาเสร็จเรียบร้อยแล้ว ก็จะมาถามว่า มีอะไรที่ต้องอีกหรือเปล่า ? ซึ่งก็จะมาอ่าน code ในนี้เหละครับว่า โหลดเสร็จแล้วต้องทำอะไร ถ้าเราดูใน code ภายในก็จะเห็นว่าเราได้บอกว่า หลังจากโหลด UIView นี้ก็ให้จองหน่วยความจำและ init ให้กับ array ของเรานั่นก็คือ m_studentList นั่นเอง และส่วนฟังก์ชั่น dealloc จะถูกเรียกเมื่อโปรแกรมได้จบลง ซึ่งเราก็ได้คืนหน่วยความจำที่เราได้ให้ m_studentList จองไว้นั่นเอง
Button Action
action method ในส่วนตรงนี้เราได้เขียน addStudent เพื่อที่ว่า เราจะนำข้อความจาก text field มาใส่ยัง array ของเรานั่นเอง และส่วน delStudent นั้นก็คือเราจะทำการลบข้อมูลที่ได้เลือกไว้ ออกจากตาราง อธิบายเพิ่มเติมในส่วนของ code นิดหนึ่งครับ วิธีการที่เราจะรู้ว่าแถวในตารางไหนจะถูกเลือก จะเห็นว่าเราได้เรียก
NSIndexPath *indexPath = [m_table indexPathForSelectedRow];
แต่ indexPath จะยังใช้โดยตรงไม่ได้ เราต้องเรียก [indexPath row] อีกทีเพื่อที่จะได้ตำแหน่งของแถวในตาราง และเมื่อเราได้ลบออกไปแล้ว เราก็ให้ตารางได้ reload เพื่อปรับข้อมูลในการแสดงผล
Text Field Action
ในส่วนของ action สำหรับ text field นั้นจริงๆก็ไม่ได้มีอะไรเลยครับ เราแค่ต้องการให้ เมื่อเราได้พิมพ์ข้อความ และหลังจากกด done เรียบร้อยแล้ว ก็จะให้ keyboard นั้นหายไป วิธีการก็คือเราก็ให้ text field ได้ถอนตัวจากการเป็น first responder นั่นเอง
UITableView Delegate
ก็อย่างที่บอกไปครับว่า เมื่อเราจะใช้ UITableView นั้นเราจำเป็นต้อง implement – delegate ของ UITableView สอง function โดย delegate funciton แรกคือ
-(NSInteger) tableView:(UITableView*) tableView numberOfRowsInSection:(NSInteger) section
นั้นเป็นฟังก์ชั่นที่เอาไว้บอกกับ table view ว่ามีจำนวนแถวกี่แถวที่ต้องแสดง และจาก code ที่เราเขียนไป เราก็ได้บอกว่าจำนวนแถวในตารางทั้งหมดของเรา เท่ากับจำนวนของค่าที่เก็บใน m_studentList นั่นเอง
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
สำหรับ delegate method นี้เป็นฟังก์ชั่นที่เอาไว้บอกว่า ข้อมูลที่จะแสดงในแถวของ ตาราง คืออะไร ** และอย่างที่บอกไปแล้วว่า แถวของตารางนั้นเป็น control ที่เรียกว่า UITableViewCell ** ฉนั้นแล้วเราต้องสร้าง UItableViewCell ขึ้นมาก่อน
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier: identifier] autorelease];
และจากบรรทัดนี้ จะเห็นว่าเราได้ประกาศ cell ขึ้นมาและได้จองหน่วยความจำให้กับ cell พร้อมกับ init เรียบร้อย อาจจะงงตรง ที่เขียนว่า reuseIndentifier ว่ามันคืออะไร คือ UITalbleViewCell นั้นเป็น Subclass ของ UIView นั่นแปลว่า cell ของเรานั้นอาจจะเป็น ข้อความธรรมดา หรืออาจจะเป็น Custom View หรือแม้กระทั่งเป็น table ทั้งอันก็ยังได้ ฉนั้นการที่ มี indentifier ก็เพื่อระบุว่า cell นี้เป็นประเภทไหน ความสำคัญอีกอย่างก็เพื่อจะได้นำกลับมาใช้ใหม่ซึ่งจะอธิบายในลำดับต่อไป
เมื่อเรามี cell แล้วลำดับต่อไปเราก็จะนำข้อมูลที่ต้องการใส่ไปใน cell และข้อมูลที่เราต้องการในที่นี้ก็คือข้อมูลที่เราได้เก็บไว้ในตัวแปร m_studentList นั่นเอง
NSUInteger row = [indexPath row]; cell.text = [m_studentList objectAtIndex:row]; return cell;
ยังมี code ส่วนที่เหลือนั่นก็คือ
static NSString *identifier = @"Macfeteria Cell"; UITableViewCell *cell; cell = [tableView dequeueReusableCellWithIdentifier:identifier];
อธิบายเพิ่มเติมนะครับว่า เมื่อเราได้ใช้นิ้วเลื่อนดูค่าในตำแหน่งอื่นๆของตาราง Cell ที่ได้ถูกเลื่อนไปจนไม่สามารถจะแสดงผลที่หน้าจอได้ ตามหลักการทำงานของโปรแกรมแล้ว มันควรจะคืนหน่วยความจำของ Cell นั้นให้กับระบบ แล้วก็จองหน่วยความจำใหม่ ให้กับ Cell ที่จะมาแทนที่ Cell เดิมที่ได้หายไปจากหน้าจอ แต่เนื่องจากว่า iPhone นั้นค่อนข้างจะจำกัดทรัพยากรของระบบ วิศวกรของ Apple เลยออกแบบให้ Cell ที่ได้หายไปจากหน้าจอจะยังไม่ถูกทำลาย แต่จะถูกเก็บไว้ยัง dequeue เพื่อที่ว่าจะได้นำกลับมาใช้ใหม่ ซึ่งจะช่วยลดการจองและคืนหน่วยความจำให้กับระบบบ่อยๆ ดังนั้นการใช้
cell = [tableView dequeueReusableCellWithIdentifier:identifier];
ก็เพื่อเพิ่มประสิทธิภาพการใช้งานหน่วยความจำให้กับระบบนั่นเอง สรุปก็คือ ก่อนที่มันจะจองหน่วยความจำใหม่ มันจะไปถาม table ก่อนว่ามี cell ไหนที่สามารถนำกลับมาใช้ได้บ้างหรือเปล่า ถ้ามี ก็ไม่ต้องจองใหม่ แต่ถ้าไม่มี ก็จองหน่วยความจำใหม่นั่นเอง
Link Control
ลำดับต่อไปเราก็จะ link control ต่างๆให้เข้ากับ action ของเราครับ โดยกลับไปที่ interface builder แล้วก็ เชื่อม
- m_table กับ UITableView
- m_textField กับ UITextField
ผมคิดว่าใน tutorial นี้คงไม่ต้อง อธิบายเยอะนะครับว่า เราจะเชื่อม Control และ Action ยังไง ขออธิบายคร่าวๆเลยนะครับ แล้วก็ link action ให้กับ Button ของเรา รวมถึง action ของ m_textField ด้วย
มีส่วนเพิ่มเติมก็คือใน connection inspector ของ UITableView นั้นจะเห็น Delegate และ Data Source ดังรูปครับ ให้ลากเชื่อมเข้ากับ File’s Owner ดังรูป
ที่เราทำตรงนี้ก็เพื่อว่าจะได้บอกให้ table ของเราได้รู้ว่า object ไหนเป็น helper object และ datasource นั่นเอง
ส่วน Action อื่นๆ เช่น delStudent ก็ลากเข้ากับปุ่ม ให้เรียบร้อย และรวมถึง endEdit ที่ต้องเชื่อมกับ text filed ด้วยนะครับ ถ้าหากเสร็จหมดแล้ว ถ้า click ขวาที่ File’s Owner ก็จะเห็น panel พร้อมกับค่าต่างๆดังรูป
หลังจากก็ลอง Compile & Run ดูครับ เราก็จะสามารถ พิมพ์ข้อความและกด Add เพื่อให้ข้อความนั้นเข้ามายัง table ของเราได้แล้ว
และแน่นอนว่า เราสามารถลบข้อมูลได้ด้วยการเลือกไปยังแถวที่ต้องการและกด remove ดังรูป
เป็นอย่างไรบ้างครับสำหรับ tutorial นี้คงได้ไปลองๆหัดทำกัน และได้เข้าใจเกี่ยวกับ delegate พร้อมกับ UITableView กันนะครับ ยินดีรับคำแนะนำ และติชมนะครับ
Download Source :: iPhone – Student List With UITable












anuchiit says:
ถ้าจะเพิ่มจะทำให้ ให้ กด ที่ cell แล้วแสดงอีก view หนึ่งต้องเพิ่มโค๊ดในการ add view ขึ้นมาหรือเปล่าครับหรือ
August 28, 2009, 2:33 amต้องสร้าง ไฟล์ view.xib ขึ้นมาอีกด้วยค่อยไปเขียนโค๊ดเพิ่มอีกที คือยังไม่ค่อยเข้าใจ นะครับ
admin says:
ต้องเขียน code เพื่อเปลี่ยน view เองครับ
August 30, 2009, 1:53 pmbiggoogle says:
if ( [text isNotEqualTo:@""] )
คำสั่ง isNotEqualTo ไม่มีแล้วครับ มีแต่ isEqualTo
ไฟล์ตัวอย่างก็ RUN ไม่ผ่านแล้วครับ
March 1, 2010, 11:34 am