2

I prefer to use UITableView to create table with 2 level hierarchy like this picture. Everytimes user tap on header, content is collapse or expand. After 3 days research, I found that there are 2 technical:

1.custom UITableViewCell with another table in itself

2.using section header view.

Now I decide to use the second. And because UITableView does not re-use section view (although UITableView contain 2 private variable: _reusableHeaderViews & _reusableFooterViews:), I created some custom methods to do this task. Every gone okay, except 1 bug: when I using method reloadSections:withRowAnimation with UITableViewRowAnimationFade, the header view become blank view.

Here is my code:

#import "MasterViewController.h"

@interface MasterViewController () 
//remember current section
@property (assign, nonatomic) NSInteger curSession;
@property (strong, nonatomic) NSMutableDictionary *reusableHeaderViews;
@end

@implementation MasterViewController

@synthesize reusableHeaderViews = _reusableHeaderViews;
@synthesize tableView = _tableView;
@synthesize curSession = _curSession;
@synthesize detailViewController = _detailViewController;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        self.title = NSLocalizedString(@"Master", @"Master");
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.curSession = -1;
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

//method for adding header view into reuse-array
-  (void)registerHeaderView:(UITableViewCell *)headerView forReuseIdentifier:(NSString *)reuseIdentifier
{
    NSMutableDictionary *reusableDictionary  = [self reusableHeaderViews];
    if (reusableDictionary == nil)
    {
        reusableDictionary = [[NSMutableDictionary alloc] init];  //creates a storage dictionary if one doesn’t exist
        self.reusableHeaderViews = reusableDictionary;
    }

    NSMutableArray *arrayForIdentifier = [[self reusableHeaderViews] objectForKey:reuseIdentifier];
    if (arrayForIdentifier == nil)
    {
        //creates an array to store views sharing a reuse identifier if one does not exist
        arrayForIdentifier = [[NSMutableArray alloc] init];        
        [reusableDictionary setObject:arrayForIdentifier forKey:reuseIdentifier];
    }

    [arrayForIdentifier addObject:headerView];
}

//get header view in reuse-array
- (UITableViewCell *)reuseableHeaderForIdentifier:(NSString *)reuseIdentifier
{
    NSMutableArray *arrayOfViewsForIdentifier = [[self reusableHeaderViews]  objectForKey:reuseIdentifier];

    if (arrayOfViewsForIdentifier == nil)
    {
        return nil;  //We don’t have any of this kind!
    }

    NSInteger indexOfAvailableHeaderView = [arrayOfViewsForIdentifier indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop)
                                            {
                                                //If my view doesn’t have a superview, it’s not on-screen.
                                                return ![obj superview];
                                            }];

    if (indexOfAvailableHeaderView != NSNotFound)
    {
        UITableViewCell *headerView = [arrayOfViewsForIdentifier objectAtIndex:indexOfAvailableHeaderView];
        return headerView;    //Success!
    }

    return nil;
}

#pragma mark - Table View

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 15;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (_curSession == section)
        return section;
    return 0;
}

- (UIView*) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    static NSString *headerReuseIdentifier = @"Header";
    UITableViewCell *cell = [self reuseableHeaderForIdentifier:headerReuseIdentifier];
    if(cell == nil) 
    {
        //Didn’t locate a reusable
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@""];
        [self registerHeaderView:cell forReuseIdentifier:headerReuseIdentifier];
        UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(openSection:)];
        tapGR.numberOfTapsRequired = 1;
        [cell addGestureRecognizer:tapGR];
        cell.backgroundColor = [UIColor redColor];
    }
    cell.tag = section;
    cell.textLabel.text = [NSString stringWithFormat:@"Section title %i", section];

    return cell;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }

    cell.textLabel.text = [NSString stringWithFormat:@"Row %i - section %i", indexPath.row, indexPath.section];
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

}

- (void) openSection:(id)sender

{
    NSInteger section = [[(UITapGestureRecognizer*)sender view] tag];
    if(_curSession == -1)
    {
        _curSession = section;
        [_tableView reloadSections:[NSIndexSet indexSetWithIndex:_curSession] withRowAnimation:UITableViewRowAnimationFade];
    }
    else if(_curSession == section)
    {
        _curSession = -1;
        [_tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
    }
    else if(_curSession != section)
    {
        NSInteger temp = _curSession;
        _curSession = -1;
        [_tableView reloadSections:[NSIndexSet indexSetWithIndex:temp] withRowAnimation:UITableViewRowAnimationFade];
        _curSession = section;
        [_tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
    }
}

@end
Community
  • 1
  • 1
dementiazz
  • 21
  • 1
  • 2
  • you already saw this? http://developer.apple.com/library/ios/#samplecode/TableViewUpdates/Introduction/Intro.html – Yudmt Jul 05 '13 at 12:28

1 Answers1

0

It's a little late but maybe someone will have similar question.

You can try to use this component: https://github.com/serverdensity/ios-SDNestedTable

Wojciech Rutkowski
  • 11,299
  • 2
  • 18
  • 22