I am implementing a UITableView within my UIViewController. I have been able to get my text to display with a custom UITableViewCell, but I can not find a way to put spacing between my cells.
I have tried implementing tableView(_:heightForHeaderInSection:), but it seems that it is not called as I have tried to put in a print statement to see if it runs.
i had problem that heightForHeaderInSection was not working, but after i set viewForHeaderInSection then the height works properly. Make sure you have set the view header in section.
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView.init(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 44))
view.backgroundColor = .white
return view
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44
}
Make sure that you set the tableview's delegate to be your viewcontroller (and make sure that your viewcontroller conforms to the UITableViewDelegate protocol):
class CustomTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView! {
didSet {
tableView.dataSource = self
tableView.delegate = self
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 5
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 20
}
}
Results in:
Add this in your viewDidLoad() :
let HEADER_HEIGHT = 100
tableView.tableHeaderView?.frame.size = CGSize(width: tableView.frame.width, height: CGFloat(HEADER_HEIGHT))
Another way -
public override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 100
}
Related
Interface:
Interface in debugger:
Here is configuration of tableview
private func configureTableView(){
view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .none
// tableView.rowHeight = UITableView.automaticDimension
tableView.register(DishCell.self, forCellReuseIdentifier: "dishCell")
// tableView.sectionHeaderHeight = UITableView.automaticDimension
}
Here is tableView extensions
extension MenuViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return 380
}
return 48
}
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
return 122
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableView.automaticDimension
}
}
extension MenuViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return viewModel.dishes.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.dishes[section].count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let dishType = viewModel.dishTypes[section]
if section == 0 {
let restaurant = viewModel.restaurant
return FirstMenuHeader(restaurant: restaurant, dishType: dishType)
}else{
return DefaultMenuHeader(dishType: dishType)
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "dishCell") as! DishCell
let dish = viewModel.dishes[indexPath.section][indexPath.row]
cell.set(dish: dish)
return cell
}
}
Just to clarify DishCell, FirstMenuHeader and DefaultMenuHeader look well if you put them outside of UITableview. And they have constraints that define their height. However their height is dynamic and depends on amount of line of text.
Problem was in dishCell.I made constraints with view, while I had to make constraints with contentView.
I have rewrote my constraints and problem was resolved.
There are questions and answers for how to change the background color of Header titles in UITableView. These work when a class directly inherits from UITableView. However, when I embed a UITableView as a child of a UIViewController, the same approach of changing the background color does not appear to work.
Can you please see the code below and let me know how I can do this?
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var table: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = "Test row"
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Section Title"
}
func numberOfSections(in tableView: UITableView) -> Int {
1
}
// One way to change the header color
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
view.backgroundColor = .green
}
// Another way
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let vw = UIView()
vw.backgroundColor = .red
return vw
}
override func viewDidLoad() {
super.viewDidLoad()
table = UITableView(frame: CGRect(x: view.frame.maxX/3, y: view.frame.maxY/3, width: view.frame.width/2, height: view.frame.height/2))
table.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
table.dataSource = self
view.addSubview(table)
}
}
tableView(_:viewForHeaderInSection:) is a delegate method check Docs , so you need to add
table.delegate = self
You'll need to conform to UITableViewDelegate for titleForHeaderInSection, willDisplayHeaderView, and viewForHeaderInSection.
You'll need to conform to UITableViewDataSource for numberOfRowsInSection, cellForRowAt, numberOfRowsInSection.
In your viewDidLoad():
table.delegate = self
table.dataSource = self
My tableview code is -
import UIKit
class ViewController: UIViewController {
var categories = ["Action", "Drama", "Science Fiction", "Kids", "Horror"]
}
extension ViewController : UITableViewDelegate { }
extension ViewController : UITableViewDataSource {
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return categories[section]
}
func numberOfSections(in tableView: UITableView) -> Int {
return categories.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CategoryRow
return cell
}
}
The result on the simulator is -
Now, I want the to customize the font/text of the various sections i.e. Action, Drama, Science Fiction, Kids, Horror other than black, may be make it bigger etc. How is it possible ?
With tableView(_:titleForHeaderInSection:) method, you can't modify the UI properties of the header text.
You need to implement tableView(_:viewForHeaderInSection:) and tableView(_:heightForHeaderInSection:) methods to get a custom UI for the header, i.e.
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let label = UILabel()
label.text = categories[section]
label.font = UIFont.systemFont(ofSize: 20.0, weight: .bold)
label.textColor = .red
label.sizeToFit()
return label
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50.0
}
Simply return a UILabel instance with required text attributes in tableView(_:viewForHeaderInSection:)
There is below function available in UITableViewDelegate
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
<#code#>
}
You would have the full control over the header of each section and customisation can be done accordingly.
In the method
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return categories[section]
the table view uses a fixed font style for section header titles. If you want a different font style, return a custom view (for example, a UILabel object) in the delegate method tableView(_:viewForHeaderInSection:) instead.
You can use delegate method of UITableView tableView(_:viewForHeaderInSection:) to get custom UI for the header
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView(frame: CGRect(x: 0, y: 0, width: yourTable.bounds.width, height: 40))
let headerLabel = UILabel(frame: CGRect(x: 15, y: 0, width: yourTable.bounds.width, height: 40))
headerLabel.font = UIFont.boldSystemFont(ofSize: 20)
headerLabel.textColor = .blue
headerLabel.text = self.tableView(self.yourtableView, titleForHeaderInSection: section)
headerLabel.sizeToFit()
headerView.addSubview(headerLabel)
return headerView
}
And height for section
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 30 //whatever you want
}
I am using below code for one fixed cell at the top and then list of items in below in a single tableview, I am able to load the data from firestore database, but the first item in from the database is not shown, it is kind of hidden behind the fixed "detailscell", rest the fixed cell and all other items from the database shows up, how to fix that?
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// print(posts)
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 && details1.count > 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "detailsCell") as! DetailsCellInHomeScreen
cell.set(details: details1[indexPath.row])
return cell
} else if posts.count > (indexPath.row - 1) {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
cell.set(post: posts[indexPath.row - 1])
return cell
} else {
return UITableViewCell()
}
}
TableView has a function like below:
// MARK: - Headers and Footers
extension MyTableViewController {
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return MyCustomView()
}
}
You can use this function to return any view you want as a section header. Also note that sectionHeader views are sticky in default style tableView (not grouped style!). So you can use this as a advantage.
There are many tutorials like this one on the internet to follow and learn how to build a custom section section header for UITableView
You should add header on the table view:
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// print(posts)
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
cell.set(post: posts[indexPath.row - 1])
return cell
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: tableView.frame.width, height: 50))
let label = UILabel()
label.frame = CGRect.init(x: 5, y: 5, width: headerView.frame.width-10, height: headerView.frame.height-10)
label.text = "A Label on detailsCell"
headerView.addSubview(label)
return headerView
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
if the tableView has several section you can realize the section with section: Int object
tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? uses for create the header view and tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat uses for set header height
I tried to make a Footer in UITableView like in iOS app "Contacts".
I have simple tableView with simple array:
items = ["aa", "bb", "cc", "dd"]
I want to make empty space under last cell.
I tried to add this cellForRowAt:
if indexPath.row == self.converterItems.count-1 {
cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0)}
But it delete separator only for one cell.
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
var header :UITableViewHeaderFooterView = UITableViewHeaderFooterView()
header.contentView.backgroundColor = UIColor(red: 255.0/255.0, green: 255.0/255.0, blue: 255.0/255.0, alpha: 1)
return header
}
This method looks good, but it lost separator below last cell...
You should create a UIView and assign it to your table's footer view
myTableView.tableFooterView = createTableFooterView()
func createTableFooterView() -> UIView {
let footerView = UIView()
...
...
...
return footerView
}
To make the table endless. You'd better set UITableViewStyle.grouped
let tableView = UITableView(frame: CGRect.zero, style: .grouped)
And Then:
extension ViewController: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return [].count// your array
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "", for: indexPath)
// your cell
// yourIdentifier, and you should register cell Identifier for tableView at first
return cell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return ""
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return "83 KOH"
}
}