How to correctly modify iOS table view cells at runtime (add/remove subviews?)

Apologies in advance if this has been answered somewhere. I've looked everywhere and I'm still unsure what to do. (And answers that use Objective C are almost completely worthless to me.) I'm somewhat new to iOS.

I have a UITableView which serves as a newsfeed of sorts, displaying a series of posts. (a la a twitter newsfeed, for instance.) The cells in this table view are (currently) derived from a single cell prototype, created in xcode's interface builder. Each cell contains subviews to display things like username, profile image thumbnail, title, message, date, location, another image, etc.

The problem is, depending on what data a particular post contains, many of these subviews either should or should not be shown -- if a post doesn't contain an image, then that cell's image view should not be shown; if a post doesn't have a date and/or location, one or both of these views should not be shown. Not only should the unused fields be empty, but they shouldn't take up any space in the cell.

I read in Using Auto Layout in UITableView for dynamic cell layouts & variable row heights (under "2. Determine Unique Table View Cell Reuse Identifiers". Wonderful answer by @smileyborg, btw.) that for each different layout of subviews that could be in a cell, a different prototype cell and reuse identifier should be used. But this would require me to have a cell prototype for every single possible combination of data items in a post, even if the difference is single label! Surely there must be a better way.

What is the safe and correct way to do what I need to do? Is there perhaps a way to remove subviews from cells at runtime (and have the layout adjust its spacing accordingly) without completely screwing up cell recycling?

Answers


Ill assume you know everything you want to know about your layout when you see the cell.

So its basic tableview cell layout. Dequeue and decorate.

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier(MyIdentifier, forIndexPath: indexPath) as! MyCustomCellClass

    let data:MyDataClass = myDataAtIndexPath(indexPath)

    decorateCell(cell,data:data)

    return cell
}

func decorateCell(cell:MyCustomCellClass,data:MyDataClass) {

    //here is where you arrange/change your constraints and hide/reveal views
    //depending on the data
}

but also what you need is to allow the cell to set its height properly

func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return someEstimatedNumberWhichIsClose;
}

but most crucially in your XIB, the cell MUST have a continuous line of constraints from top to bottom which describe the height.

So this cell will auto-set its height correctly.

While this one will not.

NB - in the upper example , if you leave the height constraint off the text-field and make it infinite line count the cell will grow/shrink appropriately.

So to summarise you can use one multipurpose cell as long as you keep your height constraints coherent.

As a general rule - Swiss Army CellsĀ® which do lots of things may get a bit unwieldy so you do need think about how many use cases you wish to support with one cell and then maybe start creating multiple types/identifiers.


Need Your Help

How to show ArcGIS Server TileLayer within a Leaflet map

javascript leaflet arcgis-server

I am trying to show a map that I published using ArcGIS Server within a Leaflet map. I first tried to show the map as a basemap and creating a simple Leaflet TileLayer:

Exception thrown when registering custom serializers in Storm's storm.yaml

serialization configuration yaml apache-storm kryo

I registered a custom serializer for a class in Storm's conf/storm.yaml in the following way: