在此之前,我们已经创建了一个通过简单的表视图应用程序并显示预定义的图像。在本教程中,我们将继续努力,使应用程序变得更好,:
>不同的行显示不同的图像 - 上个教程,我们的所有行显示相同的缩略图。那么不同的食物显示不同的图片不是更好么?
>自定义视图单元-我们将展示我们自己的视图来替代默认表单元格样式
在我们更改代码之前,让我们回顾显示缩略图的代码。
最后,我们增加了一个行代码指示UITableView每一行显示“creme_brelee.jpg”这张图片。显然,为了显示不同的图像,我们需要改变这行代码。正如之前解释的那样,IOS在显示一条表单元格时自动调用“cellForRowAtIndexPath”方法
1
|
-
(UITableViewCell
*
)tableView
:
(UITableView
*
)tableView cellForRowAtIndexPath
:
(
NSIndexPath
*
)indexPath
|
看看该方法的参数,每次调用时通过“indexPath”来传递表单元格信息。indexPath参数包含的表单元格的行数(以及节号)。您可以简单地使用“indexPath.row”属性,找出当前指向哪一行。和数组一样,表行的计数从零开始。换言之,对于第一行“indexPath.row”返回0。
因此,为了显示不同的缩略图,我们将添加一个新的数组(即缩略图),存储文件名的缩略图:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@implementation
SimpleTableViewController
{ NSArray *tableData; NSArray *thumbnails; } - ( void )viewDidLoad { [super viewDidLoad ]; // Initialize table data tableData = [ NSArray arrayWithObjects : @ "Egg Benedict", @ "Mushroom Risotto", @ "Full Breakfast", @ "Hamburger", @ "Ham and Egg Sandwich", @ "Creme Brelee", @ "White Chocolate Donut", @ "Starbucks Coffee", @ "Vegetable Curry", @ "Instant Noodle with Egg", @ "Noodle with BBQ Pork", @ "Japanese Noodle with Pork", @ "Green Tea", @ "Thai Shrimp Cake", @ "Angry Birds Cake", @ "Ham and Cheese Panini", nil ]; // Initialize thumbnails thumbnails = [ NSArray arrayWithObjects : @ "egg_benedict.jpg", @ "mushroom_risotto.jpg", @ "full_breakfast.jpg", @ "hamburger.jpg", @ "ham_and_egg_sandwich.jpg", @ "creme_brelee.jpg", @ "white_chocolate_donut.jpg", @ "starbucks_coffee.jpg", @ "vegetable_curry.jpg", @ "instant_noodle_with_egg.jpg", @ "noodle_with_bbq_pork.jpg", @ "japanese_noodle_with_pork.jpg", @ "green_tea.jpg", @ "thai_shrimp_cake.jpg", @ "angry_birds_cake.jpg", @ "ham_and_cheese_panini.jpg", nil ]; } |
正如你可以从上面的代码中看到的,我们用图像文件名列表初始化了的缩略图数组。图像的顺序排列与“tableData”对齐。
为了您的方便,您可以下载该图像包,并把它们添加到您的项目,确保“Copy items into destination group’s folder”已勾选当然你也可以用自己的图片。
添加的图像文件后,你应该会在Project Navigator中发现他们,如下面的屏幕:
最后,更改在cellForRowAtIndexPath“方法的代码:
1
|
cell.imageView.image
=
[
UIImage的imageNamed
:
[
缩略图objectAtIndex
:
indexPath.row
]
]
;
|
这行代码获取特定行的图像名字。就是说,indexPath.row属性对于第一行返回0,我们使用“objectAtIndex”的方法选取图像数组的第一个(即egg_benedict.jpg)。
保存所有的更改后,再次尝试运行您的应用程序。现在应该不同的表中单元格显示缩略图:
应用程序是否可以更好看?我们将通过自定义表格单元格使其更好看。到目前为止,我们使用的默认样式显示表单元格,而且缩略图的位置和大小是固定的。如果你想就像下面的屏幕显示的那样使缩略图更大并附上每个菜的准备时间,怎么办?
在这种情况下,你必须创建和设计自己的表格单元格。返回到Xcode。在项目浏览器中,右键单击“SimpleTable”文件夹并选择“New File ...”。
为了设计我们自己的表格单元格,我们要创建一个新的表格单元格界面生成器。在这种情况下,我们只需要启动一个“空”的用户界面。点击“下一步”继续。
当提示选择设备系列时,选择“iPhone”,然后单击“下一步”继续。保存的文件为“SimpleTableCell”。
一旦该文件被创建时,你就能在Project Navigator中找到它。选择“SimpleTableCell.xib”切换到界面生成器。我们要设计的自定义表格单元格的外观。
在对象库中,选择“Table View Cell(表格视图单元格)”,将其拖动到界面生成器的设计区域。
为了容纳更大的缩略图,我们要改变单元格的高度。只要按住下/上侧的单元格边缘并缩放到高度78。
或者,您也可以使用“Size Inspector”改变高度。
下一步,选择“Attributes Inspector(属性检查器)“的上半部分的通用区域来为自定义单元格“SimpleTableCell”设置“Identifier(标识符)”。这个标识符将在后面的代码中使用。
表格单元格视图配置好之后,我们将往他里面放其他元素。选择“Image View”,并把它拖到表视图单元格。
image view用于显示缩略图。您可以调整其大小,使其适合单元格。参考数值,我设置的高度和宽度为69像素。
接下来,我们将添加三个标签:Name(姓名),Prep Time(准备时间)和Time(时间)。“Name”标签将用于显示配方的名称。“Prep Time”是一个静态的标签,只显示“准备时间”。最后,“Time”的标签是一个动态的标签被用于显示实际的具体菜肴的准备时间。
要添加一个标签,在Object library(对象库)中选择“标签”,将其拖动到单元格中。您可以双击标签以更改其名称。
和上面所显示的做比较,您可能会发现您的字体大小和样式是不同的。要更改字体样式,只需选择标签并选择“Attribute Inspector(属性检查器)”。从这里,你可以改变“字体”和最小字体大小的设置。您也可以通过检查更改文本颜色和对齐方式。
您的最终设计应该类似于这样:
到目前为止,我们已经设计了表格单元格。但如何才能改变自定义单元格的标签值吗?我们要为自定义表视图单元格创建一个新的类。这个类代表了自定义单元格的底层数据模型。
就像以前一样,右键单击“SimpleTable的项目浏览器”文件夹中,然后选择“新建文件”。
选择该选项后,Xcode会提示你选择一个模板。我们要创建一个新的自定义表格视图单元格类,选择“Objective-C类”下的“Cocoa Touch”,然后单击“下一步”。
类名填写“SimpleTableCell”,选中"Subclass of "里的“UITableViewCell”。
单击“下一步”,保存的文件在SimpleTable项目文件夹,并单击“创建”继续。Xcode将在Project Navigator中创建两个名为“SimpleTableCell.h”文件和“SimpleTableCell.m”。
正如前面提到的中,SimpleTableCell类作为自定义单元格的数据模型。在单元格中,我们有三个值是可变的:thumbnail image view(缩略图图像视图),name label(名称标签)和time label(时间标签)。在这个类里,我们将添加三个属性来表示这些动态值。
打开“SimpleTableCell.h”和之前的“@end”行中添加以下属性:
1
2 3 |
@property
(nonatomic, weak
)
IBOutlet UILabel
*nameLabel;
@property (nonatomic, weak ) IBOutlet UILabel *prepTimeLabel; @property (nonatomic, weak ) IBOutlet UIImageView *thumbnailImageView; |
@property (attributes) type name;
参考上面的代码,weak和nonatomic是attributes。UILabel和UIImageView是type,而“nameLabel”,“prepTimeLabel”和“thumbnailImageView”是name。
那么,IBOutlet是什么?你可以把IBOutlet想成一个指令。为了与表视图单元格(即SimpleTableCell.xib)中的元素相关联,我们使用关键字“IBOutlet”让Interface Builder中知道,他们被允许连接。后来,你会看到如何使这些outlets和在Interface Builder中的对象之间的连接。
现在,打开“SimpleTableCell.m”,以下“@implementation SimpleTableCell”下面添加以下代码:
1
2 3 |
@synthesize
nameLabel
=
_nameLabel;
@synthesize prepTimeLabel = _prepTimeLabel; @synthesize thumbnailImageView = _thumbnailImageView; |
保存更改并选择“SimpleTableCell.xib”回到Interface Builder中。现在我们可以在类的属性和Label/ ImageView之间创建连接。
首先,选择单元格,在“Identity Inspector”中把类改为“SimpleTableCell”,这样就可以在单元格视图和我们之前创建的类之间建立联系。
现在,我们要建立的连接的属性。右键单击"Objects"下的“SimpleTableCell”,以显示“Outlets”查询器。单击并按住“nameLabel”旁边的圆圈,并将其拖动到Label – Name”对象。Xcode会自动建立连接。
为“prepTimeLabel”和“thumbnailImageView”重复上述操作:
View”:
当你建立所有的连接后,它看起来应该是这样的:
我们已经完成了自定义表格单元格的设计和编码。最后,我们来到最后修改的部分 - 确认自定义单元格放在SimpleTableViewController中。
让我们重温在“SimpleTableView.m”的代码:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
-
(UITableViewCell
*
)tableView
:
(UITableView
*
)tableView cellForRowAtIndexPath
:
(
NSIndexPath
*
)indexPath
{ static NSString *simpleTableIdentifier = @ "SimpleTableItem"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier :simpleTableIdentifier ]; if (cell == nil ) { cell = [ [UITableViewCell alloc ] initWithStyle :UITableViewCellStyleDefault reuseIdentifier :simpleTableIdentifier ]; } cell.textLabel.text = [tableData objectAtIndex :indexPath.row ]; cell.imageView.image = [UIImage imageNamed : [thumbnails objectAtIndex :indexPath.row ] ]; return cell; } |
我们先前使用默认的表视图单元格(即UITableViewCell)显示的表项。为了使用我们的自定义表格单元格,我们必须改变在“SimpleTableView.m”代码:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
-
(UITableViewCell
*
)tableView
:
(UITableView
*
)tableView cellForRowAtIndexPath
:
(
NSIndexPath
*
)indexPath
{ static NSString *simpleTableIdentifier = @ "SimpleTableCell"; SimpleTableCell *cell = (SimpleTableCell * ) [tableView dequeueReusableCellWithIdentifier :simpleTableIdentifier ]; if (cell == nil ) { NSArray *nib = [ [ NSBundle mainBundle ] loadNibNamed : @ "SimpleTableCell" owner :self options : nil ]; cell = [nib objectAtIndex : 0 ]; } cell.nameLabel.text = [tableData objectAtIndex :indexPath.row ]; cell.thumbnailImageView.image = [UIImage imageNamed : [thumbnails objectAtIndex :indexPath.row ] ]; cell.prepTimeLabel.text = [prepTime objectAtIndex :indexPath.row ]; return cell; } |
然而,当你你更新代码后,,Xcode检测会有一些错误在源代码编辑器。
有什么问题吗?我们刚刚修改的代码告诉“SimpleTableViewController”去使用“SimpleTableCell”类的表格单元格。然而,“SimpleTableViewController”不知道“SimpleTableCell”类。这就是为什么Xcode会显示错误。
正如在第一个教程说的,一个头文件中声明一个类的接口。对于“SimpleTableViewController”要认识“SimpleTableCell”,我们必须在“SimpleTableViewController.m”导入“SimpleTableCell.h”。
通过导入“SimpleTableCell.h”,“SimpleTableViewController”知道"SimpleTableCell是什么并可以利用它。
最后,由于表格单元格的高度改为78,在“@end”前面添加下面的代码。
1
2 3 4 |
-
(CGFloat
)tableView
:
(UITableView
*
)tableView heightForRowAtIndexPath
:
(
NSIndexPath
*
)indexPath
{ return 78; } |
现在,点击“Run”按钮和您的SimpleTable的应用程序看起来应该象下面这样:
您可能会注意到应用程序没有显示具体时间。我故意把这个给你。尝试在你的代码做一些修改来更新准备时间。你最终的应用程序看起来非常类似下面的:
在完成本教程后,你应该对UITableView有一个更好的了解,你可以创建自己的表格单元格。下一步,我们将进一步讨论如何处理行选择。
与往常一样,我喜欢听听您的意见。