0

I have a UI as shown in the screenshot. I have currently done this using tableviews. The screen is a tableview with static prototype cell 4 rows. One for the header including the profile image, next for the profile bio, third row for the favourites, subscriptions, event image button, and last row for the content which is another tableview.

Favourite section

fav

Subscription section

sub

I have used a single inner table view for the content with all elements in the favourites, subscriptions, and events in one cell. One load, I hide other elements and show only the one depending on the icon tap.

The problem is the cell height is inconsistent in favourites section. There is gap when there is more than one line in the label. In the subscriptions section, the last item touches the tabbar.

I have disabled scrolling for the outer table view, so only the inner table view (content section) scrolls, which is not pleasant on smaller screens.

class ProfileViewController: UITableViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        profileTableView = ProfileSectionTableView()  // inner table view
        profileTableView.profileDelegate = self
        profileSectionTableView.delegate = profileTableView
        profileSectionTableView.dataSource = profileTableView
        profileSectionTableView.rowHeight = UITableView.automaticDimension
        profileSectionTableView.estimatedRowHeight = 44
    }

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        switch (indexPath.row) {
        case 0:
            return 176
        case 1:
            return 72
        case 2:
            let height = self.view.frame.height - (176 + 72 + (self.tabBarController?.tabBar.frame.height)! + 8)
            return height
        default:
            return UITableView.automaticDimension
        }
    }

    override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return 44
    }
}

The content section table view code is:

class ProfileSectionTableView: UITableView, UITableViewDelegate, UITableViewDataSource, ProfileSectionViewDelegate {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        let cell = updateTableCell(tableView, indexPath) as! ProfileCell
        var height = UITableView.automaticDimension
        if (ProfileData.profileViewType == .favourite) {
            height = cell.favouritesTitleLabel.text!.height(withConstrainedWidth: cell.favouritesTitleLabel.frame.width - 64, font: UIFont(name: "Roboto", size: 17.0)!) + 28
        } else if (ProfileData.profileViewType == .subscription) {
            height = cell.subscriptionTitleLabel.text!.height(withConstrainedWidth: cell.subscriptionTitleLabel.frame.width - 64, font: UIFont(name: "Roboto", size: 17.0)!) + 16
        }
        return height
    }

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }

    // ...
}
extension String {
    func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil)

        return ceil(boundingBox.height)
    }
}

How to fix the gap between the cells? I have label lines set as 0. How to layout UI elements for screens like this? Is the above method correct? Or should I use a UIViewController with a container view for the sections?

Related question on this How to change the cell height of inner table view cell in iOS?

John Doe
  • 2,225
  • 6
  • 16
  • 44

1 Answers1

1

Dependent your work, i am friendly with only tableView in screen. Then setup tableView with composionSection:[[String:Any]] data; either item is data of section. ex: Favourites, Subscription ... For section: i setup keyId for section, headSection, footer section, of course cell section. you can scroll to top section for an other section.

For example:

// MARK: UITableViewDataSource

var composionSection = [[String: Any]]() 

extension CountryDetailViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
    return composionSection.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if let componentSection = self.composionSection[section] as? [String:Any]{
        if let keyId = componentSection[kId] as? String, let object = componentSection[kObject] as? [String:Any] {
            if keyId == kFavourites || keyId == kSubscription{
                return object.count
            }
        }
    }
    return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if let componentSection = self.composionSection[indexPath.section] as? [String:Any]{
        if let keyId = componentSection[kId] as? String, let object = componentSection[kObject] as? [String:Any] {
            if keyId == kFavourites {
                let cell = tableView.dequeueReusableCell(withIdentifier: identifierForViewCell, for: indexPath) as! ViewFavourites
                return cell
            }
            else if keyId == kSubscription {
                let cell = tableView.dequeueReusableCell(withIdentifier: identifierForViewCell, for: indexPath) as! ViewSubscription
                return cell
            }
        }
    }
    return UITableViewCell()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if let componentSection = self.composionSection[section] as? [String:Any]{
        if let keyId = componentSection[kId] as? String, let object = componentSection[kObject] as? [String:Any] {
            if keyId == kFavourites {
                let sectionView = UIView()
                return sectionView
            }
            else if keyId == kSubscription {
                let sectionView = UIView()
                return sectionView
            }
        }
    }
    return nil
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    if let componentSection = self.composionSection[section] as? [String:Any] {
        if let keyId = componentSection[kId] as? String {
            if keyId == kFavourites {
                return 80
            }
            else if keyId == kSubscription {
                return 64 // or other
            }
        }
    }
    return 0
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return CGFloat.leastNormalMagnitude
}