How to Make Nested UITableView?

Discussion in 'iOS Programming' started by tsuru, May 21, 2012.

  1. tsuru, May 21, 2012
    Last edited: May 23, 2012

    tsuru macrumors member

    Joined:
    Dec 14, 2008
    #1
    I've been stuck on this for a number of days and if someone has an idea for how this could be done that would be absolutely fantastic.

    The goal is to display text like the following in a single UITableView:

    Heading 1
    - Sub-Heading 1
    -- Sub-Sub-Heading 1
    -- Sub-Sub-Heading 2
    - Sub-Heading 2

    Heading 2
    - Sub-Heading 1
    - Sub-Heading 2
    -- Sub-Sub-Heading 1
    -- Sub-Sub-Heading 2
    -- Sub-Sub-Heading 3
    - Sub-Heading 3

    Heading 3
    - Sub-Heading 1
    -- Sub-Sub-Heading 1
    -- Sub-Sub-Heading 2

    The table view would also allow each heading, sub-heading, etc. to collapse/expand the sub-elements underneath it and lastly also allow reordering of all rows.

    I've seen table views that allow you to collapse sections and that also allow reordering, but the reordering is always limited to the rows within the sections and there's only one level of collapsing/expanding. I know it should be possible since this style of data organization is used in applications like Photoshop with its handling of layers, but I'm not sure where to begin (or even if the theoretical solutions I have are good ones).

    One idea was to use NSMutableArrays within NSMutableArrays but then with reordering, the thought of managing all of them started to look very complicated. And so I wondered if there's a simpler way. Any ideas?
     
  2. jnoxx macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #2
    Not that hard.. Just make UISectionHeaders, if you click them with a delegate, expand them with UITableviewanimations, and create a set of arrays under them..
    If you have more specific questions, please ask :)
     
  3. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #3
    There is no such class as UISectionHeader.
     
  4. tsuru, May 21, 2012
    Last edited: May 21, 2012

    tsuru thread starter macrumors member

    Joined:
    Dec 14, 2008
    #4
    Thanks for the replies.

    OK jnoxx or anyone else, here's a few more specific questions:

    - When collapsing sections, is the normal routine to remove the rows beneath from the table view or is there a way to hide them without removing them entirely from the table view?

    - If rows are actually removed from the UITableView when collapsing sections, then my guess is that every section will need a unique identity so that you can find it in the data model to expand it (add its rows beneath back in) again. In other words, for determining which row was tapped to expand the appropriate section, you can't go by its index position since there will be variable amounts of rows in the table view.

    So if each section has a unique identity, and for example you move a sub-section from one section to another, how do you re-identify the moved sub-section to reflect its new "parent" section?

    - The goal also is to be able to add new sections to the table view. With all the adding and moving around of cells, do you think the array data model would be very resource intensive so as to make it lag?
     
  5. jnoxx, May 22, 2012
    Last edited by a moderator: May 22, 2012

    jnoxx macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #5
    I tend to put UI in front of it, my bad :)
    What I meant is, you can make your own UIView SectionHeaders with a delegate button method.
    I'll give a quick example :)

    HEADER FILE

    Code:
     @property (nonatomic) int openSection;
    M FILE
    Code:
     @synthesize openSection = _openSection; 
    in the viewDidLoad, setup your openSection to -1.

    Code:
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
    {
        return [self.causes count];
    }
    Code:
    - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
    {
        FamilyCauseSection *familySection = [[FamilyCauseSection alloc] init];
        familySection.delegateFCS = self;
        familySection.tag = section;
        familySection.causeLabel.text = [[self.causes objectAtIndex:section] 
        [familySection addPercentageView:[[self.causes objectAtIndex:section] chance]];
        
        if (familySection.tag == self.openSection) {
            [familySection.disclosure setTransform:CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(90))];
        } else {
            [familySection.disclosure setTransform:CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0))];
        }
        return familySection;
    }
    So basically, you create some Custom (with a UIView), as a Section Header, you insert a button (I will show later).

    In your normal tableView
    Code:
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    You create cells like you would do before, but like this.

    Code:
    CauseCell *causeCell = (CauseCell *)[tableView dequeueReusableCellWithIdentifier:nil];
        Cause *cause = [[[self.causes objectAtIndex:self.openSection] causes] objectAtIndex:indexPath.row];
    
    and build up the rest of your cell, so how to decide what section to collapse etc.
    Basically, in your Section View, you setup a delegate. I'll show that here.

    Code:
    @protocol FamilyCauseSectionDelegate
    @optional
    - (void)clickedSection:(FamilyCauseSection*)familyCauseSection;
    @end
    
    @interface FamilyCauseSection : UIView {
        id <FamilyCauseSectionDelegate> _delegateFCS;
    }
    @property (nonatomic, strong) id <FamilyCauseSectionDelegate> delegateFCS;
    @property (nonatomic) IBOutlet UILabel *causeLabel;
    @property (nonatomic) UIImageView *disclosure;
    
    in a special method I called BuildCell, i create the cell (could be done in layoutsubviews super method of UIView.
    Code:
        UIButton *button = [[UIButton alloc] initWithFrame:self.frame];
        [button addTarget:self action:@selector(clickedSection:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:button];
    
    Code:
    - (void)clickedSection:(FamilyCauseSection*)familyCauseSection {
            [self.delegateFCS clickedSection:self];
    }
    
    So, since you assigned the delegate of your familyCause in your controller that holds the tableview, you will receive the delegate method there :)
    So you need to assign the delegate in your controller header.
    So basically.
    Code:
    @interface DiagnoseViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, FamilyCauseSectionDelegate>
    Now it comes to actually selecting the section and collapsing the data below it.

    Code:
    - (void) clickedSection:(FamilyCauseSection *)familyCauseSection {
        [self.myTableView beginUpdates];
        
        ////////////////////////////////////
        // close section if allready open
        ////////////////////////////////////
        if (familyCauseSection.tag == self.openSection) {
            
            [self.myTableView reloadSections:[NSIndexSet indexSetWithIndex:familyCauseSection.tag] withRowAnimation:UITableViewRowAnimationAutomatic];
            self.openSection = -1;
        }
        else
        {
            int lastSection = self.openSection;
            self.openSection = familyCauseSection.tag;
            
            /////////////////////////////////
            // close last open section
            /////////////////////////////////
            if (lastSection != -1) {
                [self.myTableView reloadSections:[NSIndexSet indexSetWithIndex:lastSection] withRowAnimation:UITableViewRowAnimationAutomatic];
            }
            /////////////////////////////////
            // open new section
            /////////////////////////////////
            [self.myTableView reloadSections:[NSIndexSet indexSetWithIndex:familyCauseSection.tag] withRowAnimation:UITableViewRowAnimationAutomatic];
        }
        
        [self.myTableView endUpdates];
    }
    Basically that's it :)
    If you have more questions, please ask so. And for Dejo, sorry for misusing the UI letters.
     
  6. tsuru thread starter macrumors member

    Joined:
    Dec 14, 2008
    #6
    Woah jnoxx, that's got to be one of the most thorough replies I've received in a forum before. —And you clearly have a much superior sense for logic than I…

    It's going to take me a while to fully absorb what you wrote, but I'll see if I can't get something working. You wouldn't happen to know of any code samples on the web that demonstrate similar to what you wrote above would you? I'm more of a designer so seeing code in context helps a lot.

    Again, thank you!
     
  7. jnoxx, May 22, 2012
    Last edited: May 22, 2012

    jnoxx macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #7
    Hmm, I made this for a project I did a while back, so I don't know of any tutorials :) I'd say, if you have more specific questions, please head back.
    You do need to know how to create custom objects and make your own View Sections etc.

    PS: that exact same code is also used in another project from us called VikingSpots ->
    http://itunes.apple.com/be/app/vikingspots/id514959748?mt=8 This is not advertising, but as you can see on the screenshots, that is that arrow that will rotate, and will have the same animation :)
     
  8. tsuru, May 23, 2012
    Last edited: May 23, 2012

    tsuru thread starter macrumors member

    Joined:
    Dec 14, 2008
    #9
    Thanks for the replies guys.

    I found this bit of code that does what I was looking for: http://dotnet.kapenilattex.com/?p=656

    Now I just need to figure out how to implement adding and reordering of rows (haven't had any luck so far)… Any pointers on how I could go about doing that with the linked code? Even a general push towards the right direction would be greatly appreciated.
     

Share This Page