IOS 8编程入门--使用swift语言 专题目录:
...............
第七章 使用prototype Cell定制Table View(一)
第七章 使用prototype Cell定制Table View(二)
第八章 表格单元格选取以及UIAlertController(一)
接上一章
我们可以用UIAlertControllerStyle.ActionSheet或者UIAlertControllerStyle.Alert方法应用这两个值。所以当创建UIAlertController时可以使用如下代码:
上面的代码没有什么错误。Swift向开发者提供一种缩写方式可以帮助我们少敲代码。因为preferred Style参数的类型我们已经知道(即UIAlertControllerStyle),Swift允许我们使用一种省略UIAlertControllerStyle的短点号语法。这就是为什么用下面的代码实例化UIAlertControllerm
为Alert Controller添加Action
现在,让我们添加两个Action到alert controller:
“Call”action:呼叫选中的餐馆。我们提前准备一个假的电话号码并且显示“Call 123-000-x”
“I’ve been here“action:当被选中时,给被选中的餐馆添加一个标签。
在tableView(_:didSelectRowAtIndexPath:)方法中,为Call action添加下面的代码。你可以在Cancel action后面插入下面的代码:
这部分代码中callActionHandler对你来说是陌生的。当创建一个UIAlerAction对象时,我们可以指定一段代码块作为处理函数。当用户选择这个Action时这段代码块将会被执行。这里这段代码块显示一个警告,告知我们呼叫功能不可用。
在Swift中,代码块被称为闭包。闭包是包含一定功能的函数块,它可以在代码中传递。这和Objective-C中的块很相似。有一种提供闭包的方法是像声明变量一样声明带有常量或变量的代码块,就像上面的例子。代码块开始的部分是标识,它定义了处理函数的参数,这里是UIAlertAction。In关键字暗示闭包的参数定义和返回类型定义完毕,闭包的体部分开始。图说明闭包的语法。
UIAlertAction的标题是一个假的电话号码。它由“123-000-”加上被选中的行号形成。如你从代码中看到的,Swift允许开发者用加法符号+连接字符串。另外,你可以从整数或者其他符号创建字符。你只需要用一对圆括号包起来并且在前面添加一个反斜杠,像这样:
“Call“+“123-000-\(indexPath.row”
下面是Call Action的实现,添加下面的代码实现”I’ve been here”action:
上面的代码为你显示了另一种使用闭包的方法。你可以将闭包直接写到函数的参数处。这种使用方法更受欢迎,因为它更清晰并且可读性较高。
Swift中的可选类型(Optionals)
你可能奇怪代码中的?是什么意思。Cell是Swift中的可选类型(optional)。可选类型是Swift新引进的类型。可选的意思是“有值”或者”没有值“。由tableView.cellForRowAtIndexPath返回的cell是一个可选值。为了访问cell的附属类型属性,你要使用问号?。在这种情况下,Swift将检查cell是否存在并且在存在时允许你设置附属类型属性值。在大多数情况下,Xcode的自动完成功能在你访问一个可选类型的属性时将为你添加问号。像了解更多关于Optionals的知识,你可以阅读参考手册。
当用户在餐馆中选择”I’ve been here”,我们会为被选中的cell添加选中标签。对于一个表格单元格,它的右边是保留给附属视图的。有4种类型的附属视图显示指示器(disclosure indicator),细节显示按钮(detail disclosure button),选中标志(checkmark)和细节(detail)。在这个例子中,我们使用选中标志作为指示器。在代码的第一行使用indexPath获取被选中的表格单元格。第二行用选中标志更新单元格的附属类型属性。
编译并且运行App。点击餐馆名并且选择任何一个动作(action),App要么显示一个选中标志要么显示一个警告。
到现在为止,当你选择某行,该行会呈现亮灰色并且处于选中状态。在ableView(_:didSelectRowAtIndexPath:)方法的最后添加下面的代码取消行选中。
我们遇到了一个Bug
这个App看起来不错。但是如果你仔细看,App中存在一个Bug。如果你使用”I’ve been here”action标记“Cafe Deadend”餐馆。如果你向下翻表格,你会发现令一个餐馆(例如:Palomino Espresso)也包含一个选中标志。这是什么问题呢?为什么App会增加一个额外的选中标志。这个问题和我们在前面章节里讨论的单元格复用有关。假设UITableView需要显示30个单元格。基于性能的原因,UITableView可能只创建10个单元格然后在表格滚动时复用它们。在这个例子里,UITableView复用了第一个单元格(原来用来显示选中的Cafe Deadend)用于显示令一个餐馆。在我们的代码中,当表格重用单元格时我们只更新了图片和标签。附属图标没有更新。因此下一个餐馆重用了一个有一样附属图标的单元格。如果附属图标包含选中标志,则新的餐馆也会带着一个选中标志。
我们该如何解决这个bug呢?
我们需要找另一个方法来保存餐馆的选中状态。例如,创建令一个数组来保存选中的餐馆?在RestaurantTableViewController.swift中,声明一个Boolean数组:
varrestaurantIsVisited = [Bool](count:21, repeatedValue:false)
在Swift中Bool是一种用于储存布尔值的数据类型。Swift提供两种Boolean值,true和false。我们声明restaurantIsVisited数组存储一个Boolean值的集合。数组中每一个值都指示对应的餐馆是否被标记为”I’ve been here”。例如,我们可以通过查看restaurantIsVisited[0]的值来看”Cafe Deadend”是否被选中。
数组的初始值被设置为全false。换句话说,默认情况下餐馆没有被选中。上面的代码说明了在Swift中一种初始化具有重复值的数组的方法。它和下面的初始化语句是一样的:
修复这个Bug我们需要修改一些代码。首先当某个餐馆被选中了我们需要更新Boolean数组中对应的值。在处理函数isVisited Action中添加一行代码:
这行代码非常简单。我们在餐馆被选中时将相应的值从false修改为true。最后,添加一些代码在tableView(_:cellForRowAtIndexPath:)方法”return cell”之前,用于更新附属图像。
在这里我们检查餐馆是否要显示被选中。如果条件为true,我们在单元格中显示选中。否则,什么也不显示。
好了,重新编译并运行App。Bug现在被修复了。
其实你可以用三元条件操作符(? :)将上面的if条件语句简化为一行代码。三元条件操作符是简化简单条件的有效方法。
你的练习
现在的App不允许用户取消选中。思考一下你如何修改代码使得App能够触发选中标签。当单元格是选中状态的时候,你同样需要显示一个不同于”I’ve been there”的标签。这个功能并不是很难。
如果你需要更多的挑战,你可以尝试把UI做的更好。不使用默认的选中标签,用一个心形图标替代(或者其他你喜欢的图标)。提示一下你需要定制prototype单元格包括图标和设置图标的隐藏属性,当隐藏属性被设置为false的时候可以隐藏图标。这里是示例代码:
iconImageView.hidden= false
花一些时间做一下这个练习。我相信你会学到很多。
小结
到现在为止,你对创建表格,定制单元格和处理表格行选中,已经有了深入的了解了。你可以创建你自己的简单表格App了。是的,开始做你自己的项目。不需要多大。例如,假设你喜欢旅游,那你可以创建一个简单的App显示一系列你喜欢的目的地。如果你喜欢音乐,那可以创建一个App显示你喜欢的歌曲。尽情的使用Xcode,不断犯错,不断学习。
你可以下载 http://pan.baidu.com/s/1skWyPOx 完整的Xcode项目FoodPinCellSelection.zip用做参考。