来自服务器的 UITableViewCell 可变内容基于数据
UITableViewCell changeable content based data coming from server
我正在努力解决与 UITableViewCell
有关的这个问题。我有一个名为 ApplicantMessageCell
的子类 UITableViewCell
,它有一些子视图、标签、图像视图等。它的顶部不依赖于状态。只是获取数据,更改标签文本和 imageView 的图像。
然而,对于底部部分,对于进入的每个状态,我都有 UIView
的 3 个完全不同的子类。我需要在 ApplicationMessageCell
的底部显示相关的 UIView
子类。但是我找不到办法。
- 当然,我可以为每个州创建不同的
UITableViewCell
子类,但我不想走那条路,因为这只是一个案例,我还有更多。
- 我试图创建一个
UIView
的子类,它在调整自身大小时表现得像 UILabel
。我做不到。
- 最后,我知道添加关于每个状态的每个
UIView
子类并显式显示 one/hiding 其余部分可以解决它,但我相信有更好的方法可以实现这一点。
我没有分享任何代码,因为我认为这更像是一个理论问题,但如果有人要求,我当然会分享。
提前致谢。
这是一个简单的例子...
单元格 class 有两个标签、一个堆栈视图和 3 个高度不同的视图(红色、绿色、蓝色)以用作“显示或不显示”视图:
- 第一个标签被限制在顶部
- 第二个标签被限制在第一个标签的底部
- 堆栈视图被限制在第二个标签的底部并且被限制在单元格的底部(当然是contentView)
然后将三个不同高度的视图添加到堆栈视图中。想必,你不同视图的子视图的约束会决定它们各自的高度。对于此示例,它们设置为 40、80 和 160。
查看以下代码中的注释 - 它应该是不言自明的:
class ApplicantMessageCell: UITableViewCell {
let titleLabel = UILabel()
let subLabel = UILabel()
let stackView = UIStackView()
let viewA = UIView()
let viewB = UIView()
let viewC = UIView()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
[titleLabel, subLabel, stackView].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(v)
}
let g = contentView.layoutMarginsGuide
NSLayoutConstraint.activate([
// constrain titleLabel at top
titleLabel.topAnchor.constraint(equalTo: g.topAnchor),
titleLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor),
titleLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor),
// subLabel 8-pts below titleLabel
subLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8.0),
subLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor),
subLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor),
// stackView 8-pts below subLabel
stackView.topAnchor.constraint(equalTo: subLabel.bottomAnchor, constant: 8.0),
stackView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
])
// constrain stackView bottom to bottom
// this will avoid auto-layout complaints while the cells are configured
let c = stackView.bottomAnchor.constraint(equalTo: g.bottomAnchor)
c.priority = .defaultHigh
c.isActive = true
// UI element properties
stackView.axis = .vertical
stackView.spacing = 8
titleLabel.backgroundColor = .yellow
subLabel.backgroundColor = .cyan
viewA.backgroundColor = .red
viewB.backgroundColor = .green
viewC.backgroundColor = .blue
// you'll be filling the views with something to determine their heights
// but here we'll just set them to 40, 80 and 160 pts
for (v, h) in zip([viewA, viewB, viewC], [40.0, 80.0, 160.0]) {
stackView.addArrangedSubview(v)
v.heightAnchor.constraint(equalToConstant: CGFloat(h)).isActive = true
}
}
func fillData(_ top: String, sub: String, showViews: [Bool]) -> Void {
titleLabel.text = top
subLabel.text = sub
// hide views as defined in showViews array
for (v, b) in zip(stackView.arrangedSubviews, showViews) {
v.isHidden = !b
}
}
}
struct ApplicationStruct {
var title: String = ""
var subTitle: String = ""
var showViews: [Bool] = [true, true, true]
}
class FarukTableViewController: UITableViewController {
var theData: [ApplicationStruct] = []
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<20 {
// cycle through views 1, 2, 3
let b1 = i % 3 == 0
let b2 = i % 3 == 1
let b3 = i % 3 == 2
let a = [b1, b2, b3]
let d = ApplicationStruct(title: "Title \(i)", subTitle: "", showViews: a)
theData.append(d)
}
// just to test, set more than one view visible in a couple cells
theData[11].showViews = [true, false, true] // red and blue
theData[12].showViews = [false, true, true] // green and blue
theData[13].showViews = [true, true, false] // red and green
theData[14].showViews = [true, true, true] // all three
tableView.register(ApplicantMessageCell.self, forCellReuseIdentifier: "cell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return theData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let c = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ApplicantMessageCell
let d = theData[indexPath.row]
let subStr = "showViews: " + d.showViews.description
c.fillData(d.title, sub: subStr, showViews: d.showViews)
return c
}
}
第一行显示“ViewType1”的结果,第二行显示“ViewType2”,第三行显示“ViewType3”...然后行循环,直到我们点击设置了几行的“Title 11”行显示不止一种“子视图类型”:
我正在努力解决与 UITableViewCell
有关的这个问题。我有一个名为 ApplicantMessageCell
的子类 UITableViewCell
,它有一些子视图、标签、图像视图等。它的顶部不依赖于状态。只是获取数据,更改标签文本和 imageView 的图像。
然而,对于底部部分,对于进入的每个状态,我都有 UIView
的 3 个完全不同的子类。我需要在 ApplicationMessageCell
的底部显示相关的 UIView
子类。但是我找不到办法。
- 当然,我可以为每个州创建不同的
UITableViewCell
子类,但我不想走那条路,因为这只是一个案例,我还有更多。 - 我试图创建一个
UIView
的子类,它在调整自身大小时表现得像UILabel
。我做不到。 - 最后,我知道添加关于每个状态的每个
UIView
子类并显式显示 one/hiding 其余部分可以解决它,但我相信有更好的方法可以实现这一点。
我没有分享任何代码,因为我认为这更像是一个理论问题,但如果有人要求,我当然会分享。
提前致谢。
这是一个简单的例子...
单元格 class 有两个标签、一个堆栈视图和 3 个高度不同的视图(红色、绿色、蓝色)以用作“显示或不显示”视图:
- 第一个标签被限制在顶部
- 第二个标签被限制在第一个标签的底部
- 堆栈视图被限制在第二个标签的底部并且被限制在单元格的底部(当然是contentView)
然后将三个不同高度的视图添加到堆栈视图中。想必,你不同视图的子视图的约束会决定它们各自的高度。对于此示例,它们设置为 40、80 和 160。
查看以下代码中的注释 - 它应该是不言自明的:
class ApplicantMessageCell: UITableViewCell {
let titleLabel = UILabel()
let subLabel = UILabel()
let stackView = UIStackView()
let viewA = UIView()
let viewB = UIView()
let viewC = UIView()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
[titleLabel, subLabel, stackView].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(v)
}
let g = contentView.layoutMarginsGuide
NSLayoutConstraint.activate([
// constrain titleLabel at top
titleLabel.topAnchor.constraint(equalTo: g.topAnchor),
titleLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor),
titleLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor),
// subLabel 8-pts below titleLabel
subLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8.0),
subLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor),
subLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor),
// stackView 8-pts below subLabel
stackView.topAnchor.constraint(equalTo: subLabel.bottomAnchor, constant: 8.0),
stackView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
])
// constrain stackView bottom to bottom
// this will avoid auto-layout complaints while the cells are configured
let c = stackView.bottomAnchor.constraint(equalTo: g.bottomAnchor)
c.priority = .defaultHigh
c.isActive = true
// UI element properties
stackView.axis = .vertical
stackView.spacing = 8
titleLabel.backgroundColor = .yellow
subLabel.backgroundColor = .cyan
viewA.backgroundColor = .red
viewB.backgroundColor = .green
viewC.backgroundColor = .blue
// you'll be filling the views with something to determine their heights
// but here we'll just set them to 40, 80 and 160 pts
for (v, h) in zip([viewA, viewB, viewC], [40.0, 80.0, 160.0]) {
stackView.addArrangedSubview(v)
v.heightAnchor.constraint(equalToConstant: CGFloat(h)).isActive = true
}
}
func fillData(_ top: String, sub: String, showViews: [Bool]) -> Void {
titleLabel.text = top
subLabel.text = sub
// hide views as defined in showViews array
for (v, b) in zip(stackView.arrangedSubviews, showViews) {
v.isHidden = !b
}
}
}
struct ApplicationStruct {
var title: String = ""
var subTitle: String = ""
var showViews: [Bool] = [true, true, true]
}
class FarukTableViewController: UITableViewController {
var theData: [ApplicationStruct] = []
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<20 {
// cycle through views 1, 2, 3
let b1 = i % 3 == 0
let b2 = i % 3 == 1
let b3 = i % 3 == 2
let a = [b1, b2, b3]
let d = ApplicationStruct(title: "Title \(i)", subTitle: "", showViews: a)
theData.append(d)
}
// just to test, set more than one view visible in a couple cells
theData[11].showViews = [true, false, true] // red and blue
theData[12].showViews = [false, true, true] // green and blue
theData[13].showViews = [true, true, false] // red and green
theData[14].showViews = [true, true, true] // all three
tableView.register(ApplicantMessageCell.self, forCellReuseIdentifier: "cell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return theData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let c = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ApplicantMessageCell
let d = theData[indexPath.row]
let subStr = "showViews: " + d.showViews.description
c.fillData(d.title, sub: subStr, showViews: d.showViews)
return c
}
}
第一行显示“ViewType1”的结果,第二行显示“ViewType2”,第三行显示“ViewType3”...然后行循环,直到我们点击设置了几行的“Title 11”行显示不止一种“子视图类型”: