当前位置: 首页 > 知识库问答 >
问题:

Swift 4.2 TableViewCell动态高度编程

龚睿
2023-03-14

这不是重复的问题,因为这个问题没有真正的解决方案

我尝试使用约束通过其内容实现< code>UITableViewcell动态高度,但得到布局警告:

将尝试通过破坏约束来恢复

在 UIView 中创建一个符号断点对于不满意的约束,以便在调试器中捕获此内容。UI视图上列出的基于 UI 的基于 UI 的布局调试类别中的方法也可能有所帮助。2019-03-15 12:27:52.085475 0400 表细胞动态高[31984:1295380] [布局约束] 无法同时满足约束。以下列表中可能至少有一个约束是您不想要的约束。试试这个:(1)看看每个约束,并尝试找出你不期望的;(2)找到添加不需要的约束或约束的代码并修复它。( "", "", "", "" )

我检查了一些线程:动态表视图单元格高度

UITableView单元格的动态高度问题(Swift)

Swift 3-自定义TableViewCell动态高度-以编程方式

什么是正确的解决方案,我错过了什么?

视图控制器:

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    lazy var tableView: UITableView = {
        let table = UITableView()
        table.backgroundColor = .white
        table.translatesAutoresizingMaskIntoConstraints = false
        table.register(TableViewCell.self, forCellReuseIdentifier: "cellId")
        table.dataSource = self
        table.delegate = self
        return table
    }()


    let arr:[Int:UIColor] = [345: UIColor.random, 422: .random, 23: .random, 344: .random,200: .random,140: .random]

    var pickerDataVisitLocation = [203: "Home", 204: "Hospital", 205: "Other"]

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .red

        self.view.addSubview(tableView)
//
        tableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        tableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
        tableView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
        tableView.tableFooterView = UIView()
    }
}

extension ViewController {

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return arr.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! TableViewCell
        let value:UIColor = Array(arr)[indexPath.row].value
        let key = Array(arr)[indexPath.row].key

        cell.setupViews(he: CGFloat(key), color: value)
        return cell
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }
}

extension UIColor {
    static var random: UIColor {
        return UIColor(red: .random(in: 0...1),
                       green: .random(in: 0...1),
                       blue: .random(in: 0...1),
                       alpha: 1.0)
    }
}

表格视图单元格:

    import UIKit

    class TableViewCell: UITableViewCell {


        override func awakeFromNib() {
            super.awakeFromNib()


        }

        override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)


        }

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

        func setupViews(he:CGFloat, color:UIColor) {

            let v:UIView = UIView()
            v.translatesAutoresizingMaskIntoConstraints = false
            self.addSubview(v)

            v.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
            v.backgroundColor = color
            v.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
            v.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
            v.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
            v.heightAnchor.constraint(equalToConstant: he).isActive = true
            #warning("here is constraint error conflict with bottomAnchor and heightAnchor, need correct solution")
        }

    }

共有3个答案

马野
2023-03-14

我也有同样的问题,但原因不同,我想和你分享一下。

我只是重写布局子视图() 方法来添加我的自定义布局。

但是我没有在初始化程序中调用layoutIfNeed()方法来激活它们,而是布局仅在单元格出列并重用时才被激活。

如果您遇到同样的问题,这是我的代码供参考:

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)

    contentView.addSubviews(containerView)
    containerView.addSubviews(titleLabel, subtitleLabel, activteSwitch)

    layoutIfNeeded() // Required to triger the overriden layoutSubviews() upon initialization
}

// However, I shouldn't override this method or add any constraints here
override func layoutSubviews() {
    let margin: CGFloat = 8

    containerView.snapToEdges()
    NSLayoutConstraint.activate([
        activteSwitch.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -margin),
        activteSwitch.centerYAnchor.constraint(equalTo: containerView.centerYAnchor),

        titleLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: margin),
        titleLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: margin),
        titleLabel.trailingAnchor.constraint(equalTo: activteSwitch.leadingAnchor, constant: -margin),

        subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: margin),
        subtitleLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: margin),
        subtitleLabel.trailingAnchor.constraint(equalTo: activteSwitch.leadingAnchor, constant: -margin),
        subtitleLabel.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -margin)

    ])
}
斜博超
2023-03-14

在您的情况下,高度在dataSourcearr中可用,因此您不需要:

  1. 高度约束
  2. 索引路径处行的估计高度

您所需要的只是返回实际的高度对于RowAtIndexPath,但首先你的数据arr:[Int:UIColor]是一个字典,我不会依赖它的顺序,让我们把它改成一个元组数组

var dataSource: [(height: CGFloat, color: UIColor)] = [
    (345, .random),
    (422, .random),
    (23, .random),
    (344, .random),
    (200, .random),
    (140, .random)
]

现在使用以下UITableView委托/DataSource方法:

extension ViewController: UITableViewDataSource, UITableViewDelegate {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.dataSource.count
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return dataSource[indexPath.row].height
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! TableViewCell
        cell.setupViews(color: dataSource[indexPath.row].color)
        return cell
    }

}

由于您不需要高度约束,我从setupViews方法中删除了he参数

逑何平
2023-03-14

你做错了几件事...

首先,单元格被重用(因此是dequeueReusableCell),但每次重用单元格时,setupViews()function都会添加一个新的子视图。

这意味着当你滚动,单元格被重复使用时,你最终会得到2个、3个、4个……十几个子视图,所有这些都有相互冲突的约束。

将您的< code>addSubview()移动到单元格中的一个公共初始化函数中,这样该视图只需创建和添加一次。

这也是你应该设置约束的地方。

要在设计应用程序时更改子视图的高度,您需要更改子视图高度约束上的

这是您修改后的代码。我在代码中添加了足够多的注释,应该很清楚:

class HattoriTableViewCell: UITableViewCell {

    // the view to add as a subview
    let myView: UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    // the constraint we'll use for myView's height
    var myViewHeightConstraint: NSLayoutConstraint!

    override func awakeFromNib() {
        super.awakeFromNib()
        commonInit()
    }

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        commonInit()
    }

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

    func commonInit() -> Void {

        // add the subview
        self.addSubview(myView)

        // constrain it to all 4 sides
        myView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
        myView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
        myView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        myView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true

        // create the height constraint
        myViewHeightConstraint = myView.heightAnchor.constraint(equalToConstant: 1)

        // needs Priority less-than 1000 (default) to avoid breaking constraints
        myViewHeightConstraint.priority = UILayoutPriority.init(999)

        // activate it
        myViewHeightConstraint.isActive = true

    }

    func setupViews(he:CGFloat, color:UIColor) {

        // set myView's background color
        myView.backgroundColor = color

        // change myView's height constraint constant
        myViewHeightConstraint.constant = he

    }

}

class HattoriViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    lazy var tableView: UITableView = {
        let table = UITableView()
        table.backgroundColor = .white
        table.translatesAutoresizingMaskIntoConstraints = false
        table.register(HattoriTableViewCell.self, forCellReuseIdentifier: "cellId")
        table.dataSource = self
        table.delegate = self
        return table
    }()


    let arr:[Int:UIColor] = [345: UIColor.random, 422: .random, 23: .random, 344: .random,200: .random,140: .random]

    var pickerDataVisitLocation = [203: "Home", 204: "Hospital", 205: "Other"]

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .red

        self.view.addSubview(tableView)
        //
        tableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        tableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
        tableView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
        tableView.tableFooterView = UIView()

        // use a reasonable value -- such as the average of what you expect (if known)
        tableView.estimatedRowHeight = 200
    }
}

extension HattoriViewController {

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return arr.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! HattoriTableViewCell

        let value:UIColor = Array(arr)[indexPath.row].value
        let key = Array(arr)[indexPath.row].key

        cell.setupViews(he: CGFloat(key), color: value)

        return cell
    }

    // NOT NEEDED
//  func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//      return UITableView.automaticDimension
//  }
//
//  func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
//      return UITableView.automaticDimension
//  }

}

extension UIColor {
    static var random: UIColor {
        return UIColor(red: .random(in: 0...1),
                       green: .random(in: 0...1),
                       blue: .random(in: 0...1),
                       alpha: 1.0)
    }
}

 类似资料:
  • 我的treeview是折叠的,当我加载它,所以它是大约100x150像素大。当它展开时,我希望treeview显示所有展开的节点。 为了做到这一点,窗体需要随着treeview变大而变大,对吗?我是VB.NET的新手,我试图在treeview中找到一个“growonly”属性,但我找不到一个...有人这样做过吗?

  • 问题内容: 在Web应用程序中,我的页面包含一个DIV,该DIV的自动宽度取决于浏览器窗口的宽度。 我需要该对象的自动高度。DIV从顶部屏幕开始约300像素,其高度应使其延伸到浏览器屏幕的底部。我有一个容器DIV的最大高度,所以div的最小高度必须是最小。我相信我可以将其限制在CSS中,并使用Javascript处理DIV的大小。 我的JavaScript不够理想。我可以编写一个简单的脚本来为我做

  • 我想用和JasperSoft Studio6.5生成一个pdf文件。 在我的文件中,我有两个级别的子报告。 我对这份报告的布局有更多的困难。此报表包含(1°子报表)一个动态文件列表(带有描述字段,在某些情况下非常冗长)。 “说明”字段 第二个子报告中所列行的编号 如果2°子报告比第一个报告高,我有一个问题,如果我有一个页面改变。因此,如果第一个子报告高于第二个子报告,则第二个子报告不会跟随第一个子

  • DynamicHeights是一个动态表格元素高度(动态TableViewCell)的例子。实际应用场景在iOS开发中会经常遇到不规律的TableViewCell,往往需要根据内容的多少而动态调整这些Cell的大小。在http://www.cimgf.com/2009/09/23/uitableviewcell-dynamic-height/ 中,有详细的解说开发的流程以及这么处理的原因。里面的大

  • 问题内容: 我有一个表格视图,其中包含一个webView的单元格,我希望该单元格的高度与该webView的高度相匹配。 这是我使用的代码: 结果是这样的:https : //postimg.cc/image/8qew1lqjj/ 该webView是正确的高度,但单元格不是,如何解决此问题? 问题答案: TableView会自动调整单元格的大小,您只需要实现委托方法即可。 是的,您最初并不知道Web

  • 本文向大家介绍js style动态设置table高度,包括了js style动态设置table高度的使用技巧和注意事项,需要的朋友参考一下 直接在table标签中设置下不就行了吗?这是静态的,如果要动态设置你会吗?