Swift - tableView单元格高度自适应3(图片宽度固定,高度自适应)
(本文代码已升级至Swift3)
在之前的两篇文章中,列表单元格中使用的都是文本标签(Label)。本文演示图文混合的单元格(即一个单元格中除了 Label 还有 UIImageView)如何实现高度自适应。

2,实现步骤
(1)我们先创建一个自定义的单元格类(ImageTableViewCell.swift),同时创建其对应的 XIB 文件(ImageTableViewCell.xib)。

(5)对 ImageView 设置左右下 3 个约束。
(6)ImageTableViewCell.swift 代码
上面约束设置后,imageView 的宽度就固定下来了。为了让其高度自适应,我们需要在代码中通过获取其内部显示图片的宽高比,来动态地设置 imageView 的宽高比约束。保证 imageView 与原始图片的比例是一样的。
(7)ViewController.swit
在首页中我们创建一个 tabbleView 来测试上面我们自定义的单元格。这里没什么特别的,同前文差不多。
hangge_1343.zip

hangge_1343.zip
1,样例效果图
(1)单元格上面是文字,下面是图片。
(2)文字标签(UILabel)行数是自增长的。
(3)图片显示(UIImageVIew)宽度占满一行,高度随原图比例自适应高度。
(4)整个单元格高度自适应,能完整地显示全部的内容。


(1)我们先创建一个自定义的单元格类(ImageTableViewCell.swift),同时创建其对应的 XIB 文件(ImageTableViewCell.xib)。

(2)打开 ImageTableViewCell.xib,在里面添加一个 Label(用来显示标题文字),和一个 ImageView(用来显示内容图片)。并将它们在对应类中做关联引用。

(3)为了让 Label 标签能自动增长,将其 Lines 属性设置为 0。

(4)对 Label 设置上下左右 4 个约束。


上面约束设置后,imageView 的宽度就固定下来了。为了让其高度自适应,我们需要在代码中通过获取其内部显示图片的宽高比,来动态地设置 imageView 的宽高比约束。保证 imageView 与原始图片的比例是一样的。
import UIKit class ImageTableViewCell: UITableViewCell { //标题文本标签 @IBOutlet weak var titleLabel: UILabel! //内容图片 @IBOutlet weak var contentImageView: UIImageView! //内容图片的宽高比约束 internal var aspectConstraint : NSLayoutConstraint? { didSet { if oldValue != nil { contentImageView.removeConstraint(oldValue!) } if aspectConstraint != nil { contentImageView.addConstraint(aspectConstraint!) } } } override func awakeFromNib() { super.awakeFromNib() } override func prepareForReuse() { super.prepareForReuse() //清除内容图片的宽高比约束 aspectConstraint = nil } //加载内容图片(并设置高度约束) func loadImage(name: String) { if let image = UIImage(named: name) { //计算原始图片的宽高比 let aspect = image.size.width / image.size.height //设置imageView宽高比约束 aspectConstraint = NSLayoutConstraint(item: contentImageView, attribute: .width, relatedBy: .equal, toItem: contentImageView, attribute: .height, multiplier: aspect, constant: 0.0) //加载图片 contentImageView.image = image }else{ //去除imageView里的图片和宽高比约束 aspectConstraint = nil contentImageView.image = nil } } }
(7)ViewController.swit
在首页中我们创建一个 tabbleView 来测试上面我们自定义的单元格。这里没什么特别的,同前文差不多。
import UIKit class ViewController: UIViewController , UITableViewDelegate, UITableViewDataSource { var catalog = [[String]]() var tableView:UITableView! override func viewDidLoad() { super.viewDidLoad() //初始化列表数据 catalog.append(["第一节:Swift 环境搭建", "img1.jpg"]) catalog.append(["第二节:Swift 基本语法(类型定义、循环遍历、判断、继承)", "img2.jpg"]) catalog.append(["第三节:Swift 数据类型", "img3.jpg"]) //创建表视图 self.tableView = UITableView(frame: self.view.frame, style: .plain) self.tableView.delegate = self self.tableView.dataSource = self //创建一个重用的单元格 self.tableView!.register(UINib(nibName:"ImageTableViewCell", bundle:nil), forCellReuseIdentifier:"myCell") //设置estimatedRowHeight属性默认值 self.tableView.estimatedRowHeight = 44.0; //rowHeight属性设置为UITableViewAutomaticDimension self.tableView.rowHeight = UITableViewAutomaticDimension; self.view.addSubview(self.tableView!) } //在本例中,只有一个分区 func numberOfSections(in tableView: UITableView) -> Int { return 1 } //返回表格行数(也就是返回控件数) func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.catalog.count } //创建各单元显示内容(创建参数indexPath指定的单元) func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { //同一形式的单元格重复使用 let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! ImageTableViewCell //获取对应的条目内容 let entry = catalog[indexPath.row] //单元格标题和内容设置 cell.titleLabel.text = entry[0] cell.loadImage(name: entry[1]) return cell } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }源码下载:

3,从网络获取图片
上面的样例我们是直接加载本地图片的。在实际项目中,我们通常会通过 url 地址加载网络上的图片并显示。
上面的样例我们是直接加载本地图片的。在实际项目中,我们通常会通过 url 地址加载网络上的图片并显示。

只需要将 ImageTableViewCell 类做如下修改可以满足需求,同样支持图片的高度自适应。
使用时,由原来的图片名称改成图片 url 地址即可。
import UIKit class ImageTableViewCell: UITableViewCell { //标题文本标签 @IBOutlet weak var titleLabel: UILabel! //内容图片 @IBOutlet weak var contentImageView: UIImageView! //内容图片的宽高比约束 internal var aspectConstraint : NSLayoutConstraint? { didSet { if oldValue != nil { contentImageView.removeConstraint(oldValue!) } if aspectConstraint != nil { contentImageView.addConstraint(aspectConstraint!) } } } override func awakeFromNib() { super.awakeFromNib() } override func prepareForReuse() { super.prepareForReuse() //清除内容图片的宽高比约束 aspectConstraint = nil } //加载内容图片(并设置高度约束) func loadImage(urlString: String) { //定义NSURL对象 let url = URL(string: urlString) let data = try? Data(contentsOf: url!) //从网络获取数据流,再通过数据流初始化图片 if let imageData = data, let image = UIImage(data: imageData) { //计算原始图片的宽高比 let aspect = image.size.width / image.size.height //设置imageView宽高比约束 aspectConstraint = NSLayoutConstraint(item: contentImageView, attribute: .width, relatedBy: .equal, toItem: contentImageView, attribute: .height, multiplier: aspect, constant: 0.0) //加载图片 contentImageView.image = image }else{ //去除imageView里的图片和宽高比约束 aspectConstraint = nil contentImageView.image = nil } } }
//初始化列表数据 catalog.append(["iPhone 6的故障率达26% 稳超安卓", "http://www.hangge.com/img1.png"]) catalog.append(["不用导航 这款无人机能够“自制”地图飞行", "http://www.hangge.com/img2.png"]) catalog.append(["无人汽车如何应对道德困境?谷歌表示不知道", "http://www.hangge.com/img33.png"])源码下载:

打开应用初次进入页面,高度总是错误,再次进入又正确了,该怎么办呢?
当cell的imageView读取网络url时,cell过多会因为 let url = URL(string: urlString)
let data = try? Data(contentsOf: url!)
好性能方法在主线程执行导致界面卡顿,有没有 好的方法处理??
航哥你好,我想问一下,我按照您这个方法做的自适应单元格,现在我想在cell中加一个button,点击单元格的button可以跳转到另一个页面,类似微信朋友圈中点击头像可以跳到对应的个人主页这样的功能。我知道跳转界面的方法是self.performSegue(withIdentifier: "identifier", sender: itemData),但是这个方法该在哪里写呢,cell的xib文件里好像不能直接写这个方法。谢谢谢谢!!
正好遇到这个,感谢