UI基础 - storyboard_swift版 02:Prototype Cell

Prototype Cell

1 -在故事模板中拖进一个 UITableViewController,并设置为初始场景。cell 配置如下

2 - 指定一个 data source:新建 PlayersViewController,它是 UITableViewController 的子类。然后回到 Storyboard,选择表视图控制器,在身份检查器 Identity inspector 中设置它的 Class 为 PlayersViewController,此时 Storyboard 中加载的那个表视图控制器就是 PlayersViewController 的实例

3 - 创建数据模型:Player.swift 文件,它包含玩家名、游戏名、评分

复制代码
 1 import UIKit
 2 
 3 class Player: NSObject {
 4     var name: String
 5     var game: String
 6     var rating: Int
 7     
 8     init(name: String, game: String, rating: Int) {
 9         self.name = name
10         self.game = game
11         self.rating = rating
12         super.init()
13     }
14 }
复制代码

 

 

 

 

 

 

 

 

 

在 PlayersViewController 中赋值到一个数组。请使用 Swift File 模板创建名为 『SampleData』 的新文件,并在 SampleData.swift 中追加以下代码

1 let playersData = [ Player(name:"Bill Evans", game:"Tic-Tac-Toe", rating: 4),
2                     Player(name: "Oscar Peterson", game: "Spin the Bottle", rating: 5),
3                     Player(name: "Dave Brubeck", game: "Texas Hold 'em Poker", rating: 2) ]

 

9 - 现在在 PlayersViewController.swift 的 class PlayersTableViewController: UITableViewController 下面添加一个玩家数组属性,用来保存玩家列表

1  var players: [Player] = playersData

说明:这里,你可能会在 PlayersViewController 中定义 players 变量时顺带就把示例数据准备好了,但以后数据可能源自 plist 或 SQL 文件,所以,在视图控制器之外处理数据加载问题是明智之选

10 - 现在你有一个包含多个 Player 对象的数组,可以在 PlayersViewController 中绑定数据源了。还是在 PlayersViewController.swift 中,用以下代码替换表视图数据源方法

复制代码
 1     override func numberOfSections(in tableView: UITableView) -> Int {
 2         // #warning Incomplete implementation, return the number of sections
 3         return 1
 4     }
 5 
 6     override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
 7         // #warning Incomplete implementation, return the number of rows
 8 
 9          return players.count
10     }
复制代码

11 - 实际工作在 cellForRowAtIndexPath 中。用以下代码替换方法(原来的注释掉)

复制代码
 1     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
 2  
 3         let cell = tableView.dequeueReusableCell(withIdentifier: "PlayerCell", for: indexPath)
 4             as UITableViewCell
 5         
 6         let player = players[indexPath.row] as Player
 7         cell.textLabel?.text = player.name
 8         cell.detailTextLabel?.text = player.game
 9         return cell
10         
11     }
复制代码

说明:dequeueReusableCell(withIdentifier: "PlayerCell", for: indexPath) 方法用来检查是否存在可重用的表项。如果没有,就返回一个自动分配的原型表项。你只需要提供之前在 Storyboard 编辑器中给原型表项设定的重用标识符,本例中对应 『PlayerCell』。一定要设置标识符,否则无法正常工作

12 - 运行App,现在表视图中有玩家项了

 

注: - 该 App 中只使用了一个原型单元格,但如果你的列表需要显示不同种类的单元格,你可以向 Storyboard 中另外添加原型单元格。可以复制现有的单元格再进行修改,也可以增大表视图的 Prototype Cells 属性值。记得每个表项都要设置自己的重用标识符

设计自己的原型单元格

1 - 对很多 App 来说使用内建的标准表项样式已经足够了,但这个 App 需要在表项的右侧添加一个显示评分(1星到5星)的图片。标准表项样式不支持在这里包含图片视图,所以你只能自己创建自定义设计

2 - 切回 Main.storyboard,选择表视图中的原型单元格,在属性检查器中设置 Style 属性为 Custom(自定义),运行,随后默认的 Label 不见了

3 - 首先让表项增高一些,拖动底边上的小方块或在尺寸检查器(Size inspector)中修改 Row Height(行高)值,设置表项高度为55点(points)

4 - 从 Objects Library 拖两个 Label 到表项上,把它们放到和之前的标准样式差不多的地方,你可以在属性检查器中随意设置字体和颜色。设置上面的 Label 文本为『Name』,下面的为『Game

5 - 把一个 Image View(图片视图)拖到表项中,放在右面紧挨展开方向标的地方,设宽度为81点,高度不是很重要。将其 Mode 设为 Center(在属性检查器的View下面),保证载入视图的图片不会被拉伸

6 - 在尺寸检查器中设 Label 宽度为190点。Label不应盖住 Image View。原型表项的最终设计大概是这个样子

7 - 因为这是一个自定义单元格,所以再也不能用  UITableViewCell 中的 textLabel 和 detailTextLabel 属性来设置文本了。这些属性只在标准表项类型中有效,它们指向的 label 在该表项中已经不存在了。为此,你需要用 tag(标记)找到相应的 label

8 - 你也可以选择创建一个继承 UITableViewCell 的自定义类并包含对应单元格视图中的 label 的属性。而 tag 可以用来简化工作,在简单情况下是很不错的解决方案。不过本教程后面会尝试使用自定义类的方法

9 - 在属性检查器中设置『Name』Label 的 tag 值为100,『Game』Label 为101,Image View 为102

10 - 打开 PlayersViewController.swift,在后面如下添加新方法 imageForRating

复制代码
 1     func imageForRating(rating:Int) -> UIImage? {
 2         switch rating {
 3         case 1:
 4             return UIImage(named: "1StarSmall")
 5         case 2:
 6             return UIImage(named: "2StarsSmall")
 7         case 3:
 8             return UIImage(named: "3StarsSmall")
 9         case 4:
10             return UIImage(named: "4StarsSmall")
11         case 5:
12             return UIImage(named: "5StarsSmall")
13         default:
14             return nil
15         }
16     }
复制代码

11 - 很简单,该方法根据评分返回不同的星级图片。依然在 PlayersViewController 中,如下修改 tableView(_:cellForRowAtIndexPath:)方法

复制代码
 1     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
 2  
 3         let cell = tableView.dequeueReusableCell(withIdentifier: "PlayerCell", for: indexPath) as UITableViewCell //1
 4         
 5         let player = players[indexPath.row] as Player //2
 6         
 7         if let nameLabel = cell.viewWithTag(100) as? UILabel { //3
 8             nameLabel.text = player.name
 9         }
10         if let gameLabel = cell.viewWithTag(101) as? UILabel {
11             gameLabel.text = player.game
12         }
13         if let ratingImageView = cell.viewWithTag(102) as? UIImageView {
14             ratingImageView.image = self.imageForRating(rating: player.rating)
15         }
16         return cell
17     }
复制代码

说明:①  dequeueReusableCell 在回收表项可重用的情况下会抽出重用标识符为PlayerCell的表项,否则创建一个新表项

   ②  按行号查看 Player 对象并将其赋值给 player

   ③  按表项上的 tag 找到 label 和图片,并参照 player 对象填充数据

12 - 应该可以了。现在再次运行 App,大概会像这样

13 - 看起来不大对劲:表项都重叠在一起了。你只修改了原型表项的高度,但是并没有把表视图考虑进去。这里有两个解决方案,一是改变表视图的 Row Height 属性,二是实现 tableView(tableView:heightForRowAtIndexPath:)方法。本例中前者更合适,因为只有一种表项,而且我们已经事先了解表项的高度

注: - 如果无法事先判定表项的高度,或者各行的高度可能不一致,可以使用 tableView(tableView:heightForRowAtIndexPath:)方法

14 - 回到 Main.storyboard,在表视图的尺寸检查器中设 Row Height 为 55 点

15 - 现在运行,一切高大上

 

posted on   低头捡石頭  阅读(65)  评论(0编辑  收藏  举报

编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示