table view应该是iOS应用中最常用的UI element。最好的例子就是iPhone自带的一些应用,如电话,邮件,设置等。TED,Google+,Airbnb,微信等等都是很好例子。
创建一个项目
- 项目名称为SimpleTable,模板为"Single View application"
设计UI
- 选中
Main.storyboard
,从Object library中拖动Table View
进入视图 - 改变
Table View
的大小至整个view,修改属性Prototype Cells
为1 - 选中
Table View Cell
,修改Style
为Basic,Identifier
为Cell。table view cell的标准类型有 basic、right detail、left detail 和 subtitle,当然还有定制类型custom。 - 选中
Table View
,设置四个spacing约束,上下左右的距离都设置为0
为UITableView添加两个协议
- Object library中的每一UI component都是对应一个class,如
Table View
就是对应UITableView
。可以通过点击并悬停在UI component上查看对应的class和介绍。 - 在
ViewController.swift
文件的UIViewController
后,添加代码, UITableViewDataSource, UITableViewDelegate
,表示ViewController
类实现了UITableViewDataSource
,UITableViewDelegate
两个协议。
出现红色感叹号,这是xcode的问题提示,点击参看问题描述:
Type 'ViewController' does not conform to protocol
'UITableViewDataSource'
问题描述为ViewController
不符合协议UITableViewDataSource
。通过command+点击 (最新的xcode9变成了command+option+点击)到UITableViewDataSource
中看看你:
public protocol UITableViewDataSource : NSObjectProtocol {
@available(iOS 2.0, *)
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
@available(iOS 2.0, *)
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
@available(iOS 2.0, *)
optional public func numberOfSections(in tableView: UITableView) -> Int // Default is 1 if not implemented
@available(iOS 2.0, *)
optional public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? // fixed font style. use custom view (UILabel) if you want something different
@available(iOS 2.0, *)
optional public func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String?
// Editing
// Individual rows can opt out of having the -editing property set for them. If not implemented, all rows are assumed to be editable.
@available(iOS 2.0, *)
optional public func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool
...
-
UITableViewDataSource
协议中定义了很多方法,除了前两个方法没有optional
其它都有,有的表示这个方法不一定要实现,没有的就一定要实现,把这个两个方法实现了,问题提示就会消失。这两个方法从名字和返回值类型也大概能知道做了什么:-
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
一个section有几行,也就是一个section有几个UITableViewCell
, section就是一组UITableViewCell
的意思,Table View可以定义多个section,默认是一个。 -
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
返回每一行的UITableViewCell
-
在
ViewController.swift
中定义一个变量restaurantNames
,类型是数组,表示一系列餐馆的名字。
var restaurantNames = ["Cafe Deadend", "Homei", "Teakha", "Cafe Loisl", "PetiteOyster", "For Kee Restaurant", "Po's Atelier", "Bourke Street Bakery", "Haigh'sChocolate", "Palomino Espresso", "Upstate", "Traif", "Graham Avenue Meats AndDeli", "Waffle & Wolf", "Five Leaves", "Cafe Lore", "Confessional","Barrafina", "Donostia", "Royal Oak", "CASK Pub and Kitchen"]
- 定义
UITableViewDataSource
的两个方法:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// 1
return restaurantNames.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->
UITableViewCell {
// 2
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier,
for: indexPath)
// 3
cell.textLabel?.text = restaurantNames[indexPath.row]
return cell
}
- 1 餐馆的数目就是section的行数
- 2 "Cell"与之前定义的
UITableViewCell
的Identifier
属性是对应的。dequeueReusableCell
方法是产生一个UITableViewCell
。 - 3
UITableViewCell
中有可算属性textLabel
,其实就是一个UILabel
,由于是可选属性,调用时也用可选链式调用cell.textLabel?.text
连接 DataSource 和 Delegate
运行app,没有数据显示。尽管上面已经在代码中让ViewController
继承了UITableViewDataSource
, UITableViewDelegate
,但storyboard并不知道。
- 在document outline中选择Table View,使用control-drag到View Controller,在弹出框中选择dataSource。同样的方法选择delegate
- 确认连接是否成功。选中Table View,在connetion检查器中查看;或者直接在document outline中右击Table View
-
运行app
添加图片到Table View
- 从simpletable-image1.zip下载图片,解压后一起拖到asset catalog
- 在
ViewController.swift
的tableView(_:cellForRowAtIndexPath:)
方法的return cell
前添加代码cell.imageView?.image = UIImage(named: "restaurant")
。使每个UITableViewCell
的image都是一样的。
隐藏状态栏
顶部状态来和table view 数据重叠了,只要在ViewController
加一段代码就可以:
override var prefersStatusBarHidden: Bool {
return true
}
prefersStatusBarHidden
是父类UIViewController
中的属性,所以要加 override
,表示重写了。
不同的Cell对应不同的图片
- 从simpletable-image2.zip下载图片,解压后一起拖到asset catalog
- 修改
ViewController.swift
的tableView(_:cellForRowAtIndexPath:)
为:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->
UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier,
for: indexPath)
// Configure the cell...
let restaurantName = restaurantNames[indexPath.row]
cell.textLabel?.text = restaurantName
// 1
let imageName = restaurantName.lowercased().replacingOccurrences(of: " ", with: "")
if let image = UIImage(named: imageName) {
cell.imageView?.image = image
} else {
cell.imageView?.image = UIImage(named: "restaurant")
}
return cell
}
- 1 把菜馆名字字符串先修改成小写,然后去空格
- 最终结果
代码
Beginning-iOS-Programming-with-Swift
说明
此文是学习appcode网站出的一本书 《Beginning iOS 10 Programming with Swift》 的一篇记录