[英]UICollectionView inside UITableViewCell , UITableView Dynamic Height
[英]UITableView inside UITableViewCell with dynamic height
我需要将 UITableView 放在带有自动布局的 UITableViewCell 中,因为第二个表有不同的行数,而一行可以有不同的高度。
这是我的视图控制器
class ViewController: UIViewController {
let tableView = UITableView()
let cellId = "firstTableCellId"
override func viewDidLoad() {
super.viewDidLoad()
setupView()
tableView.reloadData()
view.backgroundColor = UIColor.gray
}
func setupView() {
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .none
tableView.register(NextTable.self, forCellReuseIdentifier: cellId)
tableView.backgroundColor = UIColor.green
tableView.separatorStyle = .singleLine
view.addSubview(tableView)
view.addConstraintsWithFormat("V:|-60-[v0]-5-|", views: tableView)
view.addConstraintsWithFormat("H:|-8-[v0]-8-|", views: tableView)
}
}
extension ViewController: UITableViewDelegate {
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! NextTable
cell.layoutIfNeeded()
return cell
}
}
和 NextTable 是第一个表格中的单元格
class NextTable: UITableViewCell {
var myTableView: UITableView!
let cellId = "nextTableCellId"
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = UIColor.brown
setupView()
myTableView.reloadData()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
let label: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.text = "Next table:"
label.textColor = UIColor.black
label.sizeToFit()
label.backgroundColor = UIColor.cyan
return label
}()
func setupView() {
myTableView = UITableView()
myTableView.delegate = self
myTableView.dataSource = self
myTableView.separatorStyle = .singleLineEtched
myTableView.backgroundColor = UIColor.blue
myTableView.register(TableCell.self, forCellReuseIdentifier: cellId)
myTableView.isScrollEnabled = false
addSubview(myTableView)
addSubview(label)
addConstraintsWithFormat("H:|-30-[v0]-30-|", views: myTableView)
addConstraintsWithFormat("H:|-30-[v0]-30-|", views: label)
addConstraint(NSLayoutConstraint(item: label, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 15))
addConstraint(NSLayoutConstraint(item: myTableView, attribute: .top, relatedBy: .equal, toItem: label, attribute: .bottom, multiplier: 1.0, constant: 0))
addConstraint(NSLayoutConstraint(item: label, attribute: .bottom, relatedBy: .equal, toItem: myTableView, attribute: .top, multiplier: 1.0, constant: 0))
addConstraint(NSLayoutConstraint(item: myTableView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: -15))
}
}
extension NextTable: UITableViewDelegate {
}
extension NextTable: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! TableCell
cell.layoutIfNeeded()
return cell
}
}
和第二个表格中的单元格
class TableCell: UITableViewCell {
let label: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.text = "Some text"
label.textColor = UIColor.black
label.sizeToFit()
label.backgroundColor = UIColor.red
return label
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = UIColor.yellow
setupView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupView(){
addSubview(label)
addConstraintsWithFormat("V:|-8-[v0]-8-|", views: label)
addConstraintsWithFormat("H:|-5-[v0]-5-|", views: label)
}
}
这是我的代码的效果
没有第二个表,所以我创建新类并在单元格中将其用作新表视图
class InnerTableView: UITableView {
override var intrinsicContentSize: CGSize {
return self.contentSize
}
}
现在表格显示但尺寸太大
我该怎么做才能显示完整的第二个表格,而单元格底部没有空白空间。
我在表视图中添加了对属性的覆盖:
override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
return self.contentSize
}
你可以在我的GitHub 上找到表中表的完整代码
在您的第一个表格视图中,在您的单元格出列后将其添加到您的cellForRowAt
(可能需要稍微调整以适应您的实现):
cell.tableView.reloadData()
DispatchQueue.main.async {
cell.tableView.scrollToRow(at: IndexPath(row: cell.numberOfRowsInInnerTableView.count.count - 1, section: 0), at: .bottom, animated: false)
}
DispatchQueue.main.async {
cell.tableView.invalidateIntrinsicContentSize()
cell.tableView.layoutIfNeeded()
self.updateHeight()
}
然后在同一个类(外表视图)中定义一个函数updateHeight
:
func updateHeight() {
UIView.setAnimationsEnabled(false)
tableView.beginUpdates()
tableView.endUpdates()
UIView.setAnimationsEnabled(true)
}
显然,这有点InnerTableView
,但本质上它允许单元格的InnerTableView
知道所有内部单元格的实际高度并适当地调整外部 tableview 的大小。 这种方法对我有用。
您所需要的只是使 ParentTableView 的cellForRowAt indexPath 中的内容大小无效
parentCell.InsideTableview.invalidateIntrinsicContentSize()
我尝试了上述解决方案,但对我不起作用。 我做了一些小的改变,然后它对我来说很好。
A) 在我的 ViewController 中:
//注意:TestQuestionAnsOptionCell 是外层单元格
if let cell = tableView.dequeueReusableCell(withIdentifier: String(describing:TestQuestionAnsOptionCell.self), for: indexPath) as? TestQuestionAnsOptionCell {
cell.reloadData()
setUpInnerCellListner(cell: cell)
cell.selectionStyle = .none
return cell
}
private func setUpInnerCellListner(cell:TestQuestionAnsOptionCell) {
cell.reloadTable = { // Closure called from TestQuestionAnsOptionCell
DispatchQueue.main.async {
UIView.setAnimationsEnabled(false)
self.tbQuestion.beginUpdates()
self.tbQuestion.endUpdates()
UIView.setAnimationsEnabled(true)
}
}
}
这里使用的扩展:
extension NSObject {
class var className: String {
return String(describing: self)
}
}
B) 在 TestQuestionAnsOptionCell 中:
class TestQuestionAnsOptionCell: UITableViewCell {
var tblOptions: OwnTableView = OwnTableView()
var reloadTable:(()->(Void))?
override func awakeFromNib() {
super.awakeFromNib()
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private func setupView() {
tblOptions.estimatedRowHeight = 60.0
tblOptions.rowHeight = UITableView.automaticDimension
tblOptions.delegate = self
tblOptions.dataSource = self
tblOptions.separatorStyle = .none
tblOptions.register(UINib(nibName: TestQuestionOptionCell.className, bundle: nil), forCellReuseIdentifier: TestQuestionOptionCell.className)
tblOptions.isScrollEnabled = false
addSubview(tblOptions)
addConstraintsWithFormat("H:|-30-[v0]-30-|", views: tblOptions)
addConstraint(NSLayoutConstraint(item: tblOptions, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 15))
addConstraint(NSLayoutConstraint(item: tblOptions, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: -15))
}
func reloadData() {
tblOptions.reloadData()
}
}
使用 TableView 委托和数据源,我使用了以下内容:
extension TestQuestionAnsOptionCell:UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//NOTE: TestQuestionOptionCell is the inner cell
if let cell = tableView.dequeueReusableCell(withIdentifier: TestQuestionOptionCell.className, for: indexPath) as? TestQuestionOptionCell {
cell.updateCell()
cell.selectionStyle = .none
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
tblOptions.invalidateIntrinsicContentSize()
tblOptions.layoutIfNeeded()
reloadTable?()//Closure to update outer tableview
}
}
C) 内部 tableview 用作:
class OwnTableView: UITableView {
override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
return self.contentSize
}
override var contentSize: CGSize {
didSet{
self.invalidateIntrinsicContentSize()
}
}
}
D) UIView 扩展为:
extension UIView {
func addConstraintsWithFormat(_ format: String, views: UIView...) {
var viewsDictionary = [String:UIView]()
for(index, view) in views.enumerated() {
let key = "v\(index)"
view.translatesAutoresizingMaskIntoConstraints = false
viewsDictionary[key] = view
}
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: viewsDictionary ))
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.