UIStackView
UITableViewCell
内有contentView
UIStackView
。根据用户互动,我在UIStackView
中添加/删除项目。修改cell
中的项目后,我希望tableView.reloadData()
相应地更新其高度。但是,除非我致电reloadData()
,否则它不会更新它的高度。但是,在cellForRowAtIndexPath
/ willDisplayCell
中调用cell
会变为递归。
根据UIStackView
中的项目,在运行时调整UITableViewAutomaticDimension
高度的正确方法是什么?
我使用cellA
更新问题:
Here是我想要做的简单原型。
我的实际问题是将单元格出列。
在原型中,我有2个可重复使用的单元格和3行。对于第0行和第2行,我将cellB
出列,对于第1行,我将if indexPath.row == 0 {
// dequeue cellA with 2 items in stackView
}
if indexPath.row == 1 {
// dequeue cellB with 25 items in stackView
}
if indexPath.row == 2 {
// dequeue cellA with 8 items in stackView
}
出列。以下是我使用条件的概述。
stackView
但输出是,
第0行包含stackView
中的2个项目 - 预期
第1行包含stackView
中的25个项目 - 预期
第2行包含stackView
中的2个项目 - 意外,第0行已出列
我还尝试删除cellForRowAtIndexPath
中所有已排列的Exit Sub
子视图。但是,这样做会在滚动时闪烁UI。如何设法获得所需的输出?
答案 0 :(得分:2)
尝试使用:https://developer.apple.com/documentation/uikit/uitableview/1614935-reloadrows
重新加载单元格示例代码
这是一个例子。我们在视图控制器中有基本的表视图单元(TableViewCell)。单元格在堆栈视图中有2个标签。我们可以使用折叠/显示方法隐藏或显示第二个标签。
class TableViewCell : UITableViewCell {
@IBOutlet private var stackView: UIStackView!
@IBOutlet private var firstLabel: UILabel!
@IBOutlet private var secondLabel: UILabel!
func collapse() {
secondLabel.isHidden = true
}
func reveal() {
secondLabel.isHidden = false
}
}
class ViewController : UIViewController {
@IBOutlet var tableView: UITableView!
fileprivate var collapsedCells: Set<IndexPath> = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 128
}
@IBAction private func buttonAction(_ sender: Any) {
collapseCell(at: IndexPath(row: 0, section: 0))
}
private func collapseCell(at indexPath: IndexPath) {
if collapsedCells.contains(indexPath) {
collapsedCells.remove(indexPath)
} else {
collapsedCells.insert(indexPath)
}
tableView.reloadRows(at: [indexPath], with: .automatic)
}
}
extension ViewController : UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
if collapsedCells.contains(indexPath) {
cell.collapse()
} else {
cell.reveal()
}
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
}
答案 1 :(得分:1)
我相信问题是 时你是在堆栈视图中添加视图。
通常,当单元格初始化时,应该添加元素。
willDisplay cell:
是处理修改单元格内容属性的地方。
如果您将代码从willDisplay cell:
移至cellForRowAt indexPath:
,您应该会看到很大的差异。
我刚刚对您链接的代码进行了一次更改,现在行根据堆栈视图内容自动调整大小。
修改:查看更新后的代码...问题仍在于您将您的arrangeSubviews添加到错误的位置。然后通过调用reloadData()来复合它。
第二次编辑:忘记在重复使用单元格时处理以前添加的子视图。
更新了代码...将ViewController代码替换为:
//
// ViewController.swift
//
import UIKit
class ViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView()
tableView.estimatedRowHeight = 56
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = UITableViewCell()
if indexPath.row == 0 || indexPath.row == 2 {
cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
if let stackView = cell.viewWithTag(999) as? UIStackView {
let numberOfItemsInStackView = (indexPath.row == 0) ? 2 : 8
let color = (indexPath.row == 0) ? UIColor.gray : UIColor.black
// cells are reused, so clear out any previously added subviews...
// but leave the first view that is part of the cell prototype
while stackView.arrangedSubviews.count > 1 {
stackView.arrangedSubviews[1].removeFromSuperview()
}
// use "i" so we can count
for i in 1...numberOfItemsInStackView {
// use label instead of view so we can number them for testing
let newView = UILabel()
newView.text = "\(i)"
newView.textColor = .yellow
// add a border, so we can see the frames
newView.layer.borderWidth = 1.0
newView.layer.borderColor = UIColor.red.cgColor
newView.backgroundColor = color
let heightConstraint = newView.heightAnchor.constraint(equalToConstant: 54)
heightConstraint.priority = 999
heightConstraint.isActive = true
stackView.addArrangedSubview(newView)
}
}
}
if indexPath.row == 1 {
cell = tableView.dequeueReusableCell(withIdentifier: "lastCell")!
if let stackView = cell.viewWithTag(999) as? UIStackView {
let numberOfItemsInStackView = 25
// cells are reused, so clear out any previously added subviews...
// but leave the first view that is part of the cell prototype
while stackView.arrangedSubviews.count > 1 {
stackView.arrangedSubviews[1].removeFromSuperview()
}
// use "i" so we can count
for i in 1...numberOfItemsInStackView {
// use label instead of view so we can number them for testing
let newView = UILabel()
newView.text = "\(i)"
newView.textColor = .yellow
// add a border, so we can see the frames
newView.layer.borderWidth = 1.0
newView.layer.borderColor = UIColor.red.cgColor
newView.backgroundColor = UIColor.darkGray
let heightConstraint = newView.heightAnchor.constraint(equalToConstant: 32)
heightConstraint.priority = 999
heightConstraint.isActive = true
stackView.addArrangedSubview(newView)
}
}
}
return cell
}
// override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// if cell.reuseIdentifier == "cell" {
// if let stackView = cell.viewWithTag(999) as? UIStackView {
// let numberOfItemsInStackView = (indexPath.row == 0) ? 2 : 8
// let color = (indexPath.row == 0) ? UIColor.gray : UIColor.black
// guard stackView.arrangedSubviews.count == 1 else { return }
// for _ in 1...numberOfItemsInStackView {
// let newView = UIView()
// newView.backgroundColor = color
// let heightConstraint = newView.heightAnchor.constraint(equalToConstant: 54)
// heightConstraint.priority = 999
// heightConstraint.isActive = true
// stackView.addArrangedSubview(newView)
// }
// tableView.reloadData()
// }
// }
//
// if cell.reuseIdentifier == "lastCell" {
// if let stackView = cell.viewWithTag(999) as? UIStackView {
// let numberOfItemsInStackView = 25
// guard stackView.arrangedSubviews.count == 1 else { return }
// for _ in 1...numberOfItemsInStackView {
// let newView = UIView()
// newView.backgroundColor = UIColor.darkGray
// let heightConstraint = newView.heightAnchor.constraint(equalToConstant: 32)
// heightConstraint.priority = 999
// heightConstraint.isActive = true
// stackView.addArrangedSubview(newView)
// }
// tableView.reloadData()
// }
// }
// }
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
}