I'm creating deep level tableView (main tableView has two cells, which also have tableViews and they also have other tableViews)
Number of tableViews and cells is limited (it means i don't need recursion)
For rowHeights i'm using UITableView.automaticDimension, but it doesn't works properly.
Here is a screenshot from storyboard:
https://i.stack.imgur.com/3JARb.jpg
And this is a result:
https://i.stack.imgur.com/Kvx9t.jpg
class 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")
}
}
class 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")
}
}
class 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
}
}