This is my code
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 61.0
}
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableCellWithIdentifier("CustomHeaderCell") as! CustomHeaderCell
headerCell.titleLabel.text = "user data"
return headerCell
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
Unfortunately, custom header view does not show up.
However, when I use just this:
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "user data"
}
section headers are present, what is wrong with my custom header view code?
My bad, I blindly put these functions into dataSource although they belong to tableViewDelegate
to make it work:
extension UserProfileDelegate: UITableViewDelegate {
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableCellWithIdentifier("CustomHeaderCell") as! CustomHeaderCell
headerCell.titleLabel.text = "user data"
return headerCell
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 61.0
}
}
Related
After receiving a new object, I call this func to insert a cell:
private func addCellToTheTop(recipe: Recipe) {
guard let recipeTableView = self.recipeTableView else { return }
recipesForShow.insert(recipe, at: 0)
recipeTableView.beginUpdates()
recipeTableView.insertRows(at: [IndexPath.init(row: 0, section: 0)], with: .automatic)
recipeTableView.endUpdates()
}
But I get an error
Why the number of section does not match?
If it is important:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func numberOfSections(in tableView: UITableView) -> Int {
return recipesForShow.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return TableCellConfig.spaceBetweenCells
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.backgroundColor = UIColor.clear
return headerView
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//...
}
You are getting this exception because you are appending a new element to the array that is being used to determine the numberOfSection whereas you are inserting a new row into the tableView. To fix this you need to insert section instead of inserting new row, here's how:
recipeTableView.insertSections([0], with: .automatic)
i have a table with a variable number of sections. If there are more than one section i want to show show custom Headers, but if there is only one, i don't want a header at all.
My Approach is to use func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? and return nil if i have only one section. But instead of showing no header, i get an empty header. Any ideas?
here is my code
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Orders"
tableView.dataSource = self
tableView.delegate = self
let headerNib = UINib.init(nibName: "SectionHeader", bundle: Bundle.main)
tableView.register(headerNib, forHeaderFooterViewReuseIdentifier: "SectionHeader")
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if(ordersList.count < 2) {return nil}
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "SectionHeader") as! SectionHeader
headerView.label.text = "\(sectionHeaders[section]) (\(ordersList[section].count))"
headerView.button.setTitle(self.collapsed[section] ? "▶" : "▼", for: .normal)
headerView.onTap = {
self.collapsed[section] = !self.collapsed[section]
headerView.button.rotate(self.collapsed[section] ? CGFloat(-.pi/2.0) : CGFloat(.pi/2.0), duration: 0.1, completion: {
self.tableView.beginUpdates()
self.tableView.reloadSections([section], with: .fade)
self.tableView.endUpdates()
})
}
return headerView
}
use heightForHeaderInSection delegate method also. Make height 0 if condition not satisfy. For Reference -
public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if(ordersList.count < 2) {return 0.1}
else { return HEIGHT} //custom value of view height
}
You have to use the following methods to achieve the desired result:
func numberOfSections(in tableView: UITableView) -> Int {
if(ordersList.count < 2) {return nil}
return ordersList.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if(ordersList.count < 2) {return nil}
//else return some view }
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if(ordersList.count < 2) {return 0}
return some_height
}
Use tableView.numberOfSections to get the section count. And use this value in tableView(_:viewForHeaderInSection:) to check whether you want return SectionHeader or nil. You need to return nil in case you don't want to show header in a particular section.
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
guard tableView.numberOfSections > 1 else {
return nil
}
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "SectionHeader") as! SectionHeader
//add rest of the code...
return headerView
}
Implement tableView(_:heightForHeaderInSection:) to return the header height based on the section. Return 0 if you don't want to show header in a section otherwise it will take the default header height.
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return (tableView.numberOfSections > 1) ? 100.0 : 0.0
}
you should override numberOfSections method of tableview. And you should not use dequeueReusableHeaderFooterView for section header view. Section header views should be a custom view.
-- numberOfSections
func numberOfSections(in tableView: UITableView) -> Int {
return sectionCount
}
-- sectionHeaderView
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
// you can store data on a view model
let cellViewModel = viewModel.returnViewModel(index: section)
switch cellViewModel.type {
case .sampleViewModel1:
return UIView() // sampleView1
case .sampleViewModel2:
return UIView() // sampleView2
}
}
I would like to add some space between the last cell of a section and the header of the next section if the table is a plain type
How can I do that?
You can try
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 20
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return UIView()
}
You can use a Footer View
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return UIView()
}
To avoid sticky footer, use allowsFooterViewsToFloat() function
public extension UITableView {
func allowsHeaderViewsToFloat() -> Bool {
return true
}
func allowsFooterViewsToFloat() -> Bool {
return false
}
}
You can do it with just add empty cell at the end of section.
We do have a TableViewModel which is implementing the UITableViewDelegate and the UITableViewDataSource. It holds the sections and returns the right rows and elements of our UITableViews.
Now we want to have a custom table view section footer. Therefor we implement the optional public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? so that this returns a UIView from a xib file. This is all fine but it ends up in a wrong footer height. If we use func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? the footer is displayed correct and the height of the footer is set correct.
So we also have to implement the optional public func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat or the optional public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
Question: How do i get the height of an UIView which this was instantiated? view.frame.bounds or view.frame.height is always 0.
Question: What is the default value Apple uses for the footer and how does it calculate that? I recognised that if we return table.sectionFooterHeight for the default (not our custom footer view) the hight is correct.
TableViewModel:
class TableViewModel: NSObject, UITableViewDelegate, UITableViewDataSource {
var sections: [TableViewSection] = []
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].numberOfRowsInTableView(tableView)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return sections[(indexPath as NSIndexPath).section].tableView(tableView, cellForRowAtIndexPath: indexPath)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
sections[(indexPath as NSIndexPath).section].tableView(tableView, didSelectRowAtIndexPath: indexPath)
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section].headerText
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
sections[section].tableView(tableView, willDisplayHeaderView: view)
}
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return sections[section].footerText
}
func tableView(_ tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) {
sections[section].tableView(tableView, willDisplayFooterView: view)
}
func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool {
return sections[(indexPath as NSIndexPath).section].tableView(tableView, cellContentsToCopyAtIndexPath: indexPath, withSender: nil) != nil
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
??
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return sections[section].footerView
}
func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat {
??
}
}
I solved it by adding the following method:
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return sections[section].footerViewHeight ?? UITableViewAutomaticDimension
}
And returning the calculated height for the footer in section. It does resize properly and we are able to adjust it. As mentioned, returning the UITableViewAutomaticDimension requires:
// Returning this value from tableView:heightForHeaderInSection: or tableView:heightForFooterInSection: results in a height that fits the value returned from // tableView:titleForHeaderInSection: or tableView:titleForFooterInSection: if the title is not nil.
If you are using auto layout you can still return UITableViewAutomaticDimension in heightForFooterInSection and the footer's height will be automatically calculated. As same with heightForRowAt , heightForFooterInSection must be used in combination with estimatedHeightForFooterInSection. A simple example would look like this:
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat {
return 18 // or whatever value
}
I am using Xib files instead of storyboard. I have created a table view with some dummy data. Its working fine, Now I have created a custom cell with some labels and textFields. How can I use it as header or footer of UITableView ?
The answer is actually pretty simple.
In viewForHeaderInSection() create cell object as you do in cellForRowAtIndexPath() and return it.
Here is sample code.
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCellWithIdentifier("cellIdentifier") as! YourTableViewCell
return cell
}
You can set height for header as:
override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 80
}
Update for Swift 4.2
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier") as! YourTableViewCell
return cell
}
and
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 80
}
You can create a custom view programmatically. I tried the following code. Try it once.
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let customview:UIView = UIView();
let label = UILabel();
label.text = "ur custom data"
/*
You can add any number of subviews you want here
And don't forget to add it to your customview.
*/
customview.addSubview(label)
return customview;
}
similarly you can do the same thing for header also.
This is the Method add the Header of TableView:
In that you can any controls Like UIButton,UIImageView,....etc.
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let sectionView = UIView()
sectionView.frame = CGRectMake(x,y,height,width) // For Set the Frame
sectionView.backgroundColor = UIColor.redColor()
return sectionView
}
func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let sectionView = UIView()
sectionView.frame = CGRectMake(x,y,height,width) // For Set the Frame
sectionView.backgroundColor = UIColor.redColor()
return sectionView
}
Like Above you can set the Footer of Section and
You can add the size of the header And footer
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 20.0
}
func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 20.0
}
Swift 4.0
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let sectionView = UIView()
sectionView.frame = CGRect(x: x, y: y, width: width, height: height)// For Set the Frame
sectionView.backgroundColor = UIColor.red
return sectionView
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let sectionView = UIView()
sectionView.frame = CGRect(x: x, y: y, width: width, height: height)// For Set the Frame
sectionView.backgroundColor = UIColor.red
return sectionView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 20.0
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 20.0
}