我创建了可扩展的UITableViewCell类,它修改了constaint以实现效果。
import UIKit
class ExpandableCell: UITableViewCell {
@IBOutlet weak var img: UIImageView!
@IBOutlet weak var imgHeightConstraint: NSLayoutConstraint!
var isExpanded:Bool = false
{
didSet
{
if !isExpanded {
self.imgHeightConstraint.constant = 0.0
} else {
self.imgHeightConstraint.constant = 128.0
}
}
}
}
查看控制器
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 21
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:ExpandableCell = tableView.dequeueReusableCell(withIdentifier: "ExpandableCell") as! ExpandableCell
cell.img.image = UIImage(named: imgs[indexPath.row])
cell.isExpanded = false
return cell
}
// TableView Delegate methods
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.row)
guard let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell
else { return }
UIView.animate(withDuration: 0.3, animations: {
let offset: CGPoint = self.tableView.contentOffset
tableView.beginUpdates()
cell.isExpanded = !cell.isExpanded
self.tableView.layer.removeAllAnimations()
self.tableView.setContentOffset(offset, animated: false)
tableView.scrollToRow(at: indexPath, at: UITableViewScrollPosition.top, animated: true)
tableView.endUpdates()
})
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell
else { return }
UIView.animate(withDuration: 0.3, animations: {
tableView.beginUpdates()
cell.isExpanded = false
tableView.endUpdates()
})
}
对于少数第一行,一切正常,向下滚动后,单元格表现不正常,似乎滚动到顶部,然后图像消失。
我知道这可能与某些数组中没有存储布尔isExpanded
值以跟踪它有关,但我认为刷新TableView有点不对。
修改
Sulthan 回答给了我很多帮助,但滚动到顶部的问题尤其是在点击最低的单元格时仍然存在。
尝试了这个UITableView scrolls to top when reloading cells with changing cell heights
使用estimatedRowHeight到最接近的值但是在可扩展单元格的情况下它没有解决我的问题。
有人知道如何解决它吗?
答案 0 :(得分:1)
首先将扩展的单元格保存在控制器中:
var expandedRows = Set<Int>()
使用它们:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:ExpandableCell = tableView.dequeueReusableCell(withIdentifier: "ExpandableCell") as! ExpandableCell
cell.img.image = UIImage(named: imgs[indexPath.row])
// this!
cell.isExpanded = self.expandedRows.contains(indexPath.row)
return cell
}
更改展开状态时:
if self.expandedRows.contains(indexPath.row) {
self.expandedRows.remove(indexPath.row)
cell.isExpanded = false
} else {
self.expandedRows.add(indexPath.row)
cell.isExpanded = true
}
当然,还有另一种可能性。由于您的单元格在被选中时会被展开,因此您可以对单元格中的该事件做出反应:
class ExpandableCell : UITableViewCell {
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
self.imgHeightConstraint.constant = selected ? 128.0 : 0.0
}
}
完整的示例代码:
class ExpandableCell : UITableViewCell {
var label: UILabel?
var expandableView: UIView?
var heightConstraint: NSLayoutConstraint?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.initViews()
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.initViews()
}
private func initViews() {
self.contentView.clipsToBounds = true
let label = UILabel()
label.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin]
label.frame = CGRect(x: 0, y: 0, width: self.contentView.frame.size.width, height: 44)
self.label = label
self.contentView.addSubview(label)
let expandableView = UIView()
expandableView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(expandableView)
let horizontalConstraints = NSLayoutConstraint.constraints(
withVisualFormat: "H:|-0-[view]-0-|", options: [], metrics: nil, views: ["view": expandableView]
)
NSLayoutConstraint.activate(horizontalConstraints)
let verticalConstraints = NSLayoutConstraint.constraints(
withVisualFormat: "V:|-44-[view]-0@999-|", options: [], metrics: nil, views: ["view": expandableView]
)
NSLayoutConstraint.activate(verticalConstraints)
let heightConstraint = NSLayoutConstraint(
item: expandableView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 0
)
NSLayoutConstraint.activate([heightConstraint])
self.expandableView = expandableView
self.heightConstraint = heightConstraint
}
var isExpanded:Bool = false {
didSet {
self.heightConstraint?.constant = self.isExpanded ? 128 : 0
}
}
}
class ViewController: UITableViewController {
var expandedRows: Set<Int> = Set()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(ExpandableCell.self, forCellReuseIdentifier: "ExpandableCell")
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.allowsMultipleSelection = false
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 21
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 44.0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ExpandableCell", for: indexPath) as! ExpandableCell
cell.label!.text = "Cell at row: \(indexPath.row)"
cell.isExpanded = expandedRows.contains(indexPath.row)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Selecting: \(indexPath.row)")
self.expandedRows.insert(indexPath.row)
if let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell {
cell.isExpanded = true
}
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
print("Deselecting: \(indexPath.row)")
self.expandedRows.remove(indexPath.row)
if let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell {
cell.isExpanded = false
}
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
}