如何将 UITableView 的宽度设置为等于最大单元格数?里面的宽度?

发布于 2025-01-13 17:37:57 字数 252 浏览 2 评论 0原文

我有一个表视图,并使用一个自定义单元格,其中有 3 个 UI 元素作为子视图。我已经制作了 UIelements,它们是根据内容大小缩小的标签。现在我的问题是设置单元格根据其 UIElements 缩小并相对调整表格视图宽度。在此处输入图像描述

I have a table view and I using a custom cell which has 3 UI elements as subviews. I have made my UIelements which are labels to shrink as per there content size. Now my problem is to set cell to shrink as per its UIElements and relatively adjust tableview width.enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

猫七 2025-01-20 17:37:58

一种方法可能是:

  • 创建一个单独的视图,例如名为 ThreeElementView ,它将添加到单元格的内容视图中
  • ,其中所有行都可用,您可以调用 systemLayoutSizeFitting 来获取最大值width
  • 向表视图添加宽度约束(NSLayoutConstraint),
  • 如果表视图的数据发生变化,则调整约束

widthContraint 可以这样设置:

private var widthContraint: NSLayoutConstraint?

widthContraint = tableView.widthAnchor.constraint(equalToConstant: 128)
widthContraint?.isActive = true
if let width = calcWidth() {
    widthContraint?.constant = width
}

您还可以调用最后 3 个使用 tableView.reloadData() 更新表视图之前的行。

假设 data 包含实际的表格数据,宽度计算可能如下所示:

private func calcWidth() -> CGFloat? {
    let prototypeView = ThreeElementView()
    let widths = data.map { row -> CGFloat in
        prototypeView.label1.text = row[0]
        prototypeView.label2.text = row[1]
        prototypeView.label3.text = row[2]
        prototypeView.setNeedsLayout()
        prototypeView.layoutIfNeeded()
        return prototypeView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).width
    }
    return widths.max()
}

因此,对于每一行,您将计算内容的宽度并最终返回最大值。

独立测试

这是上述内容的独立测试。 UI 是通过代码以编程方式构建的,因此结果更容易理解。如果按下按钮,您可以看到表格视图的宽度也通过设置约束来动态调整。

ThreeElementView.swift

import UIKit

class ThreeElementView: UIView {
    
    let label1 = UILabel()
    let label2 = UILabel()
    let label3 = UILabel()
    
    init() {
        super.init(frame: .zero)
        
        label1.backgroundColor = UIColor(red: 84/255, green: 73/255, blue: 75/255, alpha: 1.0)
        label1.textColor = .white
        label2.backgroundColor = UIColor(red: 131/255, green: 151/255, blue: 136/255, alpha: 1.0)
        label2.textColor = .white
        label3.backgroundColor = UIColor(red: 189/255, green: 187/255, blue: 182/255, alpha: 1.0)
        
        label1.translatesAutoresizingMaskIntoConstraints = false
        label2.translatesAutoresizingMaskIntoConstraints = false
        label3.translatesAutoresizingMaskIntoConstraints = false
        
        self.addSubview(label1)
        self.addSubview(label2)
        self.addSubview(label3)
        
        NSLayoutConstraint.activate([
            label1.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            label1.topAnchor.constraint(equalTo: self.topAnchor),
            label1.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            
            label2.leadingAnchor.constraint(equalTo: label1.trailingAnchor),
            label2.topAnchor.constraint(equalTo: self.topAnchor),
            label2.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            
            label3.leadingAnchor.constraint(equalTo: label2.trailingAnchor),
            label3.topAnchor.constraint(equalTo: self.topAnchor),
            label3.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            label3.trailingAnchor.constraint(equalTo: self.trailingAnchor)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

ThreeElementCell.swift

import UIKit

class ThreeElementCell: UITableViewCell {
    
    static let id = "ThreeElementCellId"
    let threeElementView = ThreeElementView()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        threeElementView.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(threeElementView)
        NSLayoutConstraint.activate([
            threeElementView.topAnchor.constraint(equalTo: contentView.topAnchor),
            threeElementView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            threeElementView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            threeElementView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
        ])
    }
    
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

ViewController.swift

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
    private let tableView = UITableView()
    private let addMoreButton = UIButton()
    private var data = [
        ["a", "tiny", "row"],
    ]
    private var widthContraint: NSLayoutConstraint?

    override func viewDidLoad() {
        super.viewDidLoad()
        setupTableView()
        setupButton()
    }
    
    @objc func onAddMore() {
        if data.count < 2 {
            data.append(["a", "little bit", "longer row"])
        } else {
            data.append(["this is", " finally an even longer", "row"])
        }
        if let width = calcWidth() {
            widthContraint?.constant = width
        }
        tableView.reloadData()
    }
    
    // MARK: - UITableViewDataSource
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: ThreeElementCell.id, for: indexPath) as! ThreeElementCell
        let item = data[indexPath.row]
        cell.threeElementView.label1.text = item[0]
        cell.threeElementView.label2.text = item[1]
        cell.threeElementView.label3.text = item[2]        
        return cell
    }
    
    // MARK: - Private
    
    private func setupTableView() {
        tableView.backgroundColor = UIColor(red: 245/255, green: 228/255, blue: 215/255, alpha: 1.0)
        tableView.register(ThreeElementCell.self, forCellReuseIdentifier: ThreeElementCell.id)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(tableView)

        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16.0),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16.0),
        ])
        widthContraint = tableView.widthAnchor.constraint(equalToConstant: 128)
        
        widthContraint?.isActive = true
        if let width = calcWidth() {
            widthContraint?.constant = width
        }
        
        tableView.delegate = self
        tableView.dataSource = self
    }
    
    private func setupButton() {
        addMoreButton.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(addMoreButton)
        NSLayoutConstraint.activate([
            addMoreButton.topAnchor.constraint(equalTo: tableView.bottomAnchor, constant: 32.0),
            addMoreButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            addMoreButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -32.0),
        ])
        addMoreButton.setTitle("Add More Rows", for: .normal)
        addMoreButton.setTitleColor(.blue, for: .normal)
        addMoreButton.addTarget(self, action: #selector(onAddMore), for: .touchUpInside)
    }

    private func calcWidth() -> CGFloat? {
        let prototypeView = ThreeElementView()
        let widths = data.map { row -> CGFloat in
            prototypeView.label1.text = row[0]
            prototypeView.label2.text = row[1]
            prototypeView.label3.text = row[2]
            prototypeView.setNeedsLayout()
            prototypeView.layoutIfNeeded()
            return prototypeView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).width
        }
        return widths.max()
    }
    
}

演示

demo

One way could be to:

  • create a separate view e.g. named ThreeElementView which will be added to the content view of the cell
  • with all rows available you could call systemLayoutSizeFitting to get the maximum width
  • add an width constraint (NSLayoutConstraint) to the table view
  • if the data of the table view changes, adjust the constraint

The widthContraint can be setup like this:

private var widthContraint: NSLayoutConstraint?

widthContraint = tableView.widthAnchor.constraint(equalToConstant: 128)
widthContraint?.isActive = true
if let width = calcWidth() {
    widthContraint?.constant = width
}

You would also call the last 3 lines before updating the table view with tableView.reloadData().

Assuming that data contains the actual table data, the width calculation could look like this:

private func calcWidth() -> CGFloat? {
    let prototypeView = ThreeElementView()
    let widths = data.map { row -> CGFloat in
        prototypeView.label1.text = row[0]
        prototypeView.label2.text = row[1]
        prototypeView.label3.text = row[2]
        prototypeView.setNeedsLayout()
        prototypeView.layoutIfNeeded()
        return prototypeView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).width
    }
    return widths.max()
}

So for each line you would calculate the width of the contents and finally return the maximum value.

Self-Contained Test

Here is a self-contained test of the above. The UI has been built programmatically in code so that the result is easier to follow. If you press the button, you can see that the width of the tableview then also dynamically adjusts just by setting the constraint.

ThreeElementView.swift

import UIKit

class ThreeElementView: UIView {
    
    let label1 = UILabel()
    let label2 = UILabel()
    let label3 = UILabel()
    
    init() {
        super.init(frame: .zero)
        
        label1.backgroundColor = UIColor(red: 84/255, green: 73/255, blue: 75/255, alpha: 1.0)
        label1.textColor = .white
        label2.backgroundColor = UIColor(red: 131/255, green: 151/255, blue: 136/255, alpha: 1.0)
        label2.textColor = .white
        label3.backgroundColor = UIColor(red: 189/255, green: 187/255, blue: 182/255, alpha: 1.0)
        
        label1.translatesAutoresizingMaskIntoConstraints = false
        label2.translatesAutoresizingMaskIntoConstraints = false
        label3.translatesAutoresizingMaskIntoConstraints = false
        
        self.addSubview(label1)
        self.addSubview(label2)
        self.addSubview(label3)
        
        NSLayoutConstraint.activate([
            label1.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            label1.topAnchor.constraint(equalTo: self.topAnchor),
            label1.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            
            label2.leadingAnchor.constraint(equalTo: label1.trailingAnchor),
            label2.topAnchor.constraint(equalTo: self.topAnchor),
            label2.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            
            label3.leadingAnchor.constraint(equalTo: label2.trailingAnchor),
            label3.topAnchor.constraint(equalTo: self.topAnchor),
            label3.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            label3.trailingAnchor.constraint(equalTo: self.trailingAnchor)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

ThreeElementCell.swift

import UIKit

class ThreeElementCell: UITableViewCell {
    
    static let id = "ThreeElementCellId"
    let threeElementView = ThreeElementView()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        threeElementView.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(threeElementView)
        NSLayoutConstraint.activate([
            threeElementView.topAnchor.constraint(equalTo: contentView.topAnchor),
            threeElementView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            threeElementView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            threeElementView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
        ])
    }
    
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

ViewController.swift

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
    private let tableView = UITableView()
    private let addMoreButton = UIButton()
    private var data = [
        ["a", "tiny", "row"],
    ]
    private var widthContraint: NSLayoutConstraint?

    override func viewDidLoad() {
        super.viewDidLoad()
        setupTableView()
        setupButton()
    }
    
    @objc func onAddMore() {
        if data.count < 2 {
            data.append(["a", "little bit", "longer row"])
        } else {
            data.append(["this is", " finally an even longer", "row"])
        }
        if let width = calcWidth() {
            widthContraint?.constant = width
        }
        tableView.reloadData()
    }
    
    // MARK: - UITableViewDataSource
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: ThreeElementCell.id, for: indexPath) as! ThreeElementCell
        let item = data[indexPath.row]
        cell.threeElementView.label1.text = item[0]
        cell.threeElementView.label2.text = item[1]
        cell.threeElementView.label3.text = item[2]        
        return cell
    }
    
    // MARK: - Private
    
    private func setupTableView() {
        tableView.backgroundColor = UIColor(red: 245/255, green: 228/255, blue: 215/255, alpha: 1.0)
        tableView.register(ThreeElementCell.self, forCellReuseIdentifier: ThreeElementCell.id)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(tableView)

        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16.0),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16.0),
        ])
        widthContraint = tableView.widthAnchor.constraint(equalToConstant: 128)
        
        widthContraint?.isActive = true
        if let width = calcWidth() {
            widthContraint?.constant = width
        }
        
        tableView.delegate = self
        tableView.dataSource = self
    }
    
    private func setupButton() {
        addMoreButton.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(addMoreButton)
        NSLayoutConstraint.activate([
            addMoreButton.topAnchor.constraint(equalTo: tableView.bottomAnchor, constant: 32.0),
            addMoreButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            addMoreButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -32.0),
        ])
        addMoreButton.setTitle("Add More Rows", for: .normal)
        addMoreButton.setTitleColor(.blue, for: .normal)
        addMoreButton.addTarget(self, action: #selector(onAddMore), for: .touchUpInside)
    }

    private func calcWidth() -> CGFloat? {
        let prototypeView = ThreeElementView()
        let widths = data.map { row -> CGFloat in
            prototypeView.label1.text = row[0]
            prototypeView.label2.text = row[1]
            prototypeView.label3.text = row[2]
            prototypeView.setNeedsLayout()
            prototypeView.layoutIfNeeded()
            return prototypeView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).width
        }
        return widths.max()
    }
    
}

Demo

demo

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文