您的位置:时时app平台注册网站 > 编程知识 > UITableViewCell 自动高度时时app平台注册网站

UITableViewCell 自动高度时时app平台注册网站

2019-09-16 07:32

contentSize

大名鼎鼎 UITableView 继承于 UIScrollView,那么 UITableView 就供给安装 contentSize 值。那么 UITableView 怎么着知道 contentSize 的值呢?

一定中度

假定 TableView 中的 Cell 接纳的是一贯中度,那么 contentSize 的可观很醒目正是 fixedHeight × cellCount

自行中度

当使用了机关中度的话,那么系统会分别调用 Cell 上的 systemLayoutSizeFittingSize 的诀窍,那个方法会遵照你为 Cell 设置的羁绊总括出 Cell 的尺码,那么 contentSize 就能化为 dynamicallyCalculatedCellSize × cellCount

因此 UITableViewCell 自动中度,大家知晓了要兑现中度缓存大家须求做的办事如下:

UICollectionView

问询了UITableView的Cell行高自适应之后,要理解UICollectionviewCell的Size自适应并轻松,因为UICollectionViewCell相比较于UITableViewCell除了要经过AutoLayout分明contentView的万丈之外还要分明其宽度,其调幅分明规范和UITableViewCell的莫斯中国科学技术大学学分明是看似的,只是要通过UICollectionviewCell的contentView子控件本身鲜明其宽度,然后设置子控件和contentView相关的right约束就能够。当然对于UICollectionViewCell自适应尺寸同样必需设置UICollectionViewFlowLayout的estimatedItemSize属性(尽管接纳UICollectionViewFlowLayout)。
下边包车型客车的demo演示了类Tmall商品展现的UICollectionview布局,除了通过AutoLayout鲜明中度外,通过货色图片的left、right约束和width的设置能够反向估摸出contentView的宽窄,通过Self-Sizing Cells就足以最后显明UICollectionviewCell的size。
Cell布局代码:

    import UIKit

    class ProductCollectionViewCell: UICollectionViewCell {

        // MARK: - 公共属性
        var product:Product! {
            didSet {
                self.productImageView.image = UIImage(named: product.image)
                self.contentLabel.text = product.text
                self.priceLabel.text = "¥(product.price)"
                self.salesLabel.text = "(product.sale)人购买"
            }
        }

        // MARK: - 生命周期及方法覆盖
        override init(frame: CGRect) {
            super.init(frame: frame)
            self.setup()
        }

        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }

        override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
            return super.preferredLayoutAttributesFitting(layoutAttributes)
        }
        // MARK: - 私有方法
        private func setup() {
            self.backgroundColor = UIColor.white
            self.contentView.addSubview(self.productImageView)
            self.contentView.addSubview(self.contentLabel)
            self.contentView.addSubview(self.priceLabel)
            self.contentView.addSubview(self.salesLabel)

            let screenWidth = UIScreen.main.bounds.width
            self.productImageView.snp.makeConstraints { (make) in
                make.top.left.right.equalTo(0.0)
                make.height.equalTo(screenWidth*0.5).priority(999)
                make.width.equalTo((screenWidth-18)*0.5).priority(999) // 此设置可以确定cell宽度,注意尽管降低了默认的优先级仅仅是为了计算中间步骤不至于约束冲突,最终显示时此约束仍然会生效
            }

            self.contentLabel.snp.makeConstraints { (make) in
                make.top.equalTo(self.productImageView.snp.bottom).offset(4.0)
                make.left.equalTo(8.0)
                make.right.equalTo(-8.0)
                make.height.equalTo(28.0)
            }

            self.priceLabel.snp.makeConstraints { (make) in
                make.top.equalTo(self.contentLabel.snp.bottom).offset(8.0)
                make.left.equalTo(self.contentLabel.snp.left)
                make.bottom.equalTo(-8.0) //此设置可以确定cell高度
            }

            self.salesLabel.snp.makeConstraints { (make) in
                make.centerY.equalTo(self.priceLabel.snp.centerY)
                make.right.equalTo(-8.0)
            }
        }

        // MARK: - 私有属性
        private lazy var productImageView:UIImageView = {
            let temp = UIImageView()
            temp.contentMode = .scaleAspectFit
            temp.clipsToBounds = true
            return temp
        }()

        private lazy var contentLabel:UILabel = {
            let temp = UILabel()
            temp.textColor = UIColor(red: 50.0/255.0, green: 50.0/255.0, blue: 50.0/255.0, alpha: 1.0)
            temp.font = UIFont.systemFont(ofSize: 12.0)
            temp.numberOfLines = 2
            return temp
        }()

        private lazy var priceLabel:UILabel = {
            let temp = UILabel()
            temp.textColor = UIColor.orange
            temp.font = UIFont.systemFont(ofSize: 14.0)
            return temp
        }()

        private lazy var salesLabel:UILabel = {
            let temp = UILabel()
            temp.textColor = UIColor(red: 150.0/255.0, green: 150.0/255.0, blue: 150.0/255.0, alpha: 1.0)
            temp.font = UIFont.systemFont(ofSize: 12.0)
            return temp
        }()

    }

终极效果:
时时app平台注册网站 1
除开从iOS 8最先,UICollectionViewCell提供了preferredLayoutAttributesFitting()方法用于提供一些cell属性修改,当然通过此办法能够重复修改cell的size(富含Self-Sizing Cells自动总结后的size),对于手动总括中度的情形那也方法也提供了一种不用外界设置cell size的而能提供让UICollectionView鲜明cell尺寸的方法,但是那并不在Self-Sizing Cells商讨之列,由此本文不再深刻座谈。

时时app平台注册网站 2

主题素材及优化

在 iOS8 中选拔了 Cell 自动中度之后,你会发觉,只要三个 Cell 须求被出示到显示屏上,它的莫斯中国科学技术大学学都会被计算叁次,尽管这些 Cell 在前面包车型客车滑行中曾经被总结过高度了。之所以被规划成这么的原由系统感觉 Cell 的万丈是时刻恐怕退换的,举个例子在安装中改动了字体大小:

时时app平台注册网站 3

假设在 iOS7 中采取了全自动中度,你就能开采只要 Cell 在前头被总括过中度,那么它下三次滑动出来时就不会被计算中度了。那是因为从 iOS7 开端,iOS7 中引进了 Dynamic Type 的效劳,这么些效果使得客户可以调治应用中字体的尺寸,而 iOS7 中的全数系统运用都适配了这么些意义须求。可是从 iOS8 初阶,Apple 希望具有的施用都能够适配那么些作用必要,于是就收回了 Cell 在机动算高时的惊人缓存。

于是乎如您所见,在 iOS第88中学由于尚未了自行的万丈缓存,那么在接纳机关中度时,Cell 的中度会被屡屡计算,那样就能够招致滑动不流畅。其实那不是大的难点,Apple 为了把 Cell 的可观总结变得越来越灵敏,使得是还是不是动态总括高度 or 使用缓存已总括的万丈的干活嵌入了开拓者那边,如故很适合设计方式的,只可是开辟者使用有个别麻烦了。

优化的点子实在聊到来也是很简短的,正是对此曾经计算了可观的 Cell,只要确信它的惊人是不会再转移的,那么就将以此高度缓存起来,下回在系统向您所要 Cell 中度时(heightForRowAtIndexPath),重回那三个之间总括过的惊人缓存就行了。

其实 iOS7 中应用 Cell 自动中度未有何好研讨的了,系统会自行的为大家缓存已经总计过的 Cell 中度。独一要留意的是在 iOS7 中必要显式的装置:

tableView.rowHeight = UITableViewAutomaticDimension;

其余依然和在 iOS8 中一致的:你为 Cell 设置了『合理的封锁』,让 TabaleView 使用电动 Cell 中度计算,剩下的系列就为了做了。

全盘没接触过不清楚

地方已经说了在 iOS8 中大家需求团结主宰是或不是缓存那么些早就总结过的 Cell 中度。那么大家相应怎么样缓存呢?有两点很关键:

  1. 缓存的 Key 怎么着支配
  2. 利用什么作为 Cache Storage

经过翻阅源码,大家会意识在 FDT 中况且采纳了 objc_setAssociatedObjectNSMutableArray

UITableView

大家都明白UITableView从iOS 8开端达成行高的自适应相对相比较轻松,首先必需安装estimatedRowHeight提交预估高度,设置rowHeightUITableViewAutomaticDimension(注意:假设不变rowHeight默许就是UITableViewAutomaticDimension),对于那多少个参数除了直接修改tableview对应的属性之外依旧支撑使用相应的代办方法设置。最终只要在UITableViewCell中设置contentView的约束就能够。由于UITableViewCell的升幅等同于UITableView由此约束的装置事实上只是为了活动总计中度。平时的做法便是安装contentView的top和bottom约束,而后个中间子视图能够提供intrinsicContentSize(举例UIButtonUILabel暗中同意就曾经提供)大概已经有鲜明的height约束。这样一来就足以成功子控件鲜明了本人中度,而contentView子控件又设置了和contentView相关的bottom约束来反向计算出UITableViewCell的实在中度。
上边依然之前边UITableView著作的自定义Cell比如,比较在此以前大气的演算来讲Self-Sizing Cells能够说简化了非常多。除了安装estimatedRowHeight外最根本的正是丰盛相关Autolayout约束。由于头像中度已经固化,内容中度能够由此固有中度自动测算,而双方的距离和top、bottom约束已经固定,进而Self-Sizing Cells能够活动测算出Cell的惊人。
惊人计算约束关系:
时时app平台注册网站 4
Cell布局代码:

    import UIKit
    import SnapKit

    class StatusTableViewCell: UITableViewCell {

        // MARK: - 公共属性
        var status:Status! {
            didSet {
                self.avatarImageView.image = UIImage(named: status.profileImageUrl)
                self.userNameLabel.text = status.userName
                self.mtypeImageView.image = UIImage(named: status.mbtype)
                self.createdAtLabel.text = status.createdAt
                self.sourceLabel.text = status.source
                self.contentLabel.text = status.text
            }
        }

        // MARK: - 生命周期及方法覆盖
        override func awakeFromNib() {
            super.awakeFromNib()
        }

        override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            self.setup()
        }

        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }

        override func setSelected(_ selected: Bool, animated: Bool) {

        }

        // MARK: - 私有方法
        private func setup() {
            self.contentView.addSubview(self.avatarImageView)
            self.contentView.addSubview(self.userNameLabel)
            self.contentView.addSubview(self.mtypeImageView)
            self.contentView.addSubview(self.createdAtLabel)
            self.contentView.addSubview(self.sourceLabel)
            self.contentView.addSubview(self.contentLabel)

            self.avatarImageView.snp.makeConstraints { (make) in
                make.top.left.equalTo(10.0)
                make.size.equalTo(CGSize(width: 40.0, height: 40.0))
            }

            self.userNameLabel.snp.makeConstraints { (make) in
                make.top.equalTo(self.avatarImageView.snp.top)
                make.left.equalTo(self.avatarImageView.snp.right).offset(8.0)
            }

            self.mtypeImageView.snp.makeConstraints { (make) in
                make.top.equalTo(self.userNameLabel.snp.top)
                make.left.equalTo(self.userNameLabel.snp.right).offset(8.0)
                make.size.equalTo(CGSize(width: 14.0, height: 14.0))
            }

            self.createdAtLabel.snp.makeConstraints { (make) in
                make.left.equalTo(self.userNameLabel.snp.left)
                make.bottom.equalTo(self.avatarImageView.snp.bottom)
            }

            self.sourceLabel.snp.makeConstraints { (make) in
                make.left.equalTo(self.createdAtLabel.snp.right).offset(10.0)
                make.bottom.equalTo(self.createdAtLabel.snp.bottom)
                make.right.lessThanOrEqualTo(-8.0)
            }

            self.contentLabel.snp.makeConstraints { (make) in
                make.top.equalTo(self.avatarImageView.snp.bottom).offset(8.0)
                make.left.equalTo(self.avatarImageView.snp.left)
                make.right.equalTo(-8.0)
                make.bottom.equalTo(-10.0) // 注意此处必须设置,否则contentView无法自适应高度
            }

        }

        // MARK: - 私有属性
        private lazy var avatarImageView:UIImageView = {
            let temp = UIImageView()
            return temp
        }()

        private lazy var mtypeImageView:UIImageView = {
            let temp = UIImageView()
            return temp
        }()

        private lazy var userNameLabel:UILabel = {
            let temp = UILabel()
            temp.textColor = UIColor(red: 50.0/255.0, green: 50.0/255.0, blue: 50.0/255.0, alpha: 1.0)
            temp.font = UIFont.systemFont(ofSize: 14.0)
            return temp
        }()

        private lazy var createdAtLabel:UILabel = {
            let temp = UILabel()
            temp.textColor = UIColor(red: 120.0/255.0, green: 120.0/255.0, blue: 120.0/255.0, alpha: 1.0)
            temp.font = UIFont.systemFont(ofSize: 12.0)
            return temp
        }()

        private lazy var sourceLabel:UILabel = {
            let temp = UILabel()
            temp.textColor = UIColor(red: 120.0/255.0, green: 120.0/255.0, blue: 120.0/255.0, alpha: 1.0)
            temp.font = UIFont.systemFont(ofSize: 12.0)
            return temp
        }()

        private lazy var contentLabel:UILabel = {
            let temp = UILabel()
            temp.textColor = UIColor(red: 50.0/255.0, green: 50.0/255.0, blue: 50.0/255.0, alpha: 1.0)
            temp.font = UIFont.systemFont(ofSize: 14.0)
            temp.numberOfLines = 0
            return temp
        }()

    }

聊起底效果:
时时app平台注册网站 5
任由UITableView还是背后的UICollectionview,Self-Sizing Cells的定义均是从iOS 8最早提议的。要是是iOS 8此前的本子则必要通过systemLayoutSizeFitting()实行总括依旧经过frame直接设置。

第一在 iOS8 开端,系统将 Cell 的莫斯中国科学技术大学学总括明显的分成了二种方法:

我们驾驭数据库中的内容可以经过 ORM 造成 relational entities,譬喻您有八个 Student 表,里面每一行都以贰个上学的小孩子的新闻,于是 ORM 之后每行正是三个 entity,而 primary key(日常正是 autoincrement-id) 就能够看作 Cache Key。

恒定中度

只要一行代码就可以很简短的贯彻 Cell 的原则性中度:

tableView.rowHeight = /* fixed height */;

无法更便于了。

objc_setAssociatedObject

先说说采纳 objc_setAssociatedObject 的地方,分别是:

  1. fd_indexPathHeightCache
  2. fd_keyedHeightCache
  3. ...

大家就看五个杰出的,它们有下边包车型客车风味:

  1. lazy initialized
  2. OBJC_ASSOCIATION_RETAIN_NONATOMIC 到了 UITableView 实例上

如此做的益处呢?很领会啊:

  1. lazy initialized,正是在用到相关的缓存战略时才会早先化其 Cache Storage
  2. 将 Cache 的自由托管给了 UITableView 实例的生命周期,不用管释放内部存款和储蓄器的作业了

也是出于第 2 点优势呢,那么些地点才用了 objc_setAssociatedObject。所以说具体用什么样是酌情而定的,未有银弹。

  1. 恒定中度
  2. 机关中度

在 UITableViewCell 自动中度 中大家早就剖判了三个足以看成 Storage 的候选,最终得出 objc_setAssociatedObjectNSMutableArray 质量要高大优于 NSCache。那么大家能够看看 FDT 的兑现是或不是符合大家的愿意。

Key

因为要求通过 Key 去取回 Cell 已经计算过的 Height,那么 Key 供给能够标志出种种 Cell。大家得以挑选不仅能标志 Cells 又能够区分它们中间不等的特性来作为 Key。对于四个 Objc 对象,它们之间最鲜明的例外确定是它们的 memory address 了,并且亟需得到Objc 对象的内部存款和储蓄器地址也比异常的粗略:

NSString *temp = @"123";uintptr_t ptrAddress = (uintptr_t) temp;

可是,请回忆我们在利用 TableView 和 Cell 时常用的法子:

- dequeueReusableCellWithIdentifier:forIndexPath:- dequeueReusableCellWithIdentifier:

便是它俩驱动 TableView 中 Cells 都以 Reused。所以通过 memory address 的诀要是充裕了。剩下的举世无双可用的议程正是 indexPath

本文由时时app平台注册网站发布于编程知识,转载请注明出处:UITableViewCell 自动高度时时app平台注册网站

关键词: