[英]Self sizing tableview inside self sizing tableview cell
Let's say I have hierarchy like this: 假设我有这样的层次结构:
*TableViewCell
**TableView
***TableViewCell
and all of them should be resizable. 所有这些都应调整大小。 Did someone face this kind of problem?
有人遇到过这种问题吗? In past I've used many workarounds like
systemLayoutSizeFitting
or precalculation of height in heightForRowAt
, but it always breaks some constraints, because TableViewCell
has height constraint equal to estimated row height and there appear some kinds of magic behavior. 过去,我使用过许多变通方法,例如
systemLayoutSizeFitting
或heightForRowAt
的height的预先计算,但它总是会打破一些约束,因为TableViewCell
高度约束等于估算的行高,并且会出现某种魔术行为。 Any ways to make this live? 有什么办法可以使它成为现实?
Current workaround: 当前解决方法:
class SportCenterReviewsTableCell: UITableViewCell, MVVMView {
var tableView: SelfSizedTableView = {
let view = SelfSizedTableView(frame: .zero)
view.clipsToBounds = true
view.tableFooterView = UIView()
view.separatorStyle = .none
view.isScrollEnabled = false
view.showsVerticalScrollIndicator = false
view.estimatedRowHeight = 0
if #available(iOS 11.0, *) {
view.contentInsetAdjustmentBehavior = .never
} else {
// Fallback on earlier versions
}
return view
}()
private func markup() {
contentView.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
tableView.register(ReviewsTableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.snp.makeConstraints() { make in
make.top.equalTo(seeAllButton.snp.bottom).offset(12)
make.left.equalTo(contentView.snp.left)
make.right.equalTo(contentView.snp.right)
make.bottom.lessThanOrEqualTo(contentView.snp.bottom)
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ReviewsTableViewCell
cell.viewModel = viewModel.cellViewModels[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! ReviewsTableViewCell
cell.viewModel = viewModel.cellViewModels[indexPath.row]
cell.setNeedsLayout()
cell.layoutIfNeeded()
let size = cell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize, withHorizontalFittingPriority: .defaultHigh, verticalFittingPriority: .defaultLow)
return size.height
}
}
Self sizing tableView class: 自定义tableView类:
class SelfSizedTableView: UITableView {
override func reloadData() {
super.reloadData()
self.invalidateIntrinsicContentSize()
self.layoutIfNeeded()
}
override var intrinsicContentSize: CGSize {
self.setNeedsLayout()
self.layoutIfNeeded()
return contentSize
}
}
This is actually not an answer to the question, but just an explanation. 这实际上不是对问题的答案,而只是一种解释。
(Wrote here because of the character count limitation for the comments). (在这里写是因为注释的字符数限制)。
The thing is that you're trying to insert a vertically scrollable view inside another vertically scrollable view. 问题是您试图在另一个垂直滚动视图内插入一个垂直滚动视图。 If you don't disable the nested tableview's scroll ability, you will have a glitch while scrolling, because the system wouldn't know to whom pass the scroll event (to the nested tableview, or to the parent tableview).
如果不禁用嵌套表视图的滚动功能,则滚动时会出现故障,因为系统将不知道向谁传递滚动事件(嵌套表视图或父表视图)。 So in our case, you'll have to disable the "scrollable" property for the nested tableviews, hence you'll have to set the height of the nested tableview to be equal to its content size.
因此,在我们的案例中,您必须为嵌套表视图禁用“ scrollable”属性,因此必须将嵌套表视图的高度设置为等于其内容大小。 But this way you will lose the advantages of tableview (ie cell reusing advantage) and it will be the same as using an actual UIScrollView.
但是这样一来,您将失去tableview的优势(即单元重用优势),并且与使用实际的UIScrollView相同。 But, on the other hand, as you'll have to set the height to be equal to its content size, then there is no reason to use UIScrollView at all, you can add your nested cells to a UIStackView, and you tableview will have this hierarchy:
但是,另一方面,由于必须将高度设置为等于其内容大小,因此根本没有理由使用UIScrollView,您可以将嵌套的单元格添加到UIStackView中,并且tableview将具有此层次结构:
*TableView
**TableViewCell
***StackView
****Items
****Items
****Items
****Items
But again, the right solution is using multi-sectional tableview. 但同样,正确的解决方案是使用多部分表格视图。 Let your cells be section headers of the tableview, and let inner cells be the rows of the tableview.
让您的单元格成为表格视图的节标题,让内部单元格成为表格视图的行。
here is an example of how to make a tableview inside a table view cell with automatic height for the cells. 这是一个如何在表格视图单元格内创建具有自动高度的表格视图的示例。
You should use the 'ContentSizedTableView' class for the inner tableViews. 您应该对内部tableView使用“ ContentSizedTableView”类。
class ViewController: UIViewController {
@IBOutlet weak var outerTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
outerTableView.rowHeight = UITableView.automaticDimension
outerTableView.estimatedRowHeight = UITableView.automaticDimension
outerTableView.delegate = self
outerTableView.dataSource = self
}
}
final class ContentSizedTableView: UITableView {
override var contentSize:CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
sizeToFit()
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? TableTableViewCell
return cell!
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.