如何解决深层 tableView 中的自动高度问题?
Posted
技术标签:
【中文标题】如何解决深层 tableView 中的自动高度问题?【英文标题】:how to fix auto height problem in deep level tableView? 【发布时间】:2019-09-10 08:49:06 【问题描述】:我正在创建深层 tableView(主 tableView 有两个单元格,它们也有 tableViews,它们也有其他 tableViews)
tableViews 和单元格的数量是有限的(这意味着我不需要递归)
对于 rowHeights,我使用的是 UITableView.automaticDimension,但它不能正常工作。
这是故事板的截图:
https://imgur.com/a/2tEwwZ9
这是一个结果:
https://imgur.com/a/XLFiLKh
类 TipsCountriesTableViewCell: UITableViewCell
@IBOutlet weak var tipsCountriesTableView: TipsCountriesTableView!
@IBOutlet weak var tipsCountriesHeightConstraint: NSLayoutConstraint!
override func awakeFromNib()
tipsCountriesTableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?)
if let obj = object as? UITableView
if obj == tipsCountriesTableView && keyPath == "contentSize"
if let newSize = change?[NSKeyValueChangeKey.newKey] as? CGSize
tipsCountriesHeightConstraint.constant = tipsCountriesTableView.contentSize.height
deinit
self.tipsCountriesTableView.removeObserver(self, forKeyPath: "contentSize")
类 TipsCitiesTableViewCell: UITableViewCell
@IBOutlet weak var tipsCitiesTableView: TipsCitiesTableView!
@IBOutlet weak var tipsCitiesHeightConstraint: NSLayoutConstraint!
override func awakeFromNib()
tipsCitiesTableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?)
if let obj = object as? UITableView
if obj == tipsCitiesTableView && keyPath == "contentSize"
if let newSize = change?[NSKeyValueChangeKey.newKey] as? CGSize
tipsCitiesHeightConstraint.constant = tipsCitiesTableView.contentSize.height
deinit
self.tipsCitiesTableView.removeObserver(self, forKeyPath: "contentSize")
类 TipsTableViewCell: UITableViewCell
@IBOutlet weak var tipsTableView: TipsTableView!
@IBOutlet weak var tipsTableViewHeightConstraint: NSLayoutConstraint!
override func awakeFromNib()
tipsTableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?)
if let obj = object as? UITableView
if obj == tipsTableView && keyPath == "contentSize"
if let newSize = change?[NSKeyValueChangeKey.newKey] as? CGSize
tipsTableViewHeightConstraint.constant = tipsTableView.contentSize.height
deinit
self.tipsTableView.removeObserver(self, forKeyPath: "contentSize")
class TipsContinentsTableView: UITableView, UITableViewDataSource, UITableViewDelegate
var data: [ItineraryTipsContinent]?
required init?(coder aDecoder: NSCoder)
super.init(coder: aDecoder)
dataSource = self
delegate = self
func numberOfSections(in tableView: UITableView) -> Int
return data?.count ?? 0
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return 2
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
guard indexPath.row == 0 else
let cell = tableView.dequeueReusableCell(withIdentifier: "TipsCountriesTableViewCell") as! TipsCountriesTableViewCell
cell.tipsCountriesTableView.data = data?[indexPath.section].countries
return cell
let cell = tableView.dequeueReusableCell(withIdentifier: "TipsTableViewCell") as! TipsTableViewCell
cell.tipsTableView.data = data?[indexPath.section].tips
return cell
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
let sectionHeaderView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "TravelInfoTableViewSectionHeaderView") as! TravelInfoTableViewSectionHeaderView
guard let data = data else
return sectionHeaderView
sectionHeaderView.cityLabel.text = data[section].name
sectionHeaderView.arrowImageView.isHidden = false
return sectionHeaderView
class TipsCountriesTableView: UITableView, UITableViewDataSource, UITableViewDelegate
private let reuseIdentifier = "TravelInfoTableViewSectionHeaderView"
var data: [ItineraryTipsCountry]?
required init?(coder aDecoder: NSCoder)
super.init(coder: aDecoder)
let nib = UINib(nibName: reuseIdentifier, bundle: nil)
register(nib, forHeaderFooterViewReuseIdentifier: reuseIdentifier)
sectionHeaderHeight = 50.0
rowHeight = UITableView.automaticDimension
dataSource = self
delegate = self
func numberOfSections(in tableView: UITableView) -> Int
return data?.count ?? 0
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return 2
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
guard indexPath.row == 0 else
let cell = tableView.dequeueReusableCell(withIdentifier: "TipsCitiesTableViewCell") as! TipsCitiesTableViewCell
cell.tipsCitiesTableView.data = data?[indexPath.section].cities
return cell
let cell = tableView.dequeueReusableCell(withIdentifier: "TipsTableViewCell") as! TipsTableViewCell
cell.tipsTableView.data = data?[indexPath.section].tips
return cell
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
let sectionHeaderView = tableView.dequeueReusableHeaderFooterView(withIdentifier: reuseIdentifier) as! TravelInfoTableViewSectionHeaderView
guard let data = data else
return sectionHeaderView
sectionHeaderView.cityLabel.text = data[section].name
sectionHeaderView.arrowImageView.isHidden = false
return sectionHeaderView
class TipsCitiesTableView: UITableView, UITableViewDataSource, UITableViewDelegate
private let reuseIdentifier = "TravelInfoTableViewSectionHeaderView"
var data: [ItineraryTipsCity]?
required init?(coder aDecoder: NSCoder)
super.init(coder: aDecoder)
let nib = UINib(nibName: reuseIdentifier, bundle: nil)
register(nib, forHeaderFooterViewReuseIdentifier: reuseIdentifier)
sectionHeaderHeight = 50.0
rowHeight = UITableView.automaticDimension
dataSource = self
delegate = self
func numberOfSections(in tableView: UITableView) -> Int
return data?.count ?? 0
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return 1
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "TipsTableViewCell") as! TipsTableViewCell
cell.tipsTableView.data = data?[indexPath.section].tips
return cell
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
let sectionHeaderView = tableView.dequeueReusableHeaderFooterView(withIdentifier: reuseIdentifier) as! TravelInfoTableViewSectionHeaderView
guard let data = data else
return sectionHeaderView
sectionHeaderView.cityLabel.text = data[section].name
sectionHeaderView.arrowImageView.isHidden = false
return sectionHeaderView
class TipsTableView: UITableView, UITableViewDataSource, UITableViewDelegate
private let reuseIdentifier = "TravelInfoTableViewSectionHeaderView"
var data: [ItineraryTip]?
required init?(coder aDecoder: NSCoder)
super.init(coder: aDecoder)
let nib = UINib(nibName: reuseIdentifier, bundle: nil)
register(nib, forHeaderFooterViewReuseIdentifier: reuseIdentifier)
rowHeight = UITableView.automaticDimension
dataSource = self
delegate = self
func numberOfSections(in tableView: UITableView) -> Int
return data?.count ?? 0
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return 1
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
cell.textLabel?.text = data?[indexPath.row].text
cell.textLabel?.font = UIFont.poppinsFont(ofSize: 12.0)
cell.textLabel?.numberOfLines = 0
return cell
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
let sectionHeaderView = tableView.dequeueReusableHeaderFooterView(withIdentifier: reuseIdentifier) as! TravelInfoTableViewSectionHeaderView
guard let data = data else
return sectionHeaderView
sectionHeaderView.cityLabel.alpha = 0.48
sectionHeaderView.cityLabel.font = UIFont.poppinsFont(ofSize: 13.0)
sectionHeaderView.cityLabel.text = data[section].title
sectionHeaderView.arrowImageView.isHidden = false
return sectionHeaderView
【问题讨论】:
Self sizing tableview inside self sizing tableview cell的可能重复 【参考方案1】:您必须将恒定高度设置为内部UITableView
。为 tableView 的“contentSize”添加观察者。当内容大小发生变化时,您会收到通知。所以你可以在这里设置tipsCountriesHeightConstraint
。
在TipsCountriesTableViewCell
类的awakeFromNib
中添加观察者,如下所示,
tipsCountriesTableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
观察值如下,
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
if let obj = object as? UITableView
if obj == self.tipsCountriesTableView && keyPath == "contentSize"
if let newSize = change?[NSKeyValueChangeKey.newKey] as? CGSize
tipsCountriesHeightConstraint.constant = tipsCountriesTableView.contentSize.height
删除deinit
中的观察者
deinit
self.tipsCountriesTableView.removeObserver(self, forKeyPath: "contentSize")
TipsCountriesTableViewCell
项目必须具有顶部、底部约束。
【讨论】:
感谢@Komal Goyani 的快速响应。我已经向所有单元格添加了观察者,它看起来更好,但仍然缺少一些单元格.. 这是结果 imgur.com/a/GwFmuAU 意思是,不能向下滚动? @BekaGelashvili @Komai Goyani 是的 如果将主 tableView 设置为恒定高度,则需要将该主 tableView 放在滚动视图中。 @BekaGelashvili @komai Goyani 只有主表是可滚动的【参考方案2】:您需要通过类似这样的方式计算*** UItableView 单元格高度的大小,
var size = CGSize()
let cell = YourUITableViewCell()
cell.textLabel?.text = data?[indexPath.row].text
let fitting = CGSize(width: cell.frame.size.width, height: 1)
size = cell.contentView.systemLayoutSizeFitting(fitting,
withHorizontalFittingPriority: .required,
verticalFittingPriority: UILayoutPriority(1))
return size.height
如果 UILabel 是自定义的,则需要设置 UILabel 的底部约束以低于 1000 的优先级查看。
【讨论】:
以上是关于如何解决深层 tableView 中的自动高度问题?的主要内容,如果未能解决你的问题,请参考以下文章
TextView的自动高度,在tableView的单元格中使用autolayout
使用 swift 在不使用自动尺寸的情况下获取 tableView 中动态文本视图的高度