iOS Autolayout |查看高度锚

时间:2017-06-07 07:24:50

标签: ios swift3 autolayout height anchor

我使用 UITableViewAutomaticDimension 来计算单元格高度。 在我的自定义单元格中,高度取决于它的内容(文本)。
所以我需要布局UIImageView高度。我需要将UIImageView的最大高度设置为某个常量。但是当文字很短时,UIImageView的高度变得更小,以适应其插图的超视图 Current result
Needs to be
游乐场代码示例:

//: Playground - noun: a place where people can play

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let descriptions = ["", "Curabitur.", "Senectus sit consectetur fermentum nisi suspendisse a condimentum at vestibulum a vestibulum a nostra fermentum molestie sodales molestie id viverra scelerisque consectetur.Penatibus a dictum metus mus commodo a hac morbi parturient parturient convallis ultrices a mi id.Fringilla lobortis suspendisse vestibulum quisque consectetur imperdiet.", "Condimentum adipiscing.", "Cras scelerisque parturient vitae class sollicitudin.", "Integer adipiscing a adipiscing parturient tempus condimentum a interdum facilisis feugiat.", "Donec eros eleifend a ullamcorper class scelerisque nisi nullam nisi sociis ante iaculis pharetra malesuada nibh sit consectetur condimentum.Nibh sollicitudin."]

    lazy var tableView: UITableView = {
        let tv = UITableView()
        tv.dataSource = self
        tv.estimatedRowHeight = 80
        tv.rowHeight = UITableViewAutomaticDimension
        tv.separatorStyle = .none
        tv.register(PrototypeCell.self, forCellReuseIdentifier: NSStringFromClass(PrototypeCell.self))
        return tv
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)
        tableView.frame = view.frame
        view.addSubview(self.tableView)
    }
}

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return descriptions.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(PrototypeCell.self), for: indexPath) as! PrototypeCell
        cell.titleLabel.text = "Title #\(indexPath.row)"
        cell.subtitleLabel.text = "Subtitle #\(indexPath.row)"
        cell.descriptionLabel.text = descriptions[indexPath.row]
        return cell
    }
}

class PrototypeCell: UITableViewCell {

    let foregroundView: UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .red
        return v
    }()

    let detailImageView: UIImageView = {
        let iv = UIImageView()
        iv.translatesAutoresizingMaskIntoConstraints = false
        iv.backgroundColor = .gray
        return iv
    }()

    let titleLabel: UILabel = {
        let lbl = UILabel()
        lbl.translatesAutoresizingMaskIntoConstraints = false
        lbl.numberOfLines = 1
        lbl.text = "Title"
        return lbl
    }()

    let subtitleLabel: UILabel = {
        let lbl = UILabel()
        lbl.translatesAutoresizingMaskIntoConstraints = false
        lbl.numberOfLines = 1
        lbl.text = "Subtitile"
        lbl.font = UIFont.systemFont(ofSize: 12)
        return lbl
    }()

    let descriptionLabel: UILabel = {
        let lbl = UILabel()
        lbl.translatesAutoresizingMaskIntoConstraints = false
        lbl.numberOfLines = 0
        lbl.font = UIFont.systemFont(ofSize: 10)
        return lbl
    }()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        selectionStyle = .none

        contentView.addSubview(foregroundView)
        foregroundView.addSubview(detailImageView)
        foregroundView.addSubview(titleLabel)
        foregroundView.addSubview(subtitleLabel)
        foregroundView.addSubview(descriptionLabel)

        NSLayoutConstraint.activate([
                foregroundView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 4),
                foregroundView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -4),
                foregroundView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4),
                foregroundView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 4),

                detailImageView.heightAnchor.constraint(equalToConstant: 64),
                detailImageView.widthAnchor.constraint(equalToConstant: 64),
                detailImageView.topAnchor.constraint(equalTo: foregroundView.topAnchor, constant: 4),
                detailImageView.leadingAnchor.constraint(equalTo: foregroundView.leadingAnchor, constant: 4),

                titleLabel.topAnchor.constraint(equalTo: foregroundView.topAnchor, constant: 4),
                titleLabel.trailingAnchor.constraint(equalTo: foregroundView.trailingAnchor, constant: 4),
                titleLabel.leadingAnchor.constraint(equalTo: detailImageView.trailingAnchor, constant: 4),

                subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 2),
                subtitleLabel.trailingAnchor.constraint(equalTo: foregroundView.trailingAnchor, constant: -4),
                subtitleLabel.leadingAnchor.constraint(equalTo: detailImageView.trailingAnchor, constant: 4),

                descriptionLabel.topAnchor.constraint(equalTo: subtitleLabel.bottomAnchor, constant: 2),
                descriptionLabel.trailingAnchor.constraint(equalTo: foregroundView.trailingAnchor, constant: -4),
                descriptionLabel.bottomAnchor.constraint(equalTo: foregroundView.bottomAnchor, constant: -4),
                descriptionLabel.leadingAnchor.constraint(equalTo: detailImageView.trailingAnchor, constant: 4),
            ])
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

var ctrl = ViewController()
PlaygroundPage.current.liveView = ctrl.view

谢谢大家! 最终解决方案:

    //: Playground - noun: a place where people can play

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let descriptions = [nil, "Curabitur.", "Senectus sit consectetur fermentum nisi suspendisse a condimentum at vestibulum a vestibulum a nostra fermentum molestie sodales molestie id viverra scelerisque consectetur.Penatibus a dictum metus mus commodo a hac morbi parturient parturient convallis ultrices a mi id.Fringilla lobortis suspendisse vestibulum quisque consectetur imperdiet.", "Condimentum adipiscing.", "Cras scelerisque parturient vitae class sollicitudin.", "Integer adipiscing a adipiscing parturient tempus condimentum a interdum facilisis feugiat.", "Donec eros eleifend a ullamcorper class scelerisque nisi nullam nisi sociis ante iaculis pharetra malesuada nibh sit consectetur condimentum.Nibh sollicitudin."]

    lazy var tableView: UITableView = {
        let tv = UITableView()
        tv.dataSource = self
        tv.estimatedRowHeight = 80
        tv.rowHeight = UITableViewAutomaticDimension
        tv.separatorStyle = .none
        tv.register(PrototypeCell.self, forCellReuseIdentifier: NSStringFromClass(PrototypeCell.self))
        return tv
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)
        tableView.frame = view.frame
        view.addSubview(self.tableView)
    }
}

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return descriptions.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(PrototypeCell.self), for: indexPath) as! PrototypeCell
        cell.titleLabel.text = "Title #\(indexPath.row)"
        cell.subtitleLabel.text = "Subtitle #\(indexPath.row)"
        cell.descriptionLabel.text = descriptions[indexPath.row]
        return cell
    }
}

class PrototypeCell: UITableViewCell {

    let foregroundView: UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .red
        return v
    }()

    let detailImageView: UIImageView = {
        let iv = UIImageView()
        iv.translatesAutoresizingMaskIntoConstraints = false
        iv.backgroundColor = .gray
        return iv
    }()

    let titleLabel: UILabel = {
        let lbl = UILabel()
        lbl.translatesAutoresizingMaskIntoConstraints = false
        lbl.numberOfLines = 1
        lbl.text = "Title"
        return lbl
    }()

    let subtitleLabel: UILabel = {
        let lbl = UILabel()
        lbl.translatesAutoresizingMaskIntoConstraints = false
        lbl.numberOfLines = 1
        lbl.text = "Subtitile"
        lbl.font = UIFont.systemFont(ofSize: 12)
        return lbl
    }()

    let descriptionLabel: UILabel = {
        let lbl = UILabel()
        lbl.translatesAutoresizingMaskIntoConstraints = false
        lbl.numberOfLines = 0
        lbl.font = UIFont.systemFont(ofSize: 10)
        return lbl
    }()

    var detailImageViewBottomAnchor: NSLayoutConstraint!

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        detailImageViewBottomAnchor = detailImageView.bottomAnchor.constraint(equalTo: foregroundView.bottomAnchor, constant: -4)
        detailImageViewBottomAnchor.priority = 749
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        selectionStyle = .none

        contentView.addSubview(foregroundView)
        foregroundView.addSubview(detailImageView)
        foregroundView.addSubview(titleLabel)
        foregroundView.addSubview(subtitleLabel)
        foregroundView.addSubview(descriptionLabel)

        NSLayoutConstraint.activate([
                foregroundView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 4),
                foregroundView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -4),
                foregroundView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4),
                foregroundView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 4),

                detailImageView.heightAnchor.constraint(lessThanOrEqualToConstant: 64),
                detailImageView.widthAnchor.constraint(equalToConstant: 64),
                detailImageView.topAnchor.constraint(equalTo: foregroundView.topAnchor, constant: 4),
                detailImageViewBottomAnchor,
                detailImageView.leadingAnchor.constraint(equalTo: foregroundView.leadingAnchor, constant: 4),

                titleLabel.topAnchor.constraint(equalTo: foregroundView.topAnchor, constant: 4),
                titleLabel.trailingAnchor.constraint(equalTo: foregroundView.trailingAnchor, constant: 4),
                titleLabel.leadingAnchor.constraint(equalTo: detailImageView.trailingAnchor, constant: 4),

                subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 2),
                subtitleLabel.trailingAnchor.constraint(equalTo: foregroundView.trailingAnchor, constant: -4),
                subtitleLabel.leadingAnchor.constraint(equalTo: detailImageView.trailingAnchor, constant: 4),

                descriptionLabel.topAnchor.constraint(equalTo: subtitleLabel.bottomAnchor, constant: 2),
                descriptionLabel.trailingAnchor.constraint(equalTo: foregroundView.trailingAnchor, constant: -4),
                descriptionLabel.bottomAnchor.constraint(equalTo: foregroundView.bottomAnchor, constant: -4),
                descriptionLabel.leadingAnchor.constraint(equalTo: detailImageView.trailingAnchor, constant: 4),

            ])
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

var ctrl = ViewController()
PlaygroundPage.current.liveView = ctrl.view

2 个答案:

答案 0 :(得分:0)

在PrototypeCell的layoutSubviews()函数中添加

  if self.view.frame.size.height < 68 {
        detailImageView.heightAnchor.constraint(equalToConstant: self.frame.size.height - 8)
    } else {
    detailImageView.heightAnchor.constraint(equalToConstant: 64)
   }

如果单元格高度小于68,那么imageview高度将是单元格高度 - 8.其中8是imageview(4)的顶部空间+ imageview(4)的底部空间。

答案 1 :(得分:0)

我刚刚找到了适用于我的解决方案。

我已按照this解决方案使其正常运行。 所有你需要为你的观点做。

  1. 让您的身高限制小于或等于为一个值(比如说,40)和优先级默认值(1000)

  2. 绘制一个具有高优先级(750)的底部约束并只提供一个值

  3. 就是这样。

    这就是它的样子。

    enter image description here

    这是身高限制的属性。

    enter image description here

    这是针对底部约束的。

    enter image description here

    这是我的整个布局层次结构(它并不重要,只是为了让您知道可以使用堆栈视图作为文本标签:))

    enter image description here

    这是输出。

    enter image description here