How to make Automatic Height Header in UITableView? - swift

Hello i try to make expand/collapse using UITableView but i have problem with Header. I have try all tutorial but not working. This is my sample code:
import UIKit
import SafariServices
class AboutViewController: UIViewController {
#IBOutlet weak var tblView: UITableView!
var data = [
DataModal(headerName: "Apa itu Brevir?", subType: ["Brevir adalah bla..bla"], isExpandable: false),
DataModal(headerName: "Apa isi Brevir?", subType: ["Garis besarnya adalah bla..bla..blaa...bla..bla..blaa...bla..bla..blaa...bla..bla..blaa"], isExpandable: false),
DataModal(headerName: "Mengapa 7x Sehari?", subType: ["Tujuh Kali dalam bla..bla"], isExpandable: false),
DataModal(headerName: "Ibadat apa saja yang termaksud dalam 7x sehari tersebut?", subType: ["a. Ibadat Pembukaan", "b. Ibadat Pembukaan", "c. Ibadat Pembukaan", "d. Ibadat Pembukaan", "e. Ibadat Pembukaan", "f. Ibadat Pembukaan", "g. Ibadat Pembukaan"], isExpandable: false)]
override func viewDidLoad() {
super.viewDidLoad()
tblView.tableFooterView = UIView()
}
}
extension AboutViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = HeaderView(frame: CGRect(x: 10, y: 10, width: tblView.frame.size.width - 20, height: 40))
headerView.delegate = self
headerView.secIndex = section
headerView.btn.setTitle(data[section].headerName, for: .normal)
return headerView
}
func numberOfSections(in tableView: UITableView) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if data[section].isExpandable {
return data[section].subType.count
} else {
return Int(UITableView.automaticDimension)
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.numberOfLines = 0
cell.textLabel?.text = data[indexPath.section].subType[indexPath.row]
return cell
}
override func viewWillAppear(_ animated: Bool) {
tblView.estimatedSectionHeaderHeight = 40
tblView.sectionHeaderHeight = UITableView.automaticDimension
}
}
extension AboutViewController: HeaderDelegate {
func callHeader(idx: Int) {
data[idx].isExpandable = !data[idx].isExpandable
tblView.reloadSections([idx], with: .automatic)
}
}

Since you are using button, it won't expand automatically.
Use a label instead and set its numberOfLines = 0.
Later add Button over it.
Also implement table view sections delegate/dataSource methods:
heightForHeaderInSection return 50 //minimum height
estimateHeightForHeaderSection return UITableView.automaticDimension // automatic height

Try this:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let board = UIView()
let headerView = HeaderView(frame: CGRect(x: 10, y: 10, width: tablView.frame.size.width - 20, height: 40)
headerView.delegate = self
headerView.secIndex = section
headerView.btn.setTitle(data[section].headerName, for: .normal)
board.addSubview(headerView)
return board
}

First you have to calculate height and use "UITableViewDelegate" methods as follows
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int)
-> CGFloat {
return ( your calculated height for header)
}

Related

Multiple headerview in tableview in swift

I want to create 3 headers in the tableview given in the images and 8 students in each row, my code is as follows
Screenshot of the example
class ViewController: UIViewController {
var schoolOfList: [Any] = [
[["school": ["VIP", "Bright International", "Motherland"]],
[["student1": ["Chirag", "Akshay", "Shailesh", "Vishal", "Mehul", "Vinod", "Mukesh", "Darshan"]],
["student2": ["Manjari", "Kairav", "Abhimanyu", "Akshara", "Arohi", "Neel", "Naksh", "Naman"]],
["student3": ["Paritosh", "Anuj", "Kavya", "Samar", "Vanraj", "Kinjal", "Anupama", "Riyan"]]]]]
#IBOutlet weak var mytableview : UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ViewController:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> (Int) {
return schoolOfList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for:indexPath)
cell.textLabel?.text = schoolOfList["school"] as! [String]indexPath.row
return cell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerview = UIView(frame: CGRect(x:0,y:0,width:self.mytableview.frame.width,height:50))
headerview.backgroundColor = .green
let lable = UILabel(frame: CGRect(x:0,y:0,width:self.mytableview.frame.width,height:50))
lable.textAlignment = .center
lable.text = (schoolOfList["school"]as!String)
headerview.addSubview(lable)
return headerview
}

How to add corner radius and a background to a whole section including its header and cells in UI Table View

How do I add corner radius and background to both the section header and its cell together like in the iOS weather app?
My table view data source and delegate-
extension HomeViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
10
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: HourlyForecastViewTableViewCell.identifier) else { return UITableViewCell() }
cell.layer.backgroundColor = UIColor.blue.cgColor
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
200
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return HourlyForecastHeaderView()
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
}
You can tryout this below code, here I just explained how to use UIRectCorner to apply corner radius to the specific edge.
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let kCellId = "kCellId"
var lCell = tableView.dequeueReusableCell(withIdentifier: kCellId)
if lCell == nil {
lCell = UITableViewCell(style: .default, reuseIdentifier: kCellId)
lCell?.textLabel?.text = "Row - \(indexPath.row)"
}
lCell?.backgroundColor = .orange
return lCell!
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let kHeaderId = "kHeaderId"
var header = tableView.dequeueReusableHeaderFooterView(withIdentifier: kHeaderId)
if header == nil {
header = HeaderView(reuseIdentifier: kHeaderId)
header?.frame = CGRect(origin: .zero, size: CGSize(width: tableView.bounds.size.width, height: 35))
header?.tintColor = .orange
let titleLabel = UILabel()
titleLabel.text = "Section - \(section)"
titleLabel.sizeToFit()
titleLabel.frame = CGRect(origin: CGPoint(x: 20, y: 0), size: CGSize(width: tableView.bounds.size.width-20, height: 35))
header?.addSubview(titleLabel)
}
return header
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
view.applyCorners(to: [.topLeft, .topRight], with: view.bounds)
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let isLastCell = tableView.numberOfRows(inSection: indexPath.section)-1 == indexPath.row
if isLastCell {
cell.applyCorners(to: [.bottomLeft, .bottomRight], with: cell.bounds)
}else{
cell.noCorners()
}
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
50
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
35
}
}
class HeaderView: UITableViewHeaderFooterView {
}
extension UIView {
func noCorners() {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.allCorners], cornerRadii: CGSize(width: 0, height: 0))
let shape = CAShapeLayer()
shape.path = path.cgPath
layer.mask = shape
}
func applyCorners(to: UIRectCorner, with rect: CGRect) {
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: to, cornerRadii: CGSize(width: 10, height: 10))
let shape = CAShapeLayer()
shape.path = path.cgPath
layer.mask = shape
}
}

Need help adding a section to TableViewController array

I want to add a third section to the this UITableViewController. I've tried this :
var listOfCauses:[[String]] = [
["Causes", "", ""],
["Cause 1" , "small descript", "links"],
["Cause 2", "small descript", "links"]
]
When I run the application table view the links subheading doesn't show. How do I fix this? Thanks in advance! Here is my full code for the UITableViewController below:
import UIKit
class CausesTableViewController: UITableViewController {
// I want to add the third section to this array
var listOfCauses:[[String]] = [
["Causes", ""],
["Cause 1" , "small descript"],
["Cause 2", "small descript"]
]
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
// return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listOfCauses.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell( withIdentifier: "cellIdentifier")
if cell == nil {
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cellIdentifier")
}
cell?.textLabel?.font = UIFont.boldSystemFont(ofSize: 23)
cell!.textLabel!.text = listOfCauses[indexPath.row][0]
cell?.detailTextLabel?.textColor = .darkGray
cell?.detailTextLabel?.font = UIFont.systemFont(ofSize: 17.0)
cell!.detailTextLabel!.text = listOfCauses[indexPath.row][1]
return cell!
}
}
Update these methods
override func numberOfSections(in tableView: UITableView) -> Int {
// return the number of sections
return listOfCauses.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listOfCauses[section].count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell( withIdentifier: "cellIdentifier")
if cell == nil {
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cellIdentifier")
}
cell?.textLabel?.font = UIFont.boldSystemFont(ofSize: 23)
cell!.textLabel!.text = listOfCauses[indexPath.section][indexPath.row]
cell?.detailTextLabel?.textColor = .darkGray
cell?.detailTextLabel?.font = UIFont.systemFont(ofSize: 17.0)
cell!.detailTextLabel!.text = listOfCauses[indexPath.row][1]
return cell!
}

How to adjust or remove grouped tableView Header size

I have a grouped tableView and it has four sections , I would like to reduce the size of the header section in some section headers and I would like to remove the section header in other sections. I have tried solutions in most questions similar to mine but nothing works.
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
tableView.separatorStyle = .none
tableView.clipsToBounds = true
self.tableView.sectionHeaderHeight = UITableView.automaticDimension
self.tableView.estimatedSectionHeaderHeight = 200
self.registerTableViewCells()
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
(view as? UITableViewHeaderFooterView)?.textLabel?.textColor = UIColor.gray
if section == 0 {
(view as? UITableViewHeaderFooterView)?.contentView.backgroundColor = UIColor.white
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
switch section {
case 0:
let headerView = self.tableView.dequeueReusableHeaderFooterView(withIdentifier: "\(TestHeaderView.self)" ) as! TestHeaderView
return headerView
case 1, 2, 3 :
return nil
default:
return nil
}
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section {
case 0, 1, 2:
return nil
case 3:
return " some title"
default:
return nil
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
switch section {
case 0:
return UITableView.automaticDimension
case 1:
return CGFloat(10.0)
case 2:
return CGFloat(10.0)
case 3:
return CGFloat(43.0)
default:
return 0
}
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return CGFloat.leastNonzeroMagnitude
}
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
return 250
}
I would like to have the tableView section headers to have specific heights as highlighted in heightForHeaderInSection.
You don't seem to be setting the dataSource or tableView delegates (unless it is happening in some part of the code not shown). These will be needed for this (and most dynamic tableview functions).
For headers/footers that won't change size it is reasonably straightforward to create the them - return the view you want to use from tableView(_:viewForHeaderInSection:) and the height you want in tableView(_:heightForHeaderInSection:). Set these to nil and 0 respectively to hide a header.
A simple example that provides different size headers for section 0 & 2, no header for section 1, and hides all footers. I've set the headers background colours to allow them to stand out, and not provided the other methods such as cellForRowAt. Note the height is controlled by the height method, not the frame height.
class MyVC1: UIViewController {
var mapa: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
title = "Dummy TableView"
view.backgroundColor = .lightGray
let tableView = UITableView(frame: CGRect(x:50, y:100, width: 300, height: 680), style: .grouped)
view.addSubview(tableView)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.dataSource = self
tableView.delegate = self
}
}
//add dataSource and delegate support
extension MyVC1: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
5
}
func numberOfSections(in tableView: UITableView) -> Int {
3
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
switch section {
case 0:
let v = UIView(frame: CGRect(x: 10, y: 10, width: tableView.frame.width - 20, height: 90))
v.backgroundColor = .purple
return v
case 1: return nil
case 2:
let v = UIView(frame: CGRect(x: 10, y: 10, width: tableView.frame.width - 20, height: 20))
v.backgroundColor = .magenta
return v
default: fatalError()
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
switch section {
case 0: return CGFloat(60)
case 1: return CGFloat(0)
case 2: return CGFloat(100)
default: fatalError()
}
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
nil
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
0
}
}
have you added UITableViewdelegate and UITableViewDataSource ?
or try this self.tableView.estimatedSectionHeaderHeight = 80

Retrieving the tag from a cell in row in a section [duplicate]

This question already has answers here:
Cannot assign a value of type '[(String)]' to a value of type 'String!'?
(2 answers)
Closed 4 years ago.
enter image description hereI have a tableView with a custom cell. I have added a button to this cell (I have created a UITableViewCell subclass for this cell).
My data is distributed in 3 sections and rows. I want to be able to press the button at any row and pass that row content to the next page. I was able to do all this when I did not have any sections. Here is my code:
import UIKit
class ViewController: UIViewController,UITableViewDataSource {
var menu = ["a", "b", "c"]
#IBOutlet weak var tblview: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// print(menu[section].count)
return menu.count
}
func numberOfSections(in tableView: UITableView) -> Int {
//print(menu.count)
return menu.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! AddItemClassCell
cell.textLabel?.text = menu[indexPath.row]
cell.addBtn.tag = indexPath.row
cell.addBtn.addTarget(self, action: #selector(BtnClicked), for: .touchUpInside)
return cell
}
#objc private func BtnClicked(sender: UIButton) {
let vc = self.storyboard!.instantiateViewController(withIdentifier: "NextVC") as! NextVC
vc.loadViewIfNeeded()
//vc.lb.text = menu[sender.indexPath.section][sender.indexPath.row]
vc.lb.text = menu[sender.tag]
self.navigationController?.pushViewController(vc, animated: true)
}
}
Here is the cell class:
import UIKit
class AddItemClassCell: UITableViewCell {
#IBOutlet weak var addBtn: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Cannot assign value of type '[String]' to type 'String?'
If your are using a button on a cell you can use
import UIKit
struct Menu {
let title: String
let innerMenu: [String]
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var myTV: UITableView!
let menuArr = [
Menu(title: "1", innerMenu: ["a", "b", "c"]),
Menu(title: "2", innerMenu: ["d", "e", "f"]),
Menu(title: "3", innerMenu: ["g", "h", "i"]),
]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
myTV.delegate = self
myTV.dataSource = self
myTV.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return menuArr.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuArr[section].innerMenu.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let title = UILabel()
title.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 50)
title.text = menuArr[section].title
return title
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : MyCell! = tableView.dequeueReusableCell( withIdentifier: "MyCell") as? MyCell
cell.lbl_Title.text = menuArr[indexPath.section].innerMenu[indexPath.row]
cell.btn_Click.addTarget(self, action: #selector(BtnClicked), for: .touchUpInside)
return cell as MyCell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
#objc func BtnClicked(sender:UIButton!){
let view = sender.superview!
let cell = view.superview as! MyCell
let indexPath = myTV.indexPath(for: cell)
print("\(indexPath?.section) - \(indexPath?.row)")
}
}