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
Related
I have a problem that I couldn't find any appropriate solution.
I have a tableView with custom cells which holds a textView inside.
also I have a blank grey footer for the section.
whenever I click on the textView and the keyboard pops up the footer in that section goes up and hides behind the textView field.
I don't know how to make that footer sticky so it won't move when the keyboard pops.
if anyone have a solution it will be great!
thank you!
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
if section == 0 {
let footerView = UIView()
footerView.backgroundColor = .red
return footerView
}else {
return UIView()
}
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 8
}
Set your tableView as grouped give height to the tableview footer and tableView Header in the tableview header,footer height functions.
If you are not using tableview header the set the height of the header to .leastNormalMagnitude .
This is the way to make the tableView Footer Static.
We're want to do two changes to our search results.
Change the Collection View Controller to a Table View Controller
Have only the second section header show and have it scroll away inline. In other words, don't be sticky and don't stay at the top.
In regards to changing the Collection View Controller to a Table View Controller. This involves changing the section headers from a UICollectionReusableView subclass to something else. Normally, the change would be to using a UITableViewHeaderFooterView.
In regards to making the second section header scroll on up inline and out of sight and thus not be sticky, there's an issue to my solution.
To make it non-sticky, I changed the tableview to be UITableViewStyleGrouped. This causes a look for the second section that is different than what we have now. We would like it back to how it looks now.
Here's what we have in the App Store now:
Here's what we have when trying the UITableViewStyleGrouped approach and other changes:
Notice the extra gray above the "Other cars..." section header? I figure I can probably solve the rounded corners and insets via a subclass of the UITableViewHeaderFooterView. However, it's not clear how to handle the extra space above the section.
Code:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.estimatedRowHeight = 800
self.tableView.rowHeight = UITableViewAutomaticDimension
let nib = UINib(nibName: "SearchResultsOtherCarsHeader", bundle: nil)
tableView.register(nib, forHeaderFooterViewReuseIdentifier: "SearchResultsOtherCarsHeader")
:
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section != 1 {
return 0
}
return 30
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section != 1 {
return nil
}
let searchResultsOtherCarsHeaderView = self.tableView.dequeueReusableHeaderFooterView(withIdentifier: "SearchResultsOtherCarsHeader") as! SearchResultsOtherCars
return searchResultsOtherCarsHeaderView
}
How to get rid of the extra gray space above the section header?
The solution:
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.01
}
This solution was inspired by the comment made by #maddy and iPhone UITableView : How to remove the spacing between sections in group style table?
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
Im trying to implement a tableview that has cells with a product image on the left side and a listing of various product details such as price, title, etc. to the right of the image, however, I have been having trouble with setting up the appropriate spacing/padding between the cells. I want each cell to have some white space between them. Here is an image showing what i have so far, and what the issue is.
TableView
I am using a stackview as a container for the labels with the product details, and am implementing the dynamic row height feature:
self.tableView.rowHeight = UITableViewAutomaticDimension
Everything seems to work great except wajjhen the stackview height is smaller than the imageview height. I can't get the spacing to show in that scenario. I have tried everything for the past 2 days, and it is driving me crazy. Take it easy on me guys as I am an Android guy :)
All I want is for the I want the separators of tableview cells to have a bit of space between either the top and bottom of the imageview or the stackview(whichever is taller/higher).
I have attached a SS of the storyboard to show the layouts and constraints. Please let me know if any more information is need.
Storyboard
for adding consitent spacing to your cell better way is to treat your each item as a section because you can set spacing easily between sections by creating a header view between section.
So logically if you have 10 objects than you will be having 10 section with each section have only one row.
1.Each section with only one row
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
2.Number of section is equal to count array of items
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return array.count
}
3.Set Hieght for spacing/header view
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 10
}
4.create your header view and customise it
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if let view = view as? UITableViewHeaderFooterView{
view.backgroundView?.backgroundColor = UIColor.clearColor()
}
}
Assuming that you have no problem with setting the appropriate height for each cell (if you have, you might want to check this Q&A), I suggest to let each cell on a section instead adding them in the same one.
Technique:
By default, if you are not implementing numberOfSections(in:), it returns 1. You should:
implement it and let it returns the number of array data source -for example- (instead of doing it in tableView(_:numberOfRowsInSection:)).
Let tableView(_:numberOfRowsInSection:) returns 1. Each section will has only one cell.
After that, the trick is to add a header view for the sections (with a clear background color) with desired height, the height will be the margin between the section (cells in your case). You should achieve this by implementing:
tableView(:viewForHeaderInSection:) and tableView(:heightForHeaderInSection:).
The code will be similar to:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// ...
// MARK:- UITableViewDataSource
func numberOfSections(in tableView: UITableView) -> Int {
return dataSource.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-ID")
// note that you should read from 'indexPath.section' instead of 'indexPath.row'
let currentObejct = dataSource[indexPath.section]
}
// MARK:- UITableViewDelegate
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
// here, you can customize the header
// or your case want to let it clear...
let margin = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 20.0))
margin.backgroundColor = UIColor.clear
return margin
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 20.0
}
// ...
}
Hope this helped.
You can try giving the Fruit Image a top and a bottom constraint but they must be >= so it doesn't mess your auto layout
And your constraints will probably look like this
3 days later, I finally found a solution I am content with, albeit it is quite janky, but at this point(3 days of dealing with this issue), I don;t really care. I am posting my solutuion in case it helps anyone in the future.
I ended up pinning a view to the tableviewcell with a minimum height of 130 to contain the imageview and stackview. Since I know the minimum height of the tableviewcells is 120, 130 gave a padding of 5 on the top and bottom. I attached the screenshot of my storyboard:
Storyboard
TableView
I'm trying to apply a size on my UITableView headerView but it seems like the first section header always is a bit smaller than the rest section headerViews. I've said the constraints for the UITableView so it should be fine. How come the first section is smaller?
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return ""
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 20
}
This behavior occurs when using a Grouped UITableView. The section header height appears shorter for the first section header, because it doesn't have a footer above of it. However, every section header after the first one, does have a footer directly above it. The footers have a default height, which is contributing to the overall height appearance of the section header. Therefore, set the section footer heights so the space between the group sections will have the same visual height.
override func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return CGFloat.min
}
We use CGFloat.min instead of 0, because returning 0 will cause the footer to return a default height.