Ungrouping UITableView Section Header when Header is top of view - ios

I am currently working on a UITableViewController. My current implementation includes a header view (white view), a UITableView section header (red view) and tableview (grey). Currently the TableView style is grouped so the Section Header scrolls with the TableView when scrolling up to shrink the header view.
I am trying to keep the Section Header at the top of the view when the header view goes offscreen, and allow the UITableViewCells to scroll under the Section Header. Currently the tableview cannot scroll up once the Section Header reaches the top of the view. Any suggestions would be super helpful
Current Code:
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 106.0
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view1 = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 106.0))
view1.backgroundColor = UIColor.red
return view1
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80.0
}
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
let maxOffset = (scrollView.contentSize.height - scrollView.frame.size.height)
if scrollView.contentOffset.y >= maxOffset {
scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x, y: maxOffset)
}
if scrollView.contentOffset.y >= 35.0 {
scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x, y: 35.0)
}
}
}

I am not completely sure I follow what you are trying to accomplish, but please allow me to attempt to infer and feel free to provide clarifications. I like the table view practice :)
As I understand it:
1) You want the white view, the red view, and the table cells beneath the red view to scroll upward from the default position
2) You want the white view to scroll out of visibility
3) You want the red view to float at the top while the cells scroll beneath it
4) You currently have the white view as a table header, the red view as a section header, and the gray area are table cells
Sounds like a cool app!
Why not use 2 table sections:
1) Drop the table header
2) Set the white view in cell 0 section 0 of the table view.
3) Set table delegate methods so section 0 will have a nil header with 0 height
3.5) Also set the table delegate methods so section 1 will be your main table
4) Use UITableViewStylePlain so section 1 header will float at the top
Is this the desired functionality?

I was able to replicate your desired behaviour without using the scrollViewDidScroll method, however the headerView will no longer scroll with the tableView. You could use the scrollViewDidScroll method to change the height/origin of the headerView when the content offset is less than zero.
class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var headerView: UIView?
#IBOutlet weak var tableView: UITableView? {
didSet {
tableView?.dataSource = self
tableView?.delegate = self
}
}
func numberOfSections(in tableView: UITableView) -> Int { return 1 }
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 10 }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell.backgroundColor = UIColor.gray;
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 50))
header.backgroundColor = UIColor.red
return header
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 100 }
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 60 }
}

Related

Self sizing cells for nested table and collection Views

I'm trying to build a table view, one of the cells in this TableView is a tabs widget.
so I'm creating this tab widget as a CollectionView. the cells of the collectionView have different subViews and each cell has it's own size.
what I'm trying to achieve is Self-sizing cells in the collectionView, but it is not working.
I'll provide you with the way I used so I can get your help.
//MARK: TableView
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DetailsTabs", for: indexPath) as! DetailsTabs /*this cell has 2 collectionViews. The first collectionView is the tabs and the second collectionView is the content that should be diplayed. I gave the first collectionView a fixed height, trailing leading and top. the second collectionView has trailing, leading bottom, and top to the first collectionView*/
cell.postDetail = postDetail
cell.widgets = self.Template
cell.parentController = self
cell.Shownavigationbar = self.Shownavigationbar
return cell
}
//MARK: DetailsTabs Class
override func awakeFromNib() {
//code to setUp the collectionViews
//pagesLayout is the UICollectionViewFlowLayout for the second collectionView
pagesLayout.estimatedItemSize = CGSize(width: UIScreen.main.bounds.width, height: 1)
}
//MARK: IN collectionView Cells I added this function:
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var frame = layoutAttributes.frame
frame.size.height = ceil(size.height)
layoutAttributes.frame = frame
return layoutAttributes
}
note: the content of the collectionView cells might be webView or tableview.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
you should use UITableViewAutomaticDimension in estimatedHeightForRowAtIndexPath
hope this is working fine for you...!

How do I get the height of a dynamically sized section header in UITableView?

I have a UITableView, it uses a custom UIView as the section header view. Code like so:
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "ECStartTableHeaderView") as! ECStartTableHeaderView
return headerView
}
I have UITableViewAutomaticDimension for the height on the header. I need to find out what this height is in my code. How can I get this header height?
I think you have to ensure your header layout finished first, so you can get actual height.
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let height = view.frame.height
}
You can take out the Height of the Header View Just Like.
if let headerView = tableView.tableHeaderView {
height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
}

How to add separators between UITableView sections?

I'm implementing a tableview, which has 3 sections(section count remain static) and each section contain several rows.
Behaviour 1: Add section header to only the third section.
How did I achieve:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 2 {
//create and return header view
}
return UIView(frame: CGRect(x: 0, y:0, width: tableView.width, height: UIScreen.main.scale))
}
Behaviour 2: TableViewCells shouldn't have separator. But, Sections should be separated with a thin line. (similar to tableviewcell separator)
What did I try:
Add a one pixel height, tableView width UIView, with all required properties set(color, etc) and add it as a sub-view to the section header view's
Add drop shadow with CGPoint(0,1) to the section header views
None of them worked out.
How did I achieve this:
Find last cell in every section,
Create an UIView with 1px height, tableView's width and add it as a subview to the last cell
Though this seem to work. I feel, there must be a better way of doing this, rather than adding line to bottom of every section's last tableView cell. Does anyone know a better way of implementing such behaviour?
Set the Style of the Table View to Grouped:
Using heightForHeaderInSection method of UITableViewDelegate and return section wise height as per you want
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 2 {
return 1 // return height as per your requirement
}
return 0 // return height as per your requirement
}
This should work for adding "section separator lines" and a head view only on the 3rd section:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
// if it's the 3rd section, return a view with desired content for the section header
if section == 2 {
let v = UIView(frame: CGRect(x: 0, y:0, width: tableView.frame.width, height: 30))
v.backgroundColor = .yellow
let label = UILabel(frame: CGRect(x: 8.0, y: 4.0, width: v.bounds.size.width - 16.0, height: v.bounds.size.height - 8.0))
label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
label.text = "Header for Third Section"
v.addSubview(label)
return v
}
// not the 3rd section, so don't return a view
return nil
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
// if it's the 3rd section
if section == 2 {
return 30
}
return 0
}
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
// UIView with darkGray background for section-separators as Section Footer
let v = UIView(frame: CGRect(x: 0, y:0, width: tableView.frame.width, height: 1))
v.backgroundColor = .darkGray
return v
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
// Section Footer height
return 1.0
}
Simple solution of this Just add the footer view inside the tableview.Set height of the footer view to be a specific height.
Swift:
public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let view = UIView()
view.backgroundColor = UIColor.grey
return view
}
public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 10
}

adding some margin below section header text of a UITableView

I have styled the header text:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as? TableViewCell
cell!.titleLabel!.text = sections[indexPath.section].objects[indexPath.row].name
cell!.datetimeLabel!.text = "on " + sections[indexPath.section].objects[indexPath.row].date
return cell!
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 100
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section].heading // Open Events
}
And I would like to add some margin / padding below it before the section of the table cells start. I have added some margin / padding top with heightForHeaderInSection. Any way to add some top / bottom margin / padding?
titleForHeaderInSection method will have the default section header frame. You can use viewForHeaderInSection method to customize it. Try this code :
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerFrame = tableView.frame
let title = UILabel()
title.frame = CGRectMake(10, 10, headerFrame.size.width-20, 20) //width equals to parent view with 10 left and right margin
title.font = title.font.fontWithSize(14)
title.text = self.tableView(tableView, titleForHeaderInSection: section) //This will take title of section from 'titleForHeaderInSection' method or you can write directly
title.textColor = UIColor.blueColor()
let headerView:UIView = UIView(frame: CGRectMake(0, 0, headerFrame.size.width, headerFrame.size.height))
headerView.addSubview(title)
return headerView
}
Hope this will work for you.
use viewForHeaderInSection: and return a view with a label with the correct spacing below it instead of using the default header in titleForHeaderInSection
see this answer for an example

Positioning a custom UILabel inside a UITableView footer view

I have a UITableViewController and I am setting the footerView via
self.tableView.tableFooterView = FooterView()
In the class FooterView I have added a label via
self.addSubView(label)
I noticed the following.
The footerView is positioning on top of the tableView
The label is inside the footerview
My questions are
When I set the Frame of the footerView as (0, 0, 100, 100) it seems to be overlapping on the tableView. How do I position the footer at the bottom of the tableView ?
When a label is added via addSubView() of the footer. Is it positioning related to the footerView or the tableView?
FooterView's default height is 44.If you don't set your footerView's height for more and then set your label with height of 100 then it overlaps.
It is positioning with the footerView.
You can set the footerView's height by using UITableViewDelegate method.Below is the way to achieve what you wanted.Footer view only at the bottom of table view.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView .dequeueReusableCellWithIdentifier("cellIdentifier") as! UITableViewCell
cell.textLabel?.text = "trial"
return cell
}
func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
if section == 1{
return 100
}
return 0
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2 //The number you needed + 1
}
func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
if section == 1{
return FooterView()
}
return nil
}
Delete this line
self.tableView.tableFooterView = FooterView()

Resources