Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Here's the <code>CollapsingTableViewDelegate</code> class that I'm currently working with to do this. This only works with static table content.</p> <p>You supply the <code>CollapsingTableCellDelegate</code> implementation to this class, which must know how to compute the collapsed and expanded sizes of each row, and how to create a <code>UIView</code> for each row. The view stays the same whether collapsed or expanded, so that the top sliver of each row's view serves as that row's clickable header.</p> <p>You then make this class the datasource and delegate for your <code>UITableView</code>.</p> <p>Header file <code>CollapsingTableViewDelegate.h</code>:</p> <pre><code>#import &lt;UIKit/UIKit.h&gt; @protocol CollapsingTableCellDelegate&lt;NSObject&gt; @required - (CGFloat)collapsingCellHeightForRow:(int)row expanded:(BOOL)expanded; - (UIView *)collapsingCellViewForRow:(int)row; @optional - (BOOL)collapsingCellAllowCollapse:(int)row; @end struct cell; @interface CollapsingTableViewDelegate : NSObject &lt;UITableViewDelegate, UITableViewDataSource&gt; { id&lt;CollapsingTableCellDelegate&gt; cellDelegate; int numCells; int currentSelection; struct cell *cells; } @property (nonatomic, retain, readonly) id&lt;CollapsingTableCellDelegate&gt; cellDelegate; @property (nonatomic, assign, readonly) int numCells; @property (nonatomic, assign) int currentSelection; @property (nonatomic, assign, readonly) struct cell *cells; - (CollapsingTableViewDelegate *)initWithCellDelegate:(id&lt;CollapsingTableCellDelegate&gt;)delegate numCells:(int)numCells; - (void)tableView:(UITableView *)tableView touchRow:(int)newSelection; @end </code></pre> <p>and source file <code>CollapsingTableViewDelegate.m</code>:</p> <pre><code>#import "CollapsingTableViewDelegate.h" @implementation CollapsingTableViewDelegate struct cell { u_char expanded; u_char collapsable; }; @synthesize cellDelegate; @synthesize currentSelection; @synthesize cells; @synthesize numCells; #pragma mark - #pragma mark Setup and Teardown - (CollapsingTableViewDelegate *)initWithCellDelegate:(id&lt;CollapsingTableCellDelegate&gt;)delegate numCells:(int)num { if ([super init] == nil) return nil; if ((cells = calloc(num, sizeof(*cells))) == NULL) { [self autorelease]; return nil; } cellDelegate = [delegate retain]; numCells = num; for (int row = 0; row &lt; self.numCells; row++) { struct cell *const cell = &amp;self.cells[row]; cell-&gt;collapsable = ![self.cellDelegate respondsToSelector:@selector(collapsingCellAllowCollapse:)] || [self.cellDelegate collapsingCellAllowCollapse:row]; cell-&gt;expanded = !cell-&gt;collapsable; } currentSelection = -1; return self; } - (void)dealloc { [cellDelegate release]; free(cells); [super dealloc]; } - (void)tableView:(UITableView *)tableView reloadRow:(int)row fade:(BOOL)fade { [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:row inSection:0]] withRowAnimation:fade ? UITableViewRowAnimationFade : UITableViewRowAnimationNone]; } - (void)tableView:(UITableView *)tableView touchRow:(int)newSelection { // Sanity check if (newSelection &lt; -1 || newSelection &gt;= self.numCells) { NSLog(@"CollapsingTableViewDelegate: invalid row %d not in the range [-1..%d)", newSelection, self.numCells); return; } // Gather info int oldSelection = self.currentSelection; BOOL sameCellSelected = newSelection == oldSelection; struct cell *const oldCell = oldSelection != -1 ? &amp;self.cells[oldSelection] : NULL; struct cell *const newCell = newSelection != -1 ? &amp;self.cells[newSelection] : NULL; // Mark old cell as collapsed and new cell as expanded if (newCell != NULL) newCell-&gt;expanded = TRUE; if (oldCell != NULL) oldCell-&gt;expanded = FALSE; self.currentSelection = sameCellSelected ? -1 : newSelection; // Update table view if (oldSelection &gt;= newSelection) { if (oldSelection != -1) [self tableView:tableView reloadRow:oldSelection fade:sameCellSelected]; if (newSelection != -1 &amp;&amp; !sameCellSelected) [self tableView:tableView reloadRow:newSelection fade:TRUE]; } else { if (newSelection != -1 &amp;&amp; !sameCellSelected) [self tableView:tableView reloadRow:newSelection fade:TRUE]; if (oldSelection != -1) [self tableView:tableView reloadRow:oldSelection fade:sameCellSelected]; } // If expanding a cell, scroll it into view if (newSelection != -1 &amp;&amp; !sameCellSelected) { [tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:newSelection inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:TRUE]; } } #pragma mark - #pragma mark Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.numCells; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { int row = [indexPath row]; struct cell *const cell = &amp;self.cells[row]; return [self.cellDelegate collapsingCellHeightForRow:row expanded:cell-&gt;expanded]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { int row = [indexPath row]; UIView *cellView = [self.cellDelegate collapsingCellViewForRow:row]; [cellView removeFromSuperview]; UITableViewCell *tvcell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease]; [tvcell.contentView addSubview:cellView]; tvcell.clipsToBounds = TRUE; tvcell.selectionStyle = UITableViewCellSelectionStyleNone; return tvcell; } #pragma mark - #pragma mark Table view delegate - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { int row = [indexPath row]; struct cell *const cell = &amp;self.cells[row]; return cell-&gt;collapsable ? indexPath : nil; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)newSelection { [tableView deselectRowAtIndexPath:newSelection animated:TRUE]; [self tableView:tableView touchRow:[newSelection row]]; } @end </code></pre> <p>Not perfection, but seems to basically work for me.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload