I created a Uitableview in a ViewController and I want to set dynamically the size of each cell containing a subview. I try a lot of technics, the only one is using this function :
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 150.0
}
but the value is fixe so a scroll bar appear in my tableview cell and I don't want that, I want to see all the subviews without a scroll bar, here is my code for the ViewController containing the tableview :
import UIKit
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// 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.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3;
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:CustomCell? = tableView.dequeueReusableCellWithIdentifier("Cell") as? CustomCell
if(cell == nil)
{
cell = CustomCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
cell?.dataArr = ["Test 1","Test 2","Test 3","Test 4","Test 5"]
return cell!
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 150.0
}
}
and here is the custom cell :
import UIKit
class CustomCell: UITableViewCell,UITableViewDataSource,UITableViewDelegate {
var dataArr:[String] = []
var subMenuTable:UITableView?
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style , reuseIdentifier: reuseIdentifier)
setUpTable()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
setUpTable()
}
func setUpTable()
{
subMenuTable = UITableView()
subMenuTable?.delegate = self
subMenuTable?.dataSource = self
self.addSubview(subMenuTable!)
}
override func layoutSubviews() {
super.layoutSubviews()
subMenuTable?.frame = CGRectMake(0.2, 0.3, self.bounds.size.width-5, self.bounds.size.height-5)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArr.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("cellID")
if(cell == nil){
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cellID")
}
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 160.0
cell?.textLabel?.text = dataArr[indexPath.row]
return cell!
}
}
How can I fixed that ?
Try
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return tableView.cellForRowAtIndexPath(indexPath)?.contentView.frame.size.height
}
Related
In myscenario, I am trying to add Dynamic UITableview within Static UITableview Cell. How to achieve this? I tried below code but It is not working for me.
The dynamic tableview cell count based need to readjust static tableview cell height. Please provide some sample code.
Tableview Code
import UIKit
class CustomCell: UITableViewCell,UITableViewDataSource,UITableViewDelegate {
var dataArr:[String] = []
var subMenuTable:UITableView?
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style , reuseIdentifier: reuseIdentifier)
setUpTable()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
setUpTable()
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
setUpTable()
}
func setUpTable(){
subMenuTable = UITableView(frame: CGRectZero, style:UITableViewStyle.Plain)
subMenuTable?.delegate = self
subMenuTable?.dataSource = self
self.addSubview(subMenuTable!)
}
override func layoutSubviews() {
super.layoutSubviews()
subMenuTable?.frame = CGRectMake(0.2, 0.3, self.bounds.size.width-5, self.bounds.size.height-5)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArr.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("cellID")
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cellID")
}
cell?.textLabel?.text = dataArr[indexPath.row]
return cell!
}
}
Create a single view project add tableview inside storyboard and set up its datasource and delegate
do code as below to firstViewController.swift
import UIKit
class firstViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3;
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:CustomCell? = tableView.dequeueReusableCellWithIdentifier("Cell") as? CustomCell
if cell == nil {
cell = CustomCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
cell?.dataArr = ["subMenu->1","subMenu->2","subMenu->3","subMenu->4","subMenu->5"]
return cell!
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 150.0
}
}
create a new file CustomCell.swift which is the subclass of UITableViewCell and do not select with xib this file is without .xib file table and its cell will be created programatically.
do code as below to CustomCell.swift
import UIKit
class CustomCell: UITableViewCell,UITableViewDataSource,UITableViewDelegate {
var dataArr:[String] = []
var subMenuTable:UITableView?
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style , reuseIdentifier: reuseIdentifier)
setUpTable()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
setUpTable()
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
setUpTable()
}
func setUpTable(){
subMenuTable = UITableView(frame: CGRectZero, style:UITableViewStyle.Plain)
subMenuTable?.delegate = self
subMenuTable?.dataSource = self
self.addSubview(subMenuTable!)
}
override func layoutSubviews() {
super.layoutSubviews()
subMenuTable?.frame = CGRectMake(0.2, 0.3, self.bounds.size.width-5, self.bounds.size.height-5)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArr.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("cellID")
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cellID")
}
cell?.textLabel?.text = dataArr[indexPath.row]
return cell!
}
}
I hope it will work for you ...:)
Do this in your main controller:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if tableView = self.tableView {
var cell:CustomCell? = tableView.dequeueReusableCellWithIdentifier("Cell") as? CustomCell
cell.tableView.delegate = self
cell.tableView.dataSource = self
return cell!
} else {
var cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("cellID")//here you custom cell's tableView's cell
return cell
}
}
Basically you will have to calculate height of your child tableview as demonstrated below
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
{
#IBOutlet weak var parentTableView : UITableView? = nil
var sections = [[String:[[String:String]]]]()
override func viewDidLoad()
{
super.viewDidLoad()
setup()
}
func setup()
{
// Data
let section1 = ["Items" : [["Title" : "Row 1"], ["Title" : "Row 2"]]]
let section2 = ["Items" : [["Title" : "Row 1"], ["Title" : "Row 2"], ["Title" : "Row 3"]]]
let section3 = ["Items" : [["Title" : "Row 1"], ["Title" : "Row 2"], ["Title" : "Row 3"], ["Title" : "Row 4"]]]
sections.append(section1)
sections.append(section2)
sections.append(section3)
// Register header
}
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return sections.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
// Calculate the height of parent cell.
var cellHeight : CGFloat = 0.0
let aSection = sections[indexPath.row]
if let items = aSection["Items"]
{
cellHeight = CGFloat(44 * items.count)
}
return cellHeight
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
if let cell = tableView.dequeueReusableCell(withIdentifier: "ParentTableViewCell") as? ParentTableViewCell
{
if let aSection = sections[indexPath.row] as? [String:[[String:String]]], let items = aSection["Items"]
{
cell.configure(items: items)
}
return cell
}
return UITableViewCell()
}
}
Here is the link for the code
In my scenario, I have a static tableview. Now I need to add dynamic tableview at the bottom of static tableview. As per my scenario, I can’t able to mix both in one tableview. So, I have to add dynamic tableview bottom of static tableview footer or any other bottom accessory view. I tried below methods
Added footer view in static cell tableview and within that footer I have added dynamic tableview but the dynamic tableview not expanding the footer height based on its cell count also, it is not allowing dynamic cell selection.
Added accessory view but don’t know how to add it at bottom of the tableview
My StaticTableview Cell Code
override func numberOfSections(in tableView: UITableView) -> Int {
return 4
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return " "
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (section == 0) {
return 2
} else if(section == 1) {
return 1
} else if(section == 2) {
return 3
} else {
return 1
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath as IndexPath) as UITableViewCell
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if indexPath.section == 0 && indexPath.row == 0 { }
else if indexPath.section == 0 && indexPath.row == 1 {
} else if indexPath.section == 1 && indexPath.row == 0 {
} else if indexPath.section == 2 && indexPath.row == 0 {
} else if indexPath.section == 2 && indexPath.row == 1 {
} else if indexPath.section == 2 && indexPath.row == 2 {
} else if indexPath.section == 2 && indexPath.row == 3 {
} else {
}
}
Create a single view project add tableview inside storyboard and set up its datasource and delegate
do code as below to firstViewController.swift
import UIKit
class firstViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3;
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:CustomCell? = tableView.dequeueReusableCellWithIdentifier("Cell") as? CustomCell
if cell == nil {
cell = CustomCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
cell?.dataArr = ["subMenu->1","subMenu->2","subMenu->3","subMenu->4","subMenu->5"]
return cell!
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 150.0
}
}
create a new file CustomCell.swift which is the subclass of UITableViewCell and do not select with xib this file is without .xib file table and its cell will be created programatically.
do code as below to CustomCell.swift
import UIKit
class CustomCell: UITableViewCell,UITableViewDataSource,UITableViewDelegate {
var dataArr:[String] = []
var subMenuTable:UITableView?
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style , reuseIdentifier: reuseIdentifier)
setUpTable()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
setUpTable()
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
setUpTable()
}
func setUpTable(){
subMenuTable = UITableView(frame: CGRectZero, style:UITableViewStyle.Plain)
subMenuTable?.delegate = self
subMenuTable?.dataSource = self
self.addSubview(subMenuTable!)
}
override func layoutSubviews() {
super.layoutSubviews()
subMenuTable?.frame = CGRectMake(0.2, 0.3, self.bounds.size.width-5, self.bounds.size.height-5)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArr.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("cellID")
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cellID")
}
cell?.textLabel?.text = dataArr[indexPath.row]
return cell!
}
}
I hope it will work for you ...:)
Just add sections and rows in the current tableView and use different cell for those rows if needed and reload. don't make 2 tableView one below another.
var sections = 4
override func numberOfSections(in tableView: UITableView) -> Int {
return sections
}
// sections = 5
// tableView.reloadData()
and change sections on run time and handle the data source and delegate method accordingly and reload.
I try to implement UITableView programmatically without use of xib or Storyboards. This is my code:
ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let table: UITableViewController = MyTableViewController()
let tableView: UITableView = UITableView()
tableView.frame = CGRect(x: 10, y: 10, width: 100, height: 500)
tableView.dataSource = table
tableView.delegate = table
self.view.addSubview(tableView)
}
}
MyTableViewController.swift
import UIKit
class MyTableViewController: UITableViewController {
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
NSLog("sections")
return 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
NSLog("rows")
return 3
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
NSLog("get cell")
let cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "Cell")
cell.textLabel!.text = "foo"
return cell
}
}
But when I run app, all I get is empty table. In log I see a few lines of sections and rows, but no get cell. How can I fix this code to get table with 6 lines of foo text?
Note: As you mentioned you just started programming in Swift. I created a tableView programmatically. Copy and paste below code into your viewController and run the project...
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let myArray: NSArray = ["First","Second","Third"]
private var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let barHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height
let displayWidth: CGFloat = self.view.frame.width
let displayHeight: CGFloat = self.view.frame.height
myTableView = UITableView(frame: CGRect(x: 0, y: barHeight, width: displayWidth, height: displayHeight - barHeight))
myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
myTableView.dataSource = self
myTableView.delegate = self
self.view.addSubview(myTableView)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Num: \(indexPath.row)")
print("Value: \(myArray[indexPath.row])")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath as IndexPath)
cell.textLabel!.text = "\(myArray[indexPath.row])"
return cell
}
}
Output:
Updated for Swift 3
Option 1:
import UIKit
//
// MARK :- TableViewController
//
class TableViewController: UITableViewController {
private let headerId = "headerId"
private let footerId = "footerId"
private let cellId = "cellId"
//
// MARK :- HEADER
//
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 150
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerId) as! CustomTableViewHeader
return header
}
//
// MARK :- FOOTER
//
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 150
}
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footer = tableView.dequeueReusableHeaderFooterView(withIdentifier: footerId) as! CustomTableViewFooter
return footer
}
//
// MARK :- CELL
//
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! CustomTableCell
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
title = "TableView Demo"
view.backgroundColor = .white
setupTableView()
}
func setupTableView() {
tableView.backgroundColor = .lightGray
tableView.register(CustomTableViewHeader.self, forHeaderFooterViewReuseIdentifier: headerId)
tableView.register(CustomTableViewFooter.self, forHeaderFooterViewReuseIdentifier: footerId)
tableView.register(CustomTableCell.self, forCellReuseIdentifier: cellId)
}
}
//
// MARK :- HEADER
//
class CustomTableViewHeader: UITableViewHeaderFooterView {
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .orange
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//
// MARK :- FOOTER
//
class CustomTableViewFooter: UITableViewHeaderFooterView {
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .green
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//
// MARK :- CELL
//
class CustomTableCell: UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .white
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Option 2: replace above Option 1 TableViewController with this class
import UIKit
//
// MARK :- ViewController
//
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let headerId = "headerId"
private let footerId = "footerId"
private let cellId = "cellId"
lazy var tableView: UITableView = {
let tv = UITableView(frame: .zero, style: .plain)
tv.translatesAutoresizingMaskIntoConstraints = false
tv.backgroundColor = .lightGray
tv.delegate = self
tv.dataSource = self
tv.register(CustomTableViewHeader.self, forHeaderFooterViewReuseIdentifier: self.headerId)
tv.register(CustomTableViewFooter.self, forHeaderFooterViewReuseIdentifier: self.footerId)
tv.register(CustomTableCell.self, forCellReuseIdentifier: self.cellId)
return tv
}()
//
// MARK :- HEADER
//
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerId) as! CustomTableViewHeader
return header
}
//
// MARK :- FOOTER
//
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footer = tableView.dequeueReusableHeaderFooterView(withIdentifier: footerId) as! CustomTableViewFooter
return footer
}
//
// MARK :- CELL
//
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! CustomTableCell
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
title = "TableView Demo"
view.backgroundColor = .white
view.addSubview(tableView)
setupAutoLayout()
}
func setupAutoLayout() {
tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
}
Swift 4 compatible
Instead of adding a UITableView to your UIViewController, you should consider creating a UITableViewController and avoid setting up delegates:
class YourTVC: TableViewController {
override func viewDidLoad() {
super.viewDidLoad()
// setup custom cells if you use them
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "yourCell")
}
// MARK: tableView
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3 // set to value needed
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "yourCell", for: indexPath) as! CustomTableViewCell
cell.textLabel?.text = "Cell at row \(indexPath.row)"
return cell
}
}
It makes no sense that you are using a UITableViewController as the data source and delegate for your view controller's table view. Your own view controller should be the table view's data source and delegate.
Since you seem to want a view controller with a table view that doesn't take up the entire view, move every thing to your view controller as follows:
ViewController.swift:
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let tableView: UITableView = UITableView()
tableView.frame = CGRect(x: 10, y: 10, width: 100, height: 500)
tableView.dataSource = self
tableView.delegate = self
self.view.addSubview(tableView)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
NSLog("sections")
return 2
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
NSLog("rows")
return 3
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
NSLog("get cell")
let cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "Cell")
cell.textLabel!.text = "foo"
return cell
}
}
You don't need to make a separate class for UITableView. Just in your ViewController class implement protocols of UITableViewDelegate and UITableViewDataSource and then implement delegate methods.
I think your code should be like
class ViewController: UIViewController , UITableViewDelegate , UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
let table: UITableViewController = MyTableViewController()
let tableView: UITableView = UITableView()
tableView.frame = CGRect(x: 10, y: 10, width: 100, height: 500)
tableView.dataSource = table
tableView.delegate = table
self.view.addSubview(tableView)
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
NSLog("sections")
return 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
NSLog("rows")
return 3
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
NSLog("get cell")
let cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "Cell")
cell.textLabel!.text = "foo"
return cell
}
}
Tell us more info or show logs if you still face issue.
I had a similar issue in that the data would not populate for my programmatic UITableView. This was because I was using a delegate/dataSource without a strong reference. Once I kept a reference to it (I had one class implementing both UITableViewDataSource and UITableViewDelegate), the data was populated.
import UIKit
class ViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(TableCell.self, forCellReuseIdentifier: "cell")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableCell
cell.nameLabel.text = "TableViewCell programtically"
cell.nameLabel.textAlignment = .center
cell.nameLabel.textColor = .white
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
Simple solution
import UIKit
class CustomTableViewController: UICollectionViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
cell.textLabel!.text = "\(indexPath.row)"
return cell
}
}
This question was asked multiple times.
http://stackoverflow.com/questions/25581780/type-viewcontroller-does-not-confirm-to-protocol-uitableviewdatasource
and I did tried the solutions provided over there but still I am not able to get away with this error. Code to UITableView is below
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
{
#IBOutlet var tableView: UITableView!
var data: [String] = ["one","two","three","four"]
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return self.data.count;
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath!)
{
println("You clicked cell number #\(indexPath.row)!")
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
{
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel?.text = self.data[indexPath.row]
return cell
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Please tell what mistake am I doing here.
Try this just remove both the function numberOfRowsInSection and cellForRowAtIndexPath and again add this function like :
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return self.data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel?.text = self.data[indexPath.row]
return cell
}
This is works for me.
The following code didn't work for me on iOS 8.1. in XCode 6.1.1. This code works:
import UIKit
class ViewController : UIViewController,UITableViewDelegate,UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
//currently only a testing number
return 25
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
var cell:UITableViewCell=UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "mycell")
cell.textLabel?.text = "row#\(indexPath.row)"
cell.detailTextLabel?.text = "subtitle#\(indexPath.row)"
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Please confirm all tableview required methods before the last }. Like
class ViewController:UIViewController,UITableViewDataSource,UITableViewDelegate {
var data: [String] = ["one","two","three","four"]
override func viewDidLoad() {
super.viewDidLoad()
self.loadTableView()
// 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.
}
func loadTableView() {
var tableObj:UITableView=UITableView()
tableObj=UITableView(frame: UIScreen.mainScreen().bounds, style: UITableViewStyle.Plain)
tableObj.delegate=self;
tableObj.dataSource=self;
self.view.addSubview(tableObj)
}
// MARK: - Table view data source
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Section (section)"
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell=UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "mycell")
var nameLabel:UILabel = UILabel(frame: CGRect(x: 50,y: 5,width: 200,height: 30))
nameLabel.text="Title\(indexPath.row)"
nameLabel.textColor=UIColor.brownColor()
nameLabel.font=UIFont.boldSystemFontOfSize(15)
nameLabel.textAlignment=NSTextAlignment.Left
cell.contentView.addSubview(nameLabel)
var imageView:UIImageView=UIImageView(frame: CGRect(x: 5,y: 2,width: 40,height: 40))
imageView.backgroundColor=UIColor.purpleColor()
imageView.layer.masksToBounds=true
imageView.layer.cornerRadius=imageView.frame.width/2
cell.contentView.addSubview(imageView)
return cell
}
}
I am new to IOS swift development. I used to work with previous Xcode 6 beta.
I have downloaded the Xcode 6.0.1 and I can not get this to work Xcode Version: 6.0.1
I am still getting "'MyViewController' does not confirm to protocol 'UITableViewDataSource' " when I try to run the example.
Can someone please help me? I have gone through other issues on this site and added all the required functions for "UITableViewDataSource";
import UIKit
import Foundation
class MyViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
{
var array1:[String] = ["one","two","three","four"]
var array2:[String] = ["IOS","Android","java","c++","Swift"]
let sectionCount = 2
var myTableView:UITableView!
// init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
// var rect = CGRectMake(0, 0, 220, 320)
// myTableView = UITableView(frame: rect, style: UITableViewStyle.Grouped)
// super.init(nibName: nil, bundle: nil)
// // Custom initialization
// }
override func viewDidLoad() {
super.viewDidLoad()
var rect = CGRectMake(0, 0, 320, 600)
myTableView = UITableView(frame: rect, style: UITableViewStyle.Grouped)
myTableView!.delegate = self
myTableView!.dataSource = self
self.view.addSubview(myTableView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//dataSourrce
//tableview:tableview,section:
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int{
switch section{
case 0:
return array1.count
case 1:
return array2.count
default:
return 1
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!{
//---cellstart----
let identifier = "identifier"
// var cell:UITableViewCell
//cell
var cell = tableView.dequeueReusableCellWithIdentifier(identifier) as? MyCell
if cell == nil {
// cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: identifier)
cell = MyCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: identifier)
}
//---cellend----
switch indexPath.section{
case 0:
// cell!.textLabel.text = array1[indexPath.row]
cell!.myLable!.text = array1[indexPath.row]
case 1:
// cell!.textLabel.text = array2[indexPath.row]
cell!.myLable!.text = array2[indexPath.row]
default:
println()
}
var image = UIImage(named: "images/qq.png")
// cell!.imageView.image = image
cell!.myImageView!.image = image
// cell!.detailTextLabel.text = "\(indexPath.section)\(indexPath.row)
return cell!
}
//dataSourrce
func numberOfSectionsInTableView(tableView: UITableView!) -> Int {
return sectionCount
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
var title:String? = nil
switch section {
case 0:
title = "Num"
case 1:
title = "Prog"
default:
title = nil
}
return title
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
println("Test\(indexPath.section) \(indexPath.row)")
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 60.0
}
func numberOfComponentsInPickerView(pickerView: UIPickerView!) -> Int {}
func pickerView(pickerView: UIPickerView!,numberOfRowsInComponent component: Int) -> Int{}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController?{
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController?{
}
}
***************** My Cell Class ***********************************
import Foundation
import UIKit
class MyCell: UITableViewCell {
let indetifier:String = "indetifier"
var myLable:UILabel?
var myImageView:UIImageView?
override init(style: UITableViewCellStyle, reuseIdentifier: String!)
{
super.init(style: .Subtitle, reuseIdentifier: indetifier)
var rect = CGRectMake(10, 0, 60, 30)
self.myLable = UILabel()
self.myLable!.frame = rect
self.myLable!.textColor = UIColor.redColor()
self.contentView.addSubview(self.myLable!)
var imageRect = CGRectMake(160, 10, 40, 40)
self.myImageView = UIImageView()
self.myImageView!.frame = imageRect
self.contentView.addSubview(self.myImageView!)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
You need to look at the whole error message. This specific message includes additional information about which methods are missing:
Type 'MyViewController' does not conform to protocol 'UITableViewDataSource'
Protocol requires function 'tableView(_:numberOfRowsInSection:)' with type '(UITableView, numberOfRowsInSection: Int) -> Int'
Candidate has non-matching type '(UITableView!, numberOfRowsInSection: Int) -> Int'
So... your numberOfRowsInSection takes an optional UITableView, and should take a required UITableView (this is a change they made between 6 and 6.1, all UITableView delegate and datasource methods now take required tableView and indexPath values)
Try this simple solution:
import UIKit
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
{
//MARK: - Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK: - Tableview Delegate & Datasource
func tableView(tableView:UITableView, numberOfRowsInSection section:Int) -> Int
{
return 10
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
}
}
class ROTableView: UITableView, UITableViewDelegate {
func tableView(tableView:UITableView!, numberOfRowsInSection section:Int) -> Int {
return 10
}
func tableView(tableView:UITableView!, cellForRowAtIndexPath indexPath:NSIndexPath!) -> UITableViewCell! {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
// cell.text = "Row #\(indexPath.row)"
// cell.detailTextLabel.text = "Subtitle #\(indexPath.row)"
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
}
When you create the subclass for UITableView please refer the above code, you will not get any error.
In my case, i named my UITableView as tableView. That caused this same error:
'MyViewController' does not conform to protocol
'UITableViewDataSource'
including another error:
Candidate is not a function
And changed tableview name to something else, error is gone.