Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best approach for UITableViewCell with complex format

I'm new to iOS development pondering how best to approach a fairly simple design problem. I want to display a set of items, each one of which has the structure as sketched. In a given set, not more than 10's of items.

Sketch

Each item includes a thumbnail image, a heading, a blurb, and a set of buttons. There are two complications:

  1. The amount of text and number of buttons is variable.
  2. The text requires some internal formatting (italics and bold).

I've considered these approaches:

  1. Use a table view, with custom, resizable UITableViewCell, probably using something like OHAttributedLabel for the text. For the variable number of buttons, either lay these out programmatically or possibly use the new collection view (for older iOS, have to use 3rd party grid view).

  2. Use a table view with custom cell based on UIWebView.

  3. Do the whole set as one UIWebView.

  4. Use a table view with sections; each item having its own section and parsing out the buttons and text to rows.

Would love to get suggestions about how a more experienced iOS dev would approach this.

EDIT: I am now considering that the best way may be:

5) Use UICollectionView for the whole thing.

UPDATE: In the end, I laid the whole thing out in code as a custom table cell (ie., #1). This was a good choice, not only for the reasons given in the answer, but because as someone new to iOS development, it's something I needed to get under my belt. Didn't even use collection view for the buttons, because I was worried about performance and also the hassle of supporting iOS5.

I do think that using collection view for the whole design (#5) would have been an elegant solution, and I actually started down that path. However, some complications not shown in the simplified pic above made that unwieldy.

2nd UPDATE: #1 turned out to be a dead end. My final solution used a UIWebView (#3) - see answer.

like image 439
Phil Mitchell Avatar asked Dec 01 '12 23:12

Phil Mitchell


People also ask

How do you get the indexPath row when a button in a cell is tapped?

add an 'indexPath` property to the custom table cell. initialize it in cellForRowAtIndexPath. move the tap handler from the view controller to the cell implementation. use the delegation pattern to notify the view controller about the tap event, passing the index path.

How do I change the Tableview style in Swift?

You can't change the tableview style dinamically, you have to do it in your xib file or storyboard if you have one. If you don't use a storyboard or a xib, and prefer to create the tableview programmatically, specify the style while creating the tableview using the - initWithFrame:style: method.

What is UITableView in Swift?

A view that presents data using rows in a single column.


2 Answers

I have found some resources that might be useful to some people who is doing complex tableviewcell and want fast scrolling. I am still developing it, but I want to share this first to you guys.

  1. Facebook iOS release note: they mentioned techniques: core text, pre/asynchronous calculation of table height, do a lot of things on background thread, save layout attribute in core data. http://www.facebook.com/notes/facebook-engineering/under-the-hood-rebuilding-facebook-for-ios/10151036091753920

  2. Fast scrolling sample: https://github.com/adamalex/fast-scrolling

  3. Apple's sample project TableViewSuite. The 4th example. https://developer.apple.com/library/ios/#samplecode/TableViewSuite/Introduction/Intro.html

Very close to solution..YES

like image 51
Cullen SUN Avatar answered Sep 30 '22 05:09

Cullen SUN


I know this is an old thread, but I found it very interesting, as I am just now getting around enough as an iPhone developer to reach these types of performance concerns. I found a very interesting article on Facebook's site by Facebook Engineering describing how they implemented UITableView and overcame the dynamic sizing issues, also with rapid content management. It seems they precalculated using deeper objects and kept everything asynchronous and pre-cached where possible. I'm going to provide a link to the article, but I'm going to copy the section that tackles exactly this problem. I hope you find it useful. Here's the link, https://www.facebook.com/notes/facebook-engineering/under-the-hood-rebuilding-facebook-for-ios/10151036091753920, and the most relevant excerpt:

(Re-)Building for Speed

One of the biggest advantages we've gained from building on native iOS has been the ability to make the app fast. Now, when you scroll through your news feed on the new Facebook for iOS, you'll notice that it feels much faster than before. One way we have achieved this is by re-balancing where we perform certain tasks. For example, in iOS, the main thread drives the UI and handles touch events, so the more work we do on the main thread, the slower the app feels. Instead, we take care to perform computationally expensive tasks in the background. This means all our networking activity, JSON parsing, NSManagedObject creation, and saving to disk never touches the main thread.

To give another example, we use Core Text to lay out many of our strings, but layout calculations can quickly become a bottleneck. With our new iOS app, when we download new content, we asynchronously calculate the sizes for all these strings, cache our CTFramesetters (which can be expensive to create), and then use all these calculations later when we present the story into our UITableView.

Finally, when you start Facebook for iOS, you want to see your news feed, not a loading spinner. To provide the best experience possible, we now show previously-cached content immediately. But this introduces a new problem: If you have a lot of stories in your news feed, UITableView throws a small spanner in the works by calling the delegate method -tableView:heightForRowAtIndexPath: for each story in your news feed in order to work out how tall to make its scrollbar. This would result in the app loading all the story data from disk and calculating the entire story layout solely to return the height of the story, meaning startup would get progressively slower as you accumulate more stories.

The solution to this particular problem has two main parts. Firstly, when we do our initial asynchronous layout calculations, we also store the height of the story in Core Data. In doing so, we completely avoid layout calculation in -tableView:heightForRowAtIndexPath:. Secondly, we've split up our "story" model object. We only fetch the story heights (and a few other things) from disk on startup. Later, we fetch the rest of the story data, and any more layout calculations we have to do are all performed asynchronously.

All this and more leads to high frame rates while scrolling and an app that remains responsive.

like image 30
Aaron Avatar answered Sep 30 '22 04:09

Aaron