利用autolayout计算自定义cell高度(swift3.0)

前言

大部分APP里面都会用到UITableView去展示一些列表,列表高度有固定和根据内容确定的。之前做过很多高度不固定cell都是通过代码去计算,经常会遇到东西做完之后产品或者设计觉得不好又要改的,那之前写的计算高度的代码又要改很多,感觉很麻烦。这篇文章主要介绍怎样利用autolayout帮我们计算不固定cell的高度,再也不用担心改动很多了。

最终效果

效果1.png

步骤

1.创建自定义cell

新建一个继承UITableViewCell的自定义cell,我一般喜欢用xib来搭建UI,可以少写很多代码。


1.png

2.拖控件设置添加约束,拖线

这里就不详细介绍怎么添加约束了,实际工作中可以按照设计给的标注添加约束。将图片距离父view最右边的约束拖出来。

2.png

基本上UI相关的都完成了,剩下的就是赋值和一些逻辑处理了。

3.cell赋值和计算逻辑

var isCalculateHeight = false // 用来标记是否是计算高度的cell
var news : CellModel? { // model
        didSet { // 这里做一些赋值和计算操作
            lbTitle.text = news?.title
            lbDesc.text = news?.desc
            lbTime.text = news?.time
            var showImg = false
            if (news?.imageUrl?.characters.count)! == 0 {
                conImgRight.constant = -80 //如果没有图片则不显示图片 -80可以理解为图片的maxX - 80 = 父试图的最右边(也就是宽度)
            }else {
                conImgRight.constant = 15
                showImg = true
            }
            layoutIfNeeded() // 当内容或者约束发生改变时会重新布局
            if isCalculateHeight == true {  // 只有需要计算高度时才执行以下代码
                var cellHeight = CGFloat(lbTime.frame.maxY + 12) // 时间label的底部 + 设计要求的高度
                if showImg == true { // 如果不需要显示图片的话就不用管是图片距离底部最近还是时间距离底部最近了
                    if imgCover.frame.maxY > lbTime.frame.maxY {
                        cellHeight = CGFloat(imgCover.frame.maxY + 12)
                    }
                }
                news?.cellHeight = cellHeight
            }
        }
    }

4.利用cell自身去计算高度

创建计算cell方法

 static func createCalculateCell(maxHeight:CGFloat) -> TableViewCell{
        let cell = TableViewCell.createCell()
        cell.isCalculateHeight = true // 这里要标记为true
        var newFrame = cell.frame
        newFrame.size.width = UIScreen.main.bounds.width // 这里注意一定要把cell宽度改为屏幕的宽度或者自己想要的宽度
        newFrame.size.height = maxHeight // ios7对autolayout的支持不是很好所以最好给一个最大高度
        cell.frame = newFrame
        return cell
    }

这里需要注意的是,从xib中加载出来的view的大小就是xib里面设置的大小,所以计算高度的cell宽度一定要和屏幕一样大不然计算出来的高度会不准确

创建Cell方法


static func createCell()->TableViewCell {
        /* 注意,这里有个坑。如果在cell里面又加了手势的话,那就不能取数组的最后一个了。因为最后一个是手势不是cell
         */
        if let newCell = Bundle.main.loadNibNamed(ID, owner: nil, options: nil)?.last as? TableViewCell {
            return newCell;
        }else {
            let cell = TableViewCell(style: .default, reuseIdentifier: ID)
            cell.textLabel?.text = "error"
            return cell;
        }
    }

可循环利用cell的创建

static func cell(tableView:UITableView!) -> TableViewCell {
        var cell = tableView.dequeueReusableCell(withIdentifier: ID)
        if cell == nil {
            cell = TableViewCell.createCell()
        }
        return cell as! TableViewCell
    }

5.外部使用

提供一个专门用来计算高度的cell,最好用懒加载的方式。如果一个页面有很多种样式的话,有些cell可能根本就没有出现过所以就没必要创建了

lazy var dataArray = Array<CellModel>() 
lazy var calculateCell = TableViewCell.createCalculateCell(maxHeight: 999)

重写tableView cell高度的代理方法

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if indexPath.row < dataArray.count {
            let news = dataArray[indexPath.row]
            if news.cellHeight <= 0 { // 只有当没有高度时才需要计算
                calculateCell.calculate(model: news)
            }
            return news.cellHeight
        }
        return 0
    }

取模型的时候最好是判断一下数组越界的问题

横屏效果

效果2.png

屏幕旋转处理

/*
 *首先注册屏幕旋转通知
 */
func initListener() {
        NotificationCenter.default.addObserver(self, selector: #selector(TableViewController.orientationDidChange(noti:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
 }
 deinit {
        NotificationCenter.default.removeObserver(self)
  }
/*
 *屏幕宽度改变时也要改变计算cell的宽度,把已经算好的高度改为0(也可以多增加一个属性这样横竖屏算一次高度就可以了)
 */
 func orientationDidChange(noti:Notification) {
        dataArray.foreach { (news) in
            news.cellHeight = 0
        }
        calculateCell.updateWidth(maxHeight: 999)
        tableView.reloadData()
    }

源码

点击这里下载源代码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,945评论 4 60
  • 我们在上一篇《通过代码自定义不等高cell》中学习了tableView的相关知识,本文将在上文的基础上,利用sto...
    啊世ka阅读 1,481评论 2 7
  • 2017.02.22 可以练习,每当这个时候,脑袋就犯困,我这脑袋真是神奇呀,一说让你做事情,你就犯困,你可不要太...
    Carden阅读 1,306评论 0 1
  • 1.xib方式创建 每个cell的显示的内容都是固定的,也就是cell的高度都是相同的 加载数据 有plist文件...
    WeiHing阅读 6,846评论 0 6
  • 在三月温暖的阳光下,懒懒的翻开日历,三月十六日,今天是母亲去世两个月了,更忽然已经发现三十岁去哪儿了,在三十年来我...
    思想聚焦的原创阅读 181评论 0 0