Auto resize font in sectionHeader - ios

I Want to show a name and some other short informations in the sectionHeader of my Tableview.
Some of the names are very large so they don't fit, is there a way to autoresize the fontsize in the sectionHeader like in a label with:
label.adjustsFontSizeToFitWidth = true;

The easiest way would be to create a UILabel in tableView(_:viewForHeaderInSection:)
Apple Docu Discussion:
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.

Simply follow the code for custom header view -
Setup tableView
tableView.estimatedSectionHeaderHeight = 80 // You can change this value accordingly
tableView.sectionHeaderHeight = UITableViewAutomaticDimension
Implement your custom section header and return it in the delegate method
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
switch section {
case 0:
return sectionHeader
default:
fatalError("Unreachable code")
}
}
Finally, if the contents in the header section changes while the header is presented, after the change you will have to tell the tableView to redraw itself using
func refreshTableAfterCellExpansion() {
self.tableView.beginUpdates()
self.tableView.setNeedsLayout()
self.tableView.endUpdates()
}

Related

Why are separator insets not being respected for the first and last cell in a grouped section?

I want to be able to have all of my separators in a table view to be inset by a certain amount. This table view needs a custom header for each section. See the following image for the desired insets:
My storyboard is set up so that I have a UIViewController which contains a container UIView, which in turn has an embed segue for a UITableView. My table view specifies a prototype cell, and I have set in the storyboard a Grouped style, Default separator, with Automatic inset.
On my Table View Cell in the storyboard, I have a Custom separator inset of 26 on the left.
In my table view controller, I have implemented the following two methods:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "ItemHeader") as! TableSectionHeaderViewCell
header.title.text = "My Custom Date Header"
return header
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 60.0
}
In a separate file I have subclassed UITableViewHeaderFooterView to just set a font, text color, and some constraints.
Now if I set a custom separator inset on the storyboard at the table view level with 26 inset from the left, either From Cell Edges or From Automatic Insets, nothing changes with the separators that appear below each of my headers. Similarly, if I set these values programmatically in the viewDidLoad method of my table view controller, like so:
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableView.automaticDimension
tableView.register(TableSectionHeaderViewCell.self, forHeaderFooterViewReuseIdentifier: "ItemHeader")
tableView.separatorInset = UIEdgeInsets(top: 0, left: 26, bottom: 0, right: 0)
tableView.separatorStyle = .singleLine
tableView.separatorInsetReference = .fromCellEdges
}
Nothing changes with the separator insets, even using the .fromAutomaticInsets option for the separator inset reference. Here is what I am actually seeing:
It seems that the first and last cells in a section are actually not respecting the separator insets. I thought originally that this was an issue related to having a header for each grouped section, but the separator on the final cell with no header below it seems to indicate otherwise. How can I make it so that these separators all are inset by 26pts? Thank you for any insight you can provide.
Check this thread then, I think it will help:
Grouped UITableview remove outer separator line
I can see that they removed the default separator (Using Clear Color) and put a custom view for the separator themselves.
The other option I can suggest is don’t use a group style Table view, use the plain one and handle it yourself.

How to prevent tableview section head from sticking while scrolling?

I have a tableview with many sections. I am using an actual tableview cell which I dequeue to use as a custom section header. The issue I am having is when I scroll the section header "sticks" to the top of the table until the next section appears.
How can I prevent this from happening and actually have it scroll up like normal?
Here is my code
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 3 {
let cell = tableView.dequeueReusableCell(withIdentifier: "headerCell") as! HeaderTableViewCell
return cell
}
return UIView()
}
Do following steps.
From #IB
Select your tableView
Go to Attribute Inspector
Find Style Attribute drop down which is Plain by default
Change it to Grouped
Or if you are creating TableView Programmatically use
let tableView = UITableView(frame: YourFrame, style: .Grouped)
Change UITableViewStyle to UITableViewStyleGrouped.
Set UITableViewStyle to UITableViewStyleGrouped, the headers will scroll up with the cells.
and
func tableView(_ tableView: UITableView,
heightForFooterInSection section: Int) -> CGFloat
{
return 0.000001;
}
Step1: Go to Mainstoryboard
Step2: Click on Your Tableview
Step3: Go to Attribute Inspector
Step4: Find Style Attribute drop down which is Plain by default
Step5: Change it to Grouped
Some possible solutions :
If you have just one section then set the Tableview Header property to the UIView you want to set as the Section Header.
If you have multiple sections, change the row count for each section to (number of rows for that section + 1) and make the row at 0th index to be a header. Some hand coding will be required.
Change your tableview to grouped, will require UI redesign so that the design looks similar to a plain tableview cell.
Instead of UIHeaderViewCell, You should use a UITableViewCell. Make section header height as 0 and for every 0th item in that section , display a UITableViewCell with heading on it

Show header but not footer in grouped tableView with automatic dimensions

I am trying to have headers in my grouped tableView but not footers. I am creating headers with:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "Header") as! DateHeaderTableViewHeaderFooterView
...
return headerView
}
I have setup the tableView in storyboard to use automatic dimensions for all cells and headers and footers.
I assumed because I didn't provide any footers, they would not exist however footers are being added to each section. Also all the headers and footers have a gray background.
I tried unchecking the footer automatic dimension and selecting a value however the lowest value it can accept is 1 and still the footer shows up.
How can I have headers but not footers and change the background color of the header?
I can achieve what I want using a plain tableView however the headers are pinned to the top which I am trying to avoid.
You need to implement the following method:
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude
}
For Xcode 13 + iOS 15 device
You have to set UITableView.sectionHeaderTopPadding to zero also.
if #available(iOS 15.0, *) {
tableView.sectionHeaderTopPadding = 0
}
reference: https://developer.apple.com/forums/thread/683431

UITableView Section Header Automatic Height Not Updated Properly

I am running into an issue with automatic/dynamic UITableView section header views that contain a UILabel that wraps (numberOfLines = 0). The height is not being calculated properly, especially once you scroll the table and the views are reused. Sometimes the UILabel wraps, sometimes it is truncated, sometimes one or more of the labels are not visible, and sometimes there is extra spacing between the labels. The custom view contains a vertical UIStackView with three UILabels, once of which wraps.
A complete sample app demonstrating the issue can be found at https://github.com/outerstorm/tableviewHeaderTest.
The section header heights are set to automatic in viewDidLoad with the following:
tableView.sectionHeaderHeight = UITableViewAutomaticDimension
tableView.estimatedSectionHeaderHeight = 30.0
and also have implemented the following heightForHeaderInSection just to try to get it to work:
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableViewAutomaticDimension
}
I have also tried calling setNeedsLayout() and layoutIfNeeded() at various points to no avail. Any suggestions would be greatly appreciated.
Below is a screenshot of the behavior seen in the app. The first section is cutoff and the second section is too tall:
I have faced this kind of issue recently.
I solved it by setting preferredMaxLayoutWidth of multiline labels, i.e.
Before setting the value in labels, set their preferredMaxLayoutWidth as:
self.label1.preferredMaxLayoutWidth = self.label1.frame.size.width
self.label2.preferredMaxLayoutWidth = self.label2.frame.size.width
self.label3.preferredMaxLayoutWidth = self.label3.frame.size.width
Just add estimatedHeightForHeaderInSection function and return your estimated height. It will resolve your issue. Download your modified project from here
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat
{
return 30;
}
In general
heightForHeaderInSection
always called before
viewForHeaderInSection
when using UITableViewAutomaticDimension, sectionheader height will only calculate once unless called tableview.reloadData() manually.
In the code, you change sectionheader text everytime. the height was calculate at the first time, and doesnt change automatic.
you can change setup func to:
func setup(someNum: Int) {
let text = String(repeating: "This is where the really long text goes so that it will wrap lines appropriately", count: someNum)
mainLabel.text = text
}
and pass the section index to the function
A workaround can be hold the header views in array and then return the height of view from estimated height method
for _ in 0 ..< data.count {
let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: "CustomHeaderView") as! CustomHeaderView
view.setup()
headerViews.append(view)
}
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat
{
let view = headerViews[section] as? UIView
return (view?.frame.size.height)!
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return headerViews[section] as? UIView
}
From the code's documentation:
// tableView:titleForHeaderInSection: or tableView:titleForFooterInSection: if the title is not nil.
In other words. UITableViewAutomaticDimension is only intended for use if you are providing a section title using titleForHeaderInSection or titleForFooterInSection
Add
self.label1.preferredMaxLayoutWidth = self.label1.frame.size.width
self.label1.numberoflines = 0;
self.label1.linebreakmode = NSLineBreakByWordWrapping;
in awakeFromNib method
or
Kindly check this once

Renaming header of section of uitableview

How can i rename the title of section header on uitableviewcontroller outside of titleForHeaderInSection ?
So as per the question statement update title without reloading or delegates just using the label reference for updating the title for section.
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView() //set the frame accordingly
let label = UILabel() //set the frame accordingly
//make it global and use it reference for updating the title of the section
view.addSubview(label)
return view
}
I am not using Xcode so please validate just writing code roughly
// If only section 2 has a header
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return section == 2 ? updateHeader(section) : nil
}
func updateHeader(section: Int) -> CustomHeader {
let header = (tableView.footerViewForSection(section) ?? tableView.dequeueReusableHeaderFooterViewWithIdentifier("customHeader")) as! CustomHeader
// Set up your header
return header
}
// Change text in header
let header = updateHeader(2).customLabel.text = "Your custom text"
Just a small example. Be aware that when the tableview gets reloaded, it will change back to your default setup of your header. So be sure you handle that within your own code.
You can do it without using titleForHeaderInSection
Make dynamic array 1st object for header custom cell then objects for tableview cell... and so on
Draft custom cell for header
While screen appear use cellForRowAtIndexPath with condition as per header custom cell and objects for table view
At particular event change array value for header custom cell then use reloadRowsAtIndexPaths()
So it will reload only index given in reloadRowsAtIndexPaths(), no need for reloadData().

Resources