Expand/collapse section in UITableView in iOS

前端 未结 17 1059
野的像风
野的像风 2020-11-22 08:49

Could somebody tell me the way to perform UITableView expandable/collapsible animations in sections of UITableView as below?

<

17条回答
  •  佛祖请我去吃肉
    2020-11-22 09:45

    I found another relatively simple way to solve that problem. By using this method we will not required to alter our cell which is almost always related to data array index, potentially causing mess in our view controller.

    First, we add this following properties to our controller class:

    @property (strong, nonatomic) NSMutableArray* collapsedSections;
    @property (strong, nonatomic) NSMutableArray* sectionViews;
    

    collapsedSections will save collapsed section numbers. sectionViews will store our custom section view.

    Synthesize it:

    @synthesize collapsedSections;
    @synthesize sectionViews;
    

    Initialize it:

    - (void) viewDidLoad
    {
        [super viewDidLoad];
    
        self.collapsedSections = [NSMutableArray array];
        self.sectionViews      = [NSMutableArray array];
    }
    

    After that, we must connect our UITableView so it can be accessed from within our view controller class:

    @property (strong, nonatomic) IBOutlet UITableView *tblMain;
    

    Connect it from XIB to view controller using ctrl + drag like usually.

    Then we create view as custom section header for our table view by implementing this UITableView delegate:

    - (UIView*) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
    {
        // Create View
        CGRect frame = CGRectZero;
    
        frame.origin = CGPointZero;
    
        frame.size.height = 30.f;
        frame.size.width  = tableView.bounds.size.width;
    
        UIView* view = [[UIView alloc] initWithFrame:frame];
    
        [view setBackgroundColor:[UIColor blueColor]];
    
        // Add label for title
        NSArray* titles = @[@"Title 1", @"Title 2", @"Title 3"];
    
        NSString* selectedTitle = [titles objectAtIndex:section];
    
        CGRect labelFrame = frame;
    
        labelFrame.size.height = 30.f;
        labelFrame.size.width -= 20.f;
        labelFrame.origin.x += 10.f;
    
        UILabel* titleLabel = [[UILabel alloc] initWithFrame:labelFrame];
    
        [titleLabel setText:selectedTitle];
        [titleLabel setTextColor:[UIColor whiteColor]];
    
        [view addSubview:titleLabel];
    
        // Add touch gesture
        [self attachTapGestureToView:view];
    
        // Save created view to our class property array
        [self saveSectionView:view inSection:section];
    
        return view;
    }
    

    Next, we implement method to save our previously created custom section header in class property:

    - (void) saveSectionView:(UIView*) view inSection:(NSInteger) section
    {
        NSInteger sectionCount = [self numberOfSectionsInTableView:[self tblMain]];
    
        if(section < sectionCount)
        {
            if([[self sectionViews] indexOfObject:view] == NSNotFound)
            {
                [[self sectionViews] addObject:view];
            }
        }
    }
    

    Add UIGestureRecognizerDelegate to our view controller .h file:

    @interface MyViewController : UIViewController
    

    Then we create method attachTapGestureToView:

    - (void) attachTapGestureToView:(UIView*) view
    {
        UITapGestureRecognizer* tapAction = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)];
    
        [tapAction setDelegate:self];
    
        [view addGestureRecognizer:tapAction];
    }
    

    Above method will add tap gesture recognizer to all of section view we created before. Next we should implement onTap: selector

    - (void) onTap:(UITapGestureRecognizer*) gestureRecognizer
    {
        // Take view who attach current recognizer
        UIView* sectionView = [gestureRecognizer view]; 
    
        // [self sectionViews] is Array containing our custom section views
        NSInteger section = [self sectionNumberOfView:sectionView];
    
        // [self tblMain] is our connected IBOutlet table view
        NSInteger sectionCount = [self numberOfSectionsInTableView:[self tblMain]];
    
        // If section more than section count minus one set at last
        section = section > (sectionCount - 1) ? 2 : section;
    
        [self toggleCollapseSection:section];
    }
    

    Above method will invoked when user tap any of our table view section. This method search correct section number based on our sectionViews array we created before.

    Also, we implement method to get wihch section of header view belongs to.

    - (NSInteger) sectionNumberOfView:(UIView*) view
    {
        UILabel* label = [[view subviews] objectAtIndex:0];
    
        NSInteger sectionNum = 0;
    
        for(UIView* sectionView in [self sectionViews])
        {
            UILabel* sectionLabel = [[sectionView subviews] objectAtIndex:0];
    
            //NSLog(@"Section: %d -> %@ vs %@", sectionNum, [label text], [sectionLabel text]);
    
            if([[label text] isEqualToString:[sectionLabel text]])
            {
                return sectionNum;
            }
    
            sectionNum++;
        }
    
        return NSNotFound;
    }
    

    Next, we must implement method toggleCollapseSection:

    - (void) toggleCollapseSection:(NSInteger) section
    {
        if([self isCollapsedSection:section])
        {
            [self removeCollapsedSection:section];
        }
        else
        {
            [self addCollapsedSection:section];
        }
    
        [[self tblMain] reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
    }
    

    This method will insert/remove section number to our collapsedSections array we created before. When a section number inserted to that array, it means that the section should be collapsed and expanded if otherwise.

    Next we implement removeCollapsedSection:, addCollapsedSection:section and isCollapsedSection:section

    - (BOOL)isCollapsedSection:(NSInteger) section
    {
        for(NSNumber* existing in [self collapsedSections])
        {
            NSInteger current = [existing integerValue];
    
            if(current == section)
            {
                return YES;
            }
        }
    
        return NO;
    }
    
    - (void)removeCollapsedSection:(NSInteger) section
    {
        [[self collapsedSections] removeObjectIdenticalTo:[NSNumber numberWithInteger:section]];
    }
    
    - (void)addCollapsedSection:(NSInteger) section
    {
        [[self collapsedSections] addObject:[NSNumber numberWithInteger:section]];
    }
    

    This three method is just helpers to make us easier in accessing collapsedSections array.

    Finally, implement this table view delegate so our custom section views looks nice.

    - (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
    {
        return 30.f; // Same as each custom section view height
    }
    

    Hope it helps.

提交回复
热议问题