I am trying to create custom section header with dynamic height. I have created a very simplified version of my app where I am displaying a square image as table section header. The image height is the same as the screen width. The tableView has to be dynamic because the image height changes with screen width. Even though the app works, I could not be able to get rid of the constraint warnings. It is a very simple app and I have no idea why it is throwing me constraint errors. It seems like the the 1:1 ratio on the image constraint is the root of the problem. I have attached the constraints of my xib file, code and output screenshot below.
Xib Constraint
Simulator Output
class ViewController: UIViewController {
#IBOutlet weak var myTableView: UITableView!
var xibRef: CustomHeaderView!
var numberOfSection = 3
override func viewDidLoad() {
super.viewDidLoad()
myTableView.delegate = self
myTableView.dataSource = self
// Register Xib
let nib = UINib(nibName: "CustomHeaderView", bundle: nil)
self.xibRef = nib.instantiateWithOwner(self, options: nil)[0] as? CustomHeaderView
self.myTableView.registerNib(nib, forHeaderFooterViewReuseIdentifier: "CustomHeaderView")
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath)
cell.textLabel!.text = "section \(indexPath.section) row \(indexPath.row)"
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return numberOfSection
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
return view.frame.size.width
}
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableHeaderFooterViewWithIdentifier("CustomHeaderView") as! CustomHeaderView
return cell
}
}
Related
Well, I am trying to make the headers of UITableView compatible with iPhone X Landscape where I want background colors of Header should expand to edge.
I have seen the WWDC video to do that where they said to apply color on backgroundView but in my case it's always nil.
Here is my code and also link to demo of it.
extension ViewController:UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return 5
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: String.init(describing: HVTableViewCell.self)) as! HVTableViewCell
return cell
}
}
extension ViewController:UITableViewDelegate{
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 60.0
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 44.0
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: String.init(describing: HVTableViewHeaderFooterView.self)) as? HVTableViewHeaderFooterView{
if let backgroundView = headerView.backgroundView{
backgroundView.backgroundColor = UIColor.red
}else{
print("Failed")
}
return headerView
}else{
return nil
}
}
}
class ViewController: UIViewController {
#IBOutlet weak var tblReference: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.tblReference.register(UINib.init(nibName: String.init(describing: HVTableViewCell.self), bundle: nil), forCellReuseIdentifier: String.init(describing: HVTableViewCell.self))
self.tblReference.register(UINib.init(nibName: String.init(describing: HVTableViewHeaderFooterView.self), bundle: nil), forHeaderFooterViewReuseIdentifier: String.init(describing: HVTableViewHeaderFooterView.self))
self.tblReference.delegate = self
self.tblReference.dataSource = self
self.tblReference.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is the screenshot of the issue.
Thanks in advance.
I found another way to do it.
We can set the background color of Layer of HeaderView.
// HeaderView Class
self.layer.backgroundColor = UIColor.red.cgColor
Here is the link of working code.
Hope it helps to others as well.
I have a UItableview cell that is contain a UItableview, I need to make height of that cell equal to height of it's child UItableview.
Image below explain what I need to do.
First see my ViewController,which has one tableview(tblview) and UITableViewCell(CustomTableViewCell) ,
class ViewController: UIViewController {
#IBOutlet var tblview:UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.tblview.delegate = self
self.tblview.dataSource = self
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomTableViewCell.identifier) as! CustomTableViewCell
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
}
Then see my CustomTableViewCell which has one table view and one label in a cell.See,
class CustomTableViewCell: UITableViewCell {
static let identifier = "CustomTableViewCell"
#IBOutlet var tblviewCell:UITableView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.tblviewCell.delegate = self
self.tblviewCell.dataSource = self
tblviewCell.isScrollEnabled = false
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
let heighToReturn = self.tblviewCell.contentSize.height + 20 // upper and down space
return CGSize(width: self.tblviewCell.contentSize.width, height: heighToReturn)
}
}
extension CustomTableViewCell:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: customCell.identifier) as! customCell
cell.lblname?.text = "Vikas"
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
}
class customCell: UITableViewCell {
static let identifier = "customCell"
#IBOutlet weak var lblname :UILabel?
}
So, if you give tableview content size height in systemLayoutSizeFitting method then problem will be solve.
I hope this will help.
Here's how to do table header cells. The cell needs to be prototyped in the storyboard and subclassed (if needs to be configured). Then override the following funcs in the table view delegate. Alternatively, you can generate a view on the fly and return that from viewForHeaderInSection.
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 150
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableCell(withIdentifier: "ConferenceHeaderCell") as! ConferenceDetailHeaderCell
// configure cell
return headerCell
}
For the cells themselves, it's very similar:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ConferenceUserCell", for: indexPath) as! ConferenceDetail_TVCell
// Configure the cell...
return cell
}
and depending, you may to implement 'heightForRowAtIndexPath'
I have a tableview that is added programatically below that I want to hook up the delegate and dataSource to an external class. The code looks right however the tableview gets added to the view without getting the cell layout from the external class.
let tableView: UITableView = {
let dataService = ActivityDataService()
let tb = UITableView()
tb.tableHeaderView = nil
tb.tableFooterView = nil
tb.rowHeight = 50
tb.estimatedRowHeight = 50
tb.dataSource = dataService
tb.delegate = dataService
tb.register(ProfileActivitySubCell.self, forCellReuseIdentifier: "tableCell")
return tb
}()
Here is the activity service class:
class ActivityDataService: NSObject, UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! ProfileActivitySubCell
return cell
}
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
return 0
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
}
Thanks
When using a UITableView thats not in a storyboard or similar you need to register the cell with an identifier.
Depending on your UITableViewCell (if its a subclass and/or if you are using nibs or not)
You could use one of these methods:
open func register(_ nib: UINib?, forCellReuseIdentifier identifier: String)
open func register(_ cellClass: Swift.AnyClass?, forCellReuseIdentifier identifier: String)
Which is methods of UITableView
In your case probably something like this:
tb.register(ProfileActivitySubCell.classForCoder(), forCellReuseIdentifier: "tableCell")
1) Refactor the table view data source methods to a separate class
class IceCreamListDataSource: NSObject, UITableViewDataSource
{
// MARK: - Table view data source
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 5
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("IceCreamListCell", forIndexPath: indexPath)
return cell
}
}
2) In your controller class do this-:
class IceCreamListViewController: UITableViewController
{
let dataSource = IceCreamListDataSource()
// MARK: - View lifecycle
override func viewDidLoad()
{
super.viewDidLoad()
tableView.dataSource = dataSource
}
}
I managed to solve the issue. As the tableView was inside a collection view I had to use a storyboard object outlet. Finally inside the collection view cell I had to set the delegate and dataSource to the newly created object.
cell.tableView.dataSource = dataService
cell.tableView.delegate = dataService
I have an imageView in my custom table view cell. I have multiple images copied to Xcode.
Now I need to display these images in the tableview cell. I have decalared a leaderImage variable in which I have given the image names.
How can I achieve this?
This is what I have:
var leaderImage : [String]!
override func viewDidLoad() {
self.leadername = ["Oomen Chandy","PC.George","Veena George","M.Mukesh"]
self.areaName = ["Puthupally","Poonjar","Thrissur","Kollam"]
self.approvalrate = ["98%","94%","88%","95%"]
self.leaderImage = ["rahul","Anil","Manu",]
leadTableSetup()
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func leadTableSetup(){
LeadTableView.delegate = self
LeadTableView.dataSource = self
self.LeadTableView.register(UINib(nibName: "LeaderBoardTableViewCell", bundle: nil), forCellReuseIdentifier: "leadCell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return leadername.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "leadCell") as! LeaderBoardTableViewCell
cell.leaderNameLbl.text = leadername[indexPath.row]
cell.areaLbl.text = areaName[indexPath.row]
cell.approvalLabel.text = approvalrate[indexPath.row]
cell.imageView = leaderImage[indexPath.row]
return cell
}
In cell cellForRowAt method
cell.imageView.image = UIImage(named: leaderImage[indexPath.row])
In your self.leadername contains 5 element but rest of all your array contains 4 or 3 element that's why you have problem occur.
To avoid Crash
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return leaderImage.count
}
Since I use xCode 6 beta 5 UITableViews with nib files for custom cells shows only a small stripe of the cell on the left and the rest is grey. When I open up the View Debugger it says that there are thousands of _UITableViewCellSeperatorViews in my TableView.
Here is the class of the TableViewController
override func viewDidLoad() {
super.viewDidLoad()
let nib = UINib(nibName: "TestTableViewCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "newTestCell")
}
override func numberOfSectionsInTableView(tableView: UITableView!) -> Int {
return 1
}
override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let cell = tableView.dequeueReusableCellWithIdentifier("newTestCell", forIndexPath: indexPath) as TestTableViewCell
cell.loadData("Test")
return cell
}
Here is the class of the cell:
#IBOutlet weak var someLabel: UILabel!
func loadData(text: String) {
someLabel.text = text
}
Now I've got a picture of the TableView in the View Debugger:
This is indeed puzzling. Here is how I fixed it: just after registering the nib add
tableView.rowHeight = 44 // or whatever