0

I've spent over six hours researching and unsuccessfully attempting to create dynamic cells today. I've found a handful of great tutorials on it too. I'm doing something wrong and am hoping someone can tell me what.

My app: The table starts empty. Clicking an add button presents a modal VC, which has two text input fields (title/desc). That data is passed back to the table. An unwind method in the main VC reloads the table data.

Problem: If the description part of the cell is longer than one line, it just gets cut off.

Here is the code in my main view controller, which houses the table:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

//***** ----- ***** ------ ***** ----- ***** ----- *****
//Initial Setup
//***** ----- ***** ------ ***** ----- ***** ----- *****

@IBOutlet weak var tableView: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

}

override func viewDidAppear(animated: Bool) {
    tableView.reloadData()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

//Automatic table reload upon unwind
@IBAction func unwindToMain(segue: UIStoryboardSegue) {
    //RW's code for dynamic cell height
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 80.0

    tableView.reloadData()
}

//***** ----- ***** ------ ***** ----- ***** ----- *****
//Functions
//***** ----- ***** ------ ***** ----- ***** ----- *****

//Swipe to delete task cell
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if(editingStyle == UITableViewCellEditingStyle.Delete) {
        taskMgr.tasks.removeAtIndex(indexPath.row)
        tableView.reloadData()
    }
}



//***** ----- ***** ------ ***** ----- ***** ----- *****
//Table View & Cell Setup
//***** ----- ***** ------ ***** ----- ***** ----- *****

//Tells the table how many rows it should render
//*Looks to the taskMgr to count tasks, creates equal # of rows
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return taskMgr.tasks.count
}

//Creates the individual cells. If the above function returns 3, this runs 3 times
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "BasicCell")

    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 80.0

    cell.textLabel?.text = taskMgr.tasks[indexPath.row].name
    cell.detailTextLabel?.text = taskMgr.tasks[indexPath.row].desc

    return cell
}

}

Code in my modal/editor view:

class EditorView: UIViewController, UITextFieldDelegate {

@IBOutlet var txtTask: UITextField!
@IBOutlet var txtDesc: UITextView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}



//***** ----- ***** ------ ***** ----- ***** ----- *****
//Keyboard Functionality
//***** ----- ***** ------ ***** ----- ***** ----- *****

//Dismisses keyboard upon tapping the return key
func textFieldShouldReturn(textField: UITextField) -> Bool{
    textField.resignFirstResponder()
    return true
}

//Dismisses keyboard upon touch outside text boxes
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    self.view.endEditing(true)
}

//***** ----- ***** ------ ***** ----- ***** ----- *****
//Code to run upon Editor being dismissed
//***** ----- ***** ------ ***** ----- ***** ----- *****

//Actions performed upon tapping the 'Finish' button
@IBAction func dismissEditorView(sender: AnyObject) {

    //Calls a previously written function to append textfield input to the table array
    taskMgr.addTask(txtTask.text, desc: txtDesc.text)

    //Dismisses the EditorView
    dismissViewControllerAnimated(true, completion: nil)

}
}

My task manager file housing a function to append new items to table:

import UIKit

//This has global scope!!
var taskMgr: TaskManager = TaskManager()

struct task {
    var name = "Name TBD"
    var desc = "Desc TBD"
}

class TaskManager: NSObject {

    var tasks = [task]()

    func addTask(name: String, desc: String){
        tasks.append(task(name: name, desc: desc))    
    }
}

Tutorials I've been referencing:

http://natashatherobot.com/ios-8-self-sizing-table-view-cells-with-dynamic-type/

http://www.raywenderlich.com/87975/dynamic-table-view-cell-height-ios-8-swift

http://coding.tabasoft.it/ios/ios8-self-sizing-uitableview-cells/

http://useyourloaf.com/blog/2014/08/07/self-sizing-table-view-cells.html

What I think I am doing right:

-Table added to view, prototype cell added to table

-Two labels added to the cell. Auto layout added. Top label constraints are to container (leading, trailing, and top). Bottom constraint is to second label. Bottom label has top to second label, then container for leading, trailing and bottom.

-Top label has 751 priority level for compression resistance and content hugging. Bottom label has 750 priority for all four.

-Both labels have preferred width set to automatic. Explicit is unchecked

Dave G
  • 12,042
  • 7
  • 57
  • 83

3 Answers3

0

The issue is that you are setting the .rowHeight and .estimatedRowHeight after the UITableViewCell has been created. Move the following lines into the viewDidLoad():

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 80.0
douglas bumby
  • 324
  • 1
  • 4
  • 13
  • Thanks but that didn't work for me. I think it needs to go in both the viewDidLoad and the unwind segue. If it doesn't run on unwind then it won't work, viewDidLoad doesn't seem to run when dismissing a modal view. My suspicion is this has something to do with my code updating the original cell title and description and not the ones I add in the storyboard? – Dave G Aug 04 '15 at 03:48
0

Solved my problem. Basically the prototype cell's title and description label weren't linked to the code with IBOutlets. My app worked because when I ran it and added a table item it just used the default title and subtitle. However, those did not have auto layout constraints or lines set to 0, so the height behaved statically.

I added a custom class file and set the cell's custom class as the new class, and then linked IBOutlet's to this file. So that file looked like this:

import UIKit

class CustomTableViewCell: UITableViewCell {

    @IBOutlet var nameLabel:UILabel!
    @IBOutlet var descLabel:UILabel!

    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
    }

}

Then I just slightly changed my main ViewController code (shown in my above question. Here's where the change was:

//Creates the individual cells. If the above function returns 3, this runs 3 times
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cellIdentifier = "BasicCell"
    let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! CustomTableViewCell

    cell.nameLabel.text = taskMgr.tasks[indexPath.row].name
    cell.descLabel.text = taskMgr.tasks[indexPath.row].desc

And that was it. Now it works perfectly, each time I add an item, everything sizes properly.

Dave G
  • 12,042
  • 7
  • 57
  • 83
0

I will suggest you, not to use rowHeight & estimatedRowHeight. Though it is works, it will create problem when the cells are scrolled or when view is disappared, all cells get messed up. All the problem is because of height of cell. I have answered the same but in ios in following link

IOS - self sizing cells issue

Try to convert this in swift. I dont have knowledge of swift. Hopes it useful to you.

Community
  • 1
  • 1
swapnali patil
  • 304
  • 2
  • 17