Custom UITableView Cell inside a UITableViewController footer - ios

I have a UITableviewController which I created programmatically in Swift4.
The marked rectangle in the picture is my footerview with a UITableView inside
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let tableFooterView = UITableView()
tableFooterView.rowHeight = 100
return tableFooterView
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 365
}
I want to load custom cells in the tableview cells in footerview. I tried using this following code
tableFooterView.dequeueReusableCell(withIdentifier: emptyCellIdentifier) as! EmptyTableViewCells
But I get error -
fatal error: unexpectedly found nil while unwrapping an Optional value
Please help

You have to register the cell for the footer tableView when you are creating in viewForFooterInSection method and you should distinguish both the tables via tag or something if you are making the delegate and datasource as self for the tableFooterView UITableView
tableFooterView.register(EmptyTableViewCells.self, forCellReuseIdentifier: emptyCellIdentifier)
So your method will be :
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
if tableView.tag == 1 {
tableFooterView = UITableView()
tableFooterView.register(EmptyTableViewCells.self, forCellReuseIdentifier: emptyCellIdentifier)
tableFooterView.rowHeight = 100
tableFooterView.tag = 2
tableFooterView.dataSource = self
tableFooterView.delegate = self
return tableFooterView
} else {
//footer view is nil for the table view which is in the main table footer
return nil
}
}
This will stop the crash on the tableFooterView.dequeueReusableCell line but you need to add the other views like buttons and labels on the tableFooter Empty Cell by code and not IBOutlet. It will again crash if you access any IBOutlet connected component.

Related

How to show and hide Custom UITableView Header Cell of Table View in Swift3 iOS

I am developing an application in Swift3 where I have to show and hide UITableView Header for different users. For displaying UITableView Header View, I have created a custom class CustomHeaderCell of UITableViewCell.
Here is my code:
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 235.0
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell") as! CustomHeaderCell
return headerCell
}
Now Can anyone please help me to hide this Header of my UITableView?
Note: I tried using this tableView.tableHeaderView?.isHidden = true, but not working. Should I need to do the validation in heightForHeaderInSection?
Reference Link to Add HeaderViewCell: http://www.accella.net/knowledgebase/custom-header-and-footer-views-for-uitableviews/
If you have a way to differentiate users then you can just change the header height like this
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if userA {
return 235.0
} else {
return 0
}
}
That should help in hiding the header
You are mixing tableHeaderView and section header views, which are differents:
tableHeaderView is a view showed as a header for the whole UITableView
section header views are reusable views used for displaying header above each section
In your case, you want to use section header views, so you should return empty ones for non concerned users (I assume here sectionNeedHeader will be replaced by your condition).
Also, you better use UITableViewHeaderFooterView instead of UITableViewCell. The behavior is globally the same but it's made for this usage:
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if sectionNeedHeader {
return 235.0
}
return 0.0
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if sectionNeedHeader {
let headerCell = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderView") as! CustomHeaderView
return headerView
}
return nil
}

Autosizing UITableView inside custom UIView for section

I have created UIViewController and added UITableView on it (pinned to all four edges with autolayout).
Then I set estimatedRowHeight (44) and rowHeight (UITableViewAutomaticDimension) and returned 5 custom cells. And it worked.
Now, I want to add custom UITableViewHeaderFooterView that would have dynamic height.
I'm doing next:
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 88.0
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return R.nib.orderStatusHeaderView.firstView(owner: self)!
}
My OrderStatusHeaderView is a xib view that has UITableView on it pinned to all 4 edges with autolayout.
OrderStatusHeaderView:
final class OrderStatusHeaderView: UITableViewHeaderFooterView {
#IBOutlet weak var tableView: UITableView! {
didSet {
tableView.dataSource = self
tableView.delegate = self
tableView.rowHeight = 44.0
}
}
}
extension OrderStatusHeaderView: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "\(indexPath.row)")
cell.textLabel?.text = "\(indexPath.row)"
cell.backgroundColor = .red
return cell
}
}
This displays like:
And when I tap or scroll, all red cells disappears. What could it be? And how to make UITableView dynamically load content and UITableViewHeaderFooterView will size itself so it fit UITableView.contentSize. Is it possible?
Check out:
tableView(_:estimatedHeightForFooterInSection:)
and
tableView(_:heightForFooterInSection:)
You also have the equilavant for headerInSection.
Since you are asking for a table's header and footer view, you can skip the delegate methods you describe. Those (as the name implies) are for SECTION headers and footers.
When you set a view that is using AutoLayout as the table's header or footer, the its frame still has a zero height (That's why buttons in such view for example won't work as they are not receiving the touches).
To correctly size a table's header or footer views using AutoLayout you have to apply a trick to actually calculate the height yourself, and set the headerView again. It is described in detail in many posts like these:
https://stackoverflow.com/a/28102157/756039
https://gist.github.com/marcoarment/1105553afba6b4900c10
http://collindonnell.com/2015/09/29/dynamically-sized-table-view-header-or-footer-using-auto-layout/
http://roadfiresoftware.com/2015/05/how-to-size-a-table-header-view-using-auto-layout-in-interface-builder/
Hope this helps.

heightForHeaderInSection only called once

Coding in Swift 3. Have a tableView with custom cells and header.
I have a tableView with custom cells and headers. The headers have two (2) labels in them and have dynamic cell heights since the labels may be long. My problem is the first time the tableView and sections are configured the label appears as it should, HOWEVER, after scrolling down and then back up the headers' layout somehow breaks.
As you can see below, after I scroll down then back up to the cells, the label is getting cutoff.
After printing out what methods are being called I found that the first time scrolling down the tableView the following two (2) override functions are called.
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
print("\(section) heightForHeaderInSection")
print("\(section) returning AUTO for header")
return UITableViewAutomaticDimension
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
print("\(section) viewForHeaderInSection")
let header = tableView.dequeueReusableCell(withIdentifier: "QuestionHeader") as! QuestionHeader
header.delegate = self
header.contentView.backgroundColor = UIColor.groupTableViewBackground
header.questionTextLabel.text = String(questionStringArray[section])
header.questionNumberLabel.text = (String(section + 1) + ")")
return header.contentView
}
But when i scroll back up ONLY the viewForHeader function is called and I think because the height is no longer being set to UITableViewAutomaticDimension the labels get cutoff?
Any ideas?
You should return header instead of header.contentView from tableView: viewForHeaderInSection: method:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableCell(...
...
return header
}

how to programmatically hide or delete extra cell and seperators in tableview swift 2.2

In my app I have a UITableView with 5 cell data. When I will run the app. It will display 5 cells with data properly in Output. But there are many extra cell show empty. I want to remove extra cell in UITableView. I have also done in objective-C but I need some help in Swift 2.2 also I'm new in swift.
in your viewDidLoad() add this line :
yourtableView.tableFooterView = UIView()
or use
yourtableView.tableFooterView = UIView(frame: CGRectZero)
Try the following code. May be this is helpful to you.
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView()
}
The issue might be arising from the fact that you are specifying a greater number of rows in the UITableView than required to populate data. Assuming you are populating the UITableView from an Array, you should probably set the row count to the count of array.
If you are using a UITableViewController override this method
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return yourArray.count
}
If a UITableView is embedded in the UIViewController set UITableView delegate to self and implement this method.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return yourArray.count
}
write this code
self.tableView.tableFooterView = UIView(frame: CGRectZero)
Implement this delegate method like this:
func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.1
}
func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return UIView()
}

tableView section headers disappear SWIFT

I have a tableView set up so that when a cell is touched, it expands in height to reveal more information. The tableView has 5 sections.
I have a bug: when a cell expands, all headersCells below that cell go invisible. The console outputs the following: "[31233:564745] no index path for table cell being reused"
In my storyboard I have 2 custom cells : "myCell" for the data bearing cells, and "headerCell" for the headers.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let thisGoal : GoalModel = goalArray[indexPath.section][indexPath.row]
if self.currentPath != nil && self.currentPath == indexPath {
self.currentPath = nil
} else {
self.currentPath = indexPath
}
tableView.beginUpdates()
tableView.endUpdates()
}
If I enter tableView.reloadData() in between the begin/end updates, it functions properly, although the header background turns black, and loses animation.
I have all of the stuff for headers declared in: func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
what am I missing? I'd really like the tableView to still have animations, and keep the background clearColor().
Thanks in advance. I did read through the objective C answers, but couldn't get them to work for me. I'd really appreciate some SWIFT help.
I think the problem is the no index path for table cell being reused.
I found an answer in the console output. Use this code in the header function:
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
Do not return your headerCell, or your reusable identifier. Return the reuseIdentifier.contentView. For me it's: return headerCell!.contentView.
Just to add, I was baffled for WAY longer than I should have been as to why I couldn't refer to the contentView of my cell, when I could quite clearly see it was there. My custom class (using UITableViewCell rather than UITableViewHeaderFooterView) would return a fatal error each time. Therefore make sure any custom styling is setup under UITableViewHeaderFooterView class like:
class CustomHeaderCell: UITableViewHeaderFooterView {
You will also need to register the resuableIdentifer like this:
tableView.registerNib(UINib(nibName: "HeaderCell", bundle: nil), forHeaderFooterViewReuseIdentifier: "CellHeader")
Then this bad boy:
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableHeaderFooterViewWithIdentifier("CellHeader") as! CustomHeaderCell!
return headerCell!.contentView
}
Since I'm not at 50 reputation yet, I can't comment on the previous answer, so I apologize for listing this as another answer.
Returning the ContentView will make the function work but will remove all formatting done to the reuseIdentifier (headerCell)
headerCell.backgroundColor = UIColor.cyanColor()
This will NOT provide a Cyan color to your headerCell
To fix this, just add the ".contentView" to your formatting lines
headerCell.contentView.backgroundColor = UIColor.cyanColor()
Table view headers in 2 tables disappeared when I converted my app to IOS 10 - I found the reason in Apple developer API documentation on table headers. When I added the following, the missing headers reappeared!
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
return 44 // where 44 is the header cell view height in my storyboard
}
You could wrap the TableViewCell inside an UIView
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let containerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 50)) // 50 = Header height
guard let headerCell = tableView.dequeueReusableCell(withIdentifier: "MyHeaderView") as? MyHeaderView else { fatalError(" Failed to load MyHeaderView") }
headerCell.frame = containerView.bounds
containerView.addSubview(headerCell)
return containerView
}
I had the same bug because I was returning a cell using dequeue method instead of a UITableViewHeaderFooterView.
Solution:
Add a view outside of the view hierarchy
Set the type to UITableViewHeaderFooterView
Customize
Link to an #IBOutlet
In func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? return the outlet
Common pitfalls:
Don't forget to set the header sizes
Don't forget to set the outlet as strong.

Resources