【问题标题】:Expand/collapse section in UITableView in iOSiOS UITableView 中的展开/折叠部分
【发布时间】:2010-12-28 16:15:05
【问题描述】:

有人可以告诉我在sectionsUITableView 中执行UITableView 可扩展/可折叠动画的方法如下吗?

【问题讨论】:

标签: ios iphone uitableview object


【解决方案1】:

您必须制作自己的自定义标题行并将其作为每个部分的第一行。将UITableView 或已经存在的标头子类化会很痛苦。根据他们现在的工作方式,我不确定您是否可以轻松地从他们那里获得行动。您可以将单元格设置为看起来像标题,并设置 tableView:didSelectRowAtIndexPath 以手动展开或折叠它所在的部分。

我会存储一个布尔数组,对应于您每个部分的“消耗”值。然后,您可以让每个自定义标题行上的 tableView:didSelectRowAtIndexPath 切换此值,然后重新加载该特定部分。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == 0) {
        ///it's the first row of any section so it would be your custom section header

        ///put in your code to toggle your boolean value here
        mybooleans[indexPath.section] = !mybooleans[indexPath.section];

        ///reload this section
        [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
    }
}

然后设置numberOfRowsInSection 以检查mybooleans 的值,如果该部分未展开,则返回1,如果展开,则返回该部分中的项目数。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    if (mybooleans[section]) {
        ///we want the number of people plus the header cell
        return [self numberOfPeopleInGroup:section] + 1;
    } else {
        ///we just want the header cell
        return 1;
    }
}

此外,您需要更新 cellForRowAtIndexPath 以返回任何部分第一行的自定义标题单元格。

【讨论】:

  • 如果你使用过 Beejive 应用程序,你会知道他们的可折叠部分标题实际上“浮动”在表格顶部,即使你已经滚动浏览其部分部分,就像常规苹果部分标题。如果您只是在该部分的开头添加一个单元格,这是不可能的
  • 不错的优雅解决方案! user102008 在浮动标题上有一个点,但是在您真正希望“部分”滚动的情况下,这是一个很好的方法。
  • @mjdth 请给我任何示例代码bcz我需要一个特定的单元格隐藏/取消隐藏..提前谢谢
  • - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 是提供“自己的自定义标头”的更好方法,因为这正是它的设计目的。
  • 这最初对我有用,当我只有一个部分时,但一旦我有更多,我得到“无效更新无效行数”错误。我知道此解决方案较旧,但这仅适用于一个部分吗?如果我们有多个部分,我们是否需要添加实际添加/删除行的代码??
【解决方案2】:

我有一个更好的解决方案,您应该在节标题中添加一个 UIButton 并将此按钮的大小设置为等于节大小,但通过清晰的背景颜色将其隐藏,之后您可以轻松检查单击哪个节展开或崩溃

【讨论】:

  • 在我看来,此解决方案比公认的答案更好,因为从语义上讲,您将标题保留为标题,并且您不使用假行来模拟标题。方法tableView:numberOfRowsInSection: 将保持不变,您将继续能够将它用于它的真正含义。 tableView:cellForRowAtIndexPath: 也是如此。
  • 那么,您点击了部分标题中的按钮,但您将如何确定应该重新加载哪个部分?
  • @Answerbot 嗨,通过使用与节索引相同的值设置按钮标签非常容易。
  • 怕你这么说。为 tableView 索引之类的东西滥用标签属性是一个糟糕的设计选择。
  • 我从未见过任何“伟大”的解决方案,这就是为什么我希望你有不同的方法。我见过的最好的答案是 Apple 参考项目。 Apple 子类化 UITableViewHeaderFooterView 并添加 section 属性并定义 SectionHeaderViewDelegate 提供回调以打开/关闭该部分。 (developer.apple.com/library/ios/samplecode/TableViewUpdates/…)
【解决方案3】:

Apple 在此处提供了一些使用表格视图部分标题为展开/折叠操作设置动画的示例代码:Table View Animations and Gestures

这种方法的关键是实现- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 并返回一个包含按钮的自定义 UIView(通常与标题视图本身大小相同)。通过继承 UIView 并将其用于标题视图(如本示例所做的那样),您可以轻松存储其他数据,例如节号。

【讨论】:

  • 不记得了,但是为什么示例代码在 iOS 4 之前的版本中不起作用?
  • 我不知道。它只是说“iOS 4.0.2 或更高版本”
  • 链接处当前更新的代码有bug,很容易崩溃
  • 就像之前提到的 Ankit Srivastava 一样,很容易破坏这个代码示例:只需复制并粘贴 PlaysAndQuotations.plist 中的所有项目字典(我已经用根字典中的 30 个条目对此进行了测试) - 现在开始应用程序并打开第一个播放 - 之后向下滚动,直到看到一个向下的箭头(我认为这来自 dequeueReusableHeaderFooterViewWithIdentifier) - 单击该箭头并滚动回第一个播放并尝试关闭它 -> NSInternalInconsistencyException (iOS 8.4 / iPhone 5s)
【解决方案4】:

这是我发现创建可扩展表格视图单元格的最佳方式

.h 文件

  NSMutableIndexSet *expandedSections;

.m 文件

if (!expandedSections)
    {
        expandedSections = [[NSMutableIndexSet alloc] init];
    }
   UITableView *masterTable = [[UITableView alloc] initWithFrame:CGRectMake(0,100,1024,648) style:UITableViewStyleGrouped];
    masterTable.delegate = self;
    masterTable.dataSource = self;
    [self.view addSubview:masterTable];

表格视图委托方法

- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section
{
    // if (section>0) return YES;

    return YES;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    return 4;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if ([self tableView:tableView canCollapseSection:section])
    {
        if ([expandedSections containsIndex:section])
        {
            return 5; // return rows when expanded
        }

        return 1; // only top row showing
    }

    // Return the number of rows in the section.
    return 1;
}

- (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] ;
    }

    // Configure the cell...

    if ([self tableView:tableView canCollapseSection:indexPath.section])
    {
        if (!indexPath.row)
        {
            // first row
            cell.textLabel.text = @"Expandable"; // only top row showing

            if ([expandedSections containsIndex:indexPath.section])
            {

                UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UITableContract"]];
                cell.accessoryView = imView;
            }
            else
            {

                UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UITableExpand"]];
                cell.accessoryView = imView;
            }
        }
        else
        {
            // all other rows
            if (indexPath.section == 0) {
                cell.textLabel.text = @"section one";
            }else if (indexPath.section == 1) {
                cell.textLabel.text = @"section 2";
            }else if (indexPath.section == 2) {
                cell.textLabel.text = @"3";
            }else {
                cell.textLabel.text = @"some other sections";
            }

            cell.accessoryView = nil;
            cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
        }
    }
    else
    {
        cell.accessoryView = nil;
        cell.textLabel.text = @"Normal Cell";

    }

    return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([self tableView:tableView canCollapseSection:indexPath.section])
    {
        if (!indexPath.row)
        {
            // only first row toggles exapand/collapse
            [tableView deselectRowAtIndexPath:indexPath animated:YES];

            NSInteger section = indexPath.section;
            BOOL currentlyExpanded = [expandedSections containsIndex:section];
            NSInteger rows;


            NSMutableArray *tmpArray = [NSMutableArray array];

            if (currentlyExpanded)
            {
                rows = [self tableView:tableView numberOfRowsInSection:section];
                [expandedSections removeIndex:section];

            }
            else
            {
                [expandedSections addIndex:section];
                rows = [self tableView:tableView numberOfRowsInSection:section];
            }


            for (int i=1; i<rows; i++)
            {
                NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i 
                                                               inSection:section];
                [tmpArray addObject:tmpIndexPath];
            }

            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

            if (currentlyExpanded)
            {
                [tableView deleteRowsAtIndexPaths:tmpArray 
                                 withRowAnimation:UITableViewRowAnimationTop];

                UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UITableExpand"]];
                cell.accessoryView = imView;
            }
            else
            {
                [tableView insertRowsAtIndexPaths:tmpArray 
                                 withRowAnimation:UITableViewRowAnimationTop];

                UIImageView *imView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"UITableContract"]];
                cell.accessoryView = imView;
            }
        }
    }

    NSLog(@"section :%d,row:%d",indexPath.section,indexPath.row);

}

【讨论】:

  • 您可能应该将问题标记为完全重复的问题,而不是仅仅在所有问题上发送相同的答案。
  • 如果一个部分已经展开并单击另一个部分,则会出错
  • 您好先生,选定的索引高度如何更改?heightForRowAtIndexPath 如何使用您的代码?
  • 嗨,先生,如何导航到展开行的 didselected 上的另一个视图控制器?
【解决方案5】:

我最终只是创建了一个包含按钮的 headerView(事后我在上面看到了Son Nguyen's solution,但这是我的代码.. 看起来很多但很简单):

为你的部分声明几个布尔值

bool customerIsCollapsed = NO;
bool siteIsCollapsed = NO;

...代码

现在在您的 tableview 委托方法中...

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _tblSearchResults.frame.size.width, 35)];

    UILabel *lblSection = [UILabel new];
    [lblSection setFrame:CGRectMake(0, 0, 300, 30)];
    [lblSection setFont:[UIFont fontWithName:@"Helvetica-Bold" size:17]];
    [lblSection setBackgroundColor:[UIColor clearColor]];
    lblSection.alpha = 0.5;
    if(section == 0)
    {
        if(!customerIsCollapsed)
            [lblSection setText:@"Customers    --touch to show--"];
        else
            [lblSection setText:@"Customers    --touch to hide--"];
    }
    else
    {
        if(!siteIsCollapsed)
            [lblSection setText:@"Sites    --touch to show--"];
        else
            [lblSection setText:@"Sites    --touch to hide--"];    }

    UIButton *btnCollapse = [UIButton buttonWithType:UIButtonTypeCustom];
    [btnCollapse setFrame:CGRectMake(0, 0, _tblSearchResults.frame.size.width, 35)];
    [btnCollapse setBackgroundColor:[UIColor clearColor]];
    [btnCollapse addTarget:self action:@selector(touchedSection:) forControlEvents:UIControlEventTouchUpInside];
    btnCollapse.tag = section;


    [headerView addSubview:lblSection];
    [headerView addSubview:btnCollapse];

    return headerView;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    if(section == 0)
    {
        if(customerIsCollapsed)
            return 0;
        else
            return _customerArray.count;
    }
    else if (section == 1)
    {
        if(siteIsCollapsed)
            return 0;
        else
        return _siteArray.count;

    }
    return 0;
}

最后是当您触摸部分标题按钮时调用的函数:

- (IBAction)touchedSection:(id)sender
{
    UIButton *btnSection = (UIButton *)sender;

    if(btnSection.tag == 0)
    {
        NSLog(@"Touched Customers header");
        if(!customerIsCollapsed)
            customerIsCollapsed = YES;
        else
            customerIsCollapsed = NO;

    }
    else if(btnSection.tag == 1)
    {
        NSLog(@"Touched Site header");
        if(!siteIsCollapsed)
            siteIsCollapsed = YES;
        else
            siteIsCollapsed = NO;

    }
    [_tblSearchResults reloadData];
}

【讨论】:

  • 我只是想知道,该部分是否会折叠和展开动画或没有动画。如果没有动画,它看起来会很糟糕。我们怎样才能给它添加动画呢?
  • @Sam 如果您在折叠/展开方法中使用 [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade]; 之类的东西,它应该可以很好地制作动画。
【解决方案6】:

因此,基于“标题中的按钮”解决方案,这里是一个干净且简约的实现:

  • 您可以跟踪属性中的折叠(或展开)部分
  • 您使用部分索引标记按钮
  • 您在该按钮上设置了选中状态以更改箭头方向(如 △ 和 ▽)

代码如下:

@interface MyTableViewController ()
@property (nonatomic, strong) NSMutableIndexSet *collapsedSections;
@end

...

@implementation MyTableViewController

- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (!self)
        return;
    self.collapsedSections = [NSMutableIndexSet indexSet];
    return self;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // if section is collapsed
    if ([self.collapsedSections containsIndex:section])
        return 0;

    // if section is expanded
#warning incomplete implementation
    return [super tableView:tableView numberOfRowsInSection:section];
}

- (IBAction)toggleSectionHeader:(UIView *)sender
{
    UITableView *tableView = self.tableView;
    NSInteger section = sender.tag;

    MyTableViewHeaderFooterView *headerView = (MyTableViewHeaderFooterView *)[self tableView:tableView viewForHeaderInSection:section];

    if ([self.collapsedSections containsIndex:section])
    {
        // section is collapsed
        headerView.button.selected = YES;
        [self.collapsedSections removeIndex:section];
    }
    else
    {
        // section is expanded
        headerView.button.selected = NO;
        [self.collapsedSections addIndex:section];
    }

    [tableView beginUpdates];
    [tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationAutomatic];
    [tableView endUpdates];
}

@end

【讨论】:

    【解决方案7】:
    // -------------------------------------------------------------------------------
    //  tableView:viewForHeaderInSection:
    // -------------------------------------------------------------------------------
    - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    
        UIView *mView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 20, 20)];
        [mView setBackgroundColor:[UIColor greenColor]];
    
        UIImageView *logoView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 5, 20, 20)];
        [logoView setImage:[UIImage imageNamed:@"carat.png"]];
        [mView addSubview:logoView];
    
        UIButton *bt = [UIButton buttonWithType:UIButtonTypeCustom];
        [bt setFrame:CGRectMake(0, 0, 150, 30)];
        [bt setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
        [bt setTag:section];
        [bt.titleLabel setFont:[UIFont systemFontOfSize:20]];
        [bt.titleLabel setTextAlignment:NSTextAlignmentCenter];
        [bt.titleLabel setTextColor:[UIColor blackColor]];
        [bt setTitle: @"More Info" forState: UIControlStateNormal];
        [bt addTarget:self action:@selector(addCell:) forControlEvents:UIControlEventTouchUpInside];
        [mView addSubview:bt];
        return mView;
    
    }
    
    #pragma mark - Suppose you want to hide/show section 2... then
    #pragma mark  add or remove the section on toggle the section header for more info
    
    - (void)addCell:(UIButton *)bt{
    
        // If section of more information
        if(bt.tag == 2) {
    
            // Initially more info is close, if more info is open
            if(ifOpen) {
                DLog(@"close More info");
    
                // Set height of section
                heightOfSection = 0.0f;
    
                // Reset the parameter that more info is closed now
                ifOpen = NO;
            }else {
                // Set height of section
                heightOfSection = 45.0f;
                // Reset the parameter that more info is closed now
                DLog(@"open more info again");
                ifOpen = YES;
            }
            //[self.tableView reloadData];
            [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationFade];
        }
    
    }// end addCell
    #pragma mark -
    #pragma mark  What will be the height of the section, Make it dynamic
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    
        if (indexPath.section == 2) {
            return heightOfSection;
        }else {
            return 45.0f;
        }
    

    // vKj

    【讨论】:

      【解决方案8】:
      This action will happen in your didSelectRowAtIndexPath, when you will try to hide or show number of cell in a  section
      
      first of all declare a global variable numberOfSectionInMoreInfo in .h file and in your viewDidLoad set suppose to numberOfSectionInMoreInfo = 4.
      
      Now use following logic: 
      
      
       // More info link
              if(row == 3) {
      
                  /*Logic: We are trying to hide/show the number of row into more information section */
      
                  NSString *log= [NSString stringWithFormat:@"Number of section in more %i",numberOfSectionInMoreInfo];
      
                  [objSpineCustomProtocol showAlertMessage:log];
      
                  // Check if the number of rows are open or close in view
                  if(numberOfSectionInMoreInfo > 4) {
      
                      // close the more info toggle
                      numberOfSectionInMoreInfo = 4;
      
                  }else {
      
                      // Open more info toggle
                      numberOfSectionInMoreInfo = 9;
      
                  }
      
                  //reload this section
                  [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade];
      

      //vKj

      【讨论】:

      • 为什么有两个答案?您似乎没有针对该问题提供两种不同的解决方案。
      【解决方案9】:

      我找到了另一种相对简单的方法来解决这个问题。通过使用这种方法,我们将不需要更改几乎总是与数据数组索引相关的单元格,这可能会导致我们的视图控制器混乱。

      首先,我们将以下属性添加到我们的控制器类中:

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

      collapsedSections 将保存折叠的部分编号。 sectionViews 将存储我们的自定义剖面视图。

      合成它:

      @synthesize collapsedSections;
      @synthesize sectionViews;
      

      初始化它:

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

      之后,我们必须连接我们的 UITableView,以便可以从我们的视图控制器类中访问它:

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

      像往常一样使用ctrl + drag将它从XIB连接到视图控制器。

      然后我们通过实现这个 UITableView 委托为我们的表格视图创建视图作为自定义部分标题:

      - (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;
      }
      

      接下来,我们实现将我们之前创建的自定义节标题保存在类属性中的方法:

      - (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];
              }
          }
      }
      

      UIGestureRecognizerDelegate 添加到我们的视图控制器.h 文件中:

      @interface MyViewController : UIViewController<UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate>
      

      然后我们创建方法attachTapGestureToView:

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

      上述方法会将轻击手势识别器添加到我们之前创建的所有剖面视图中。接下来我们应该实现onTap:选择器

      - (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];
      }
      

      当用户点击我们的任何表格视图部分时,将调用上述方法。此方法根据我们之前创建的sectionViews 数组搜索正确的节号。

      此外,我们实现了获取标题视图所属部分的方法。

      - (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;
      }
      

      接下来,我们必须实现方法toggleCollapseSection:

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

      此方法将在我们之前创建的collapsedSections 数组中插入/删除节号。当一个节号插入该数组时,这意味着该节应折叠并展开,否则。

      接下来我们实现removeCollapsedSection:addCollapsedSection:sectionisCollapsedSection: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]];
      }
      

      这三个方法只是帮助我们更容易访问collapsedSections数组。

      最后,实现这个表视图委托,这样我们的自定义剖面视图看起来不错。

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

      希望对你有帮助。

      【讨论】:

        【解决方案10】:

        我得到了一个很好的解决方案,灵感来自 Apple 的 Table View Animations and Gestures。我从 Apple 的示例中删除了不必要的部分并将其翻译成 swift。

        我知道答案很长,但所有代码都是必需的。幸运的是,您可以复制和粘贴大部分代码,只需要对第 1 步和第 3 步进行一些修改

        1.创建SectionHeaderView.swiftSectionHeaderView.xib

        import UIKit
        
        protocol SectionHeaderViewDelegate {
            func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionOpened: Int)
            func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionClosed: Int)
        }
        
        class SectionHeaderView: UITableViewHeaderFooterView {
            
            var section: Int?
            @IBOutlet weak var titleLabel: UILabel!
            @IBOutlet weak var disclosureButton: UIButton!
            @IBAction func toggleOpen() {
                self.toggleOpenWithUserAction(true)
            }
            var delegate: SectionHeaderViewDelegate?
            
            func toggleOpenWithUserAction(userAction: Bool) {
                self.disclosureButton.selected = !self.disclosureButton.selected
                
                if userAction {
                    if self.disclosureButton.selected {
                        self.delegate?.sectionHeaderView(self, sectionClosed: self.section!)
                    } else {
                        self.delegate?.sectionHeaderView(self, sectionOpened: self.section!)
                    }
                }
            }
            
            override func awakeFromNib() {
                var tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "toggleOpen")
                self.addGestureRecognizer(tapGesture)
                // change the button image here, you can also set image via IB.
                self.disclosureButton.setImage(UIImage(named: "arrow_up"), forState: UIControlState.Selected)
                self.disclosureButton.setImage(UIImage(named: "arrow_down"), forState: UIControlState.Normal)
            }
            
        }
        

        SectionHeaderView.xib(灰色背景的视图)在 tableview 中应该看起来像这样(当然,您可以根据需要对其进行自定义):

        注意:

        a) toggleOpen 操作应链接到 disclosureButton

        b) disclosureButtontoggleOpen 操作不是必需的。如果你不需要按钮,你可以删除这两个东西。

        2.创建SectionInfo.swift

        import UIKit
        
        class SectionInfo: NSObject {
            var open: Bool = true
            var itemsInSection: NSMutableArray = []
            var sectionTitle: String?
            
            init(itemsInSection: NSMutableArray, sectionTitle: String) {
                self.itemsInSection = itemsInSection
                self.sectionTitle = sectionTitle
            }
        }
        

        3.在你的表格视图中

        import UIKit
        
        class TableViewController: UITableViewController, SectionHeaderViewDelegate  {
            
            let SectionHeaderViewIdentifier = "SectionHeaderViewIdentifier"
            
            var sectionInfoArray: NSMutableArray = []
            
            override func viewDidLoad() {
                super.viewDidLoad()
                
                let sectionHeaderNib: UINib = UINib(nibName: "SectionHeaderView", bundle: nil)
                self.tableView.registerNib(sectionHeaderNib, forHeaderFooterViewReuseIdentifier: SectionHeaderViewIdentifier)
                
                // you can change section height based on your needs
                self.tableView.sectionHeaderHeight = 30
                
                // You should set up your SectionInfo here
                var firstSection: SectionInfo = SectionInfo(itemsInSection: ["1"], sectionTitle: "firstSection")
                var secondSection: SectionInfo = SectionInfo(itemsInSection: ["2"], sectionTitle: "secondSection"))
                sectionInfoArray.addObjectsFromArray([firstSection, secondSection])
            }
            
            // MARK: - Table view data source
            
            override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
                return sectionInfoArray.count
            }
            
            override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                if self.sectionInfoArray.count > 0 {
                    var sectionInfo: SectionInfo = sectionInfoArray[section] as! SectionInfo
                    if sectionInfo.open {
                        return sectionInfo.open ? sectionInfo.itemsInSection.count : 0
                    }
                }
                return 0
            }
            
            override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
                let sectionHeaderView: SectionHeaderView! = self.tableView.dequeueReusableHeaderFooterViewWithIdentifier(SectionHeaderViewIdentifier) as! SectionHeaderView
                var sectionInfo: SectionInfo = sectionInfoArray[section] as! SectionInfo
                
                sectionHeaderView.titleLabel.text = sectionInfo.sectionTitle
                sectionHeaderView.section = section
                sectionHeaderView.delegate = self
                let backGroundView = UIView()
                // you can customize the background color of the header here
                backGroundView.backgroundColor = UIColor(red:0.89, green:0.89, blue:0.89, alpha:1)
                sectionHeaderView.backgroundView = backGroundView
                return sectionHeaderView
            }
            
            func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionOpened: Int) {
                var sectionInfo: SectionInfo = sectionInfoArray[sectionOpened] as! SectionInfo
                var countOfRowsToInsert = sectionInfo.itemsInSection.count
                sectionInfo.open = true
                
                var indexPathToInsert: NSMutableArray = NSMutableArray()
                for i in 0..<countOfRowsToInsert {
                    indexPathToInsert.addObject(NSIndexPath(forRow: i, inSection: sectionOpened))
                }
                self.tableView.insertRowsAtIndexPaths(indexPathToInsert as [AnyObject], withRowAnimation: .Top)
            }
            
            func sectionHeaderView(sectionHeaderView: SectionHeaderView, sectionClosed: Int) {
                var sectionInfo: SectionInfo = sectionInfoArray[sectionClosed] as! SectionInfo
                var countOfRowsToDelete = sectionInfo.itemsInSection.count
                sectionInfo.open = false
                if countOfRowsToDelete > 0 {
                    var indexPathToDelete: NSMutableArray = NSMutableArray()
                    for i in 0..<countOfRowsToDelete {
                        indexPathToDelete.addObject(NSIndexPath(forRow: i, inSection: sectionClosed))
                    }
                    self.tableView.deleteRowsAtIndexPaths(indexPathToDelete as [AnyObject], withRowAnimation: .Top)
                }
            }
        }
        

        【讨论】:

        • 感谢您为此付出的努力!在 github 上有一个小示例项目,这将是一个更好的答案
        • 感谢您提供详细的答案。示例项目会更好。
        【解决方案11】:

        要在iOS中实现可折叠表格部分,神奇的是如何控制每个部分的行数,或者我们可以管理每个部分的行高。

        另外,我们需要自定义section header,这样我们就可以从header区域监听tap事件(无论是按钮还是整个header)。

        如何处理表头?这很简单,我们扩展 UITableViewCell 类并制作一个自定义标题单元格,如下所示:

        import UIKit
        
        class CollapsibleTableViewHeader: UITableViewCell {
        
            @IBOutlet var titleLabel: UILabel!
            @IBOutlet var toggleButton: UIButton!
        
        }
        

        然后使用 viewForHeaderInSection 连接标题单元格:

        override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
          let header = tableView.dequeueReusableCellWithIdentifier("header") as! CollapsibleTableViewHeader
        
          header.titleLabel.text = sections[section].name
          header.toggleButton.tag = section
          header.toggleButton.addTarget(self, action: #selector(CollapsibleTableViewController.toggleCollapse), forControlEvents: .TouchUpInside)
        
          header.toggleButton.rotate(sections[section].collapsed! ? 0.0 : CGFloat(M_PI_2))
        
          return header.contentView
        }
        

        请记住,我们必须返回 contentView,因为此函数需要返回 UIView。

        现在我们来处理可折叠部分,这里是切换每个部分的可折叠道具的切换功能:

        func toggleCollapse(sender: UIButton) {
          let section = sender.tag
          let collapsed = sections[section].collapsed
        
          // Toggle collapse
          sections[section].collapsed = !collapsed
        
          // Reload section
          tableView.reloadSections(NSIndexSet(index: section), withRowAnimation: .Automatic)
        }
        

        取决于你如何管理部分数据,在这种情况下,我的部分数据是这样的:

        struct Section {
          var name: String!
          var items: [String]!
          var collapsed: Bool!
        
          init(name: String, items: [String]) {
            self.name = name
            self.items = items
            self.collapsed = false
          }
        }
        
        var sections = [Section]()
        
        sections = [
          Section(name: "Mac", items: ["MacBook", "MacBook Air", "MacBook Pro", "iMac", "Mac Pro", "Mac mini", "Accessories", "OS X El Capitan"]),
          Section(name: "iPad", items: ["iPad Pro", "iPad Air 2", "iPad mini 4", "Accessories"]),
          Section(name: "iPhone", items: ["iPhone 6s", "iPhone 6", "iPhone SE", "Accessories"])
        ]
        

        最后,我们需要做的是根据每个section的collapsible prop,控制那个section的行数:

        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
          return (sections[section].collapsed!) ? 0 : sections[section].items.count
        }
        

        我的 Github 上有一个完整的演示:https://github.com/jeantimex/ios-swift-collapsible-table-section

        如果您想在分组样式表中实现可折叠部分,我在这里有另一个带有源代码的演示:https://github.com/jeantimex/ios-swift-collapsible-table-section-in-grouped-section

        希望对您有所帮助。

        【讨论】:

        • 嗨,我在 xib 文件上做了我的自定义标题部分,并将 nib 注册到我的表视图控制器。当我删除一个部分并尝试再次展开/折叠时,我收到一个致命错误,指出索引超出范围。有没有什么办法解决这一问题?谢谢!
        • 非常好的和干净的解决方案!
        【解决方案12】:

        Apple 在Table View Animations and Gestures 提供了一些使用表格视图部分标题为展开/折叠动作设置动画的示例代码。

        这种方法的关键是实现

        - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

        并返回一个包含按钮的自定义 UIView(通常与标题视图本身大小相同)。通过继承 UIView 并将其用于标题视图(如本示例所做的那样),您可以轻松存储其他数据,例如节号。

        【讨论】:

          【解决方案13】:

          我使用了一个 NSDictionary 作为数据源,这看起来像很多代码,但它真的很简单而且效果很好! how looks here

          我为这些部分创建了一个枚举

          typedef NS_ENUM(NSUInteger, TableViewSection) {
          
              TableViewSection0 = 0,
              TableViewSection1,
              TableViewSection2,
              TableViewSectionCount
          };
          

          sections 属性:

          @property (nonatomic, strong) NSMutableDictionary * sectionsDisctionary;
          

          返回我的部分的方法:

          -(NSArray <NSNumber *> * )sections{
          
              return @[@(TableViewSection0), @(TableViewSection1), @(TableViewSection2)];
          }
          

          然后设置我的数据源:

          -(void)loadAndSetupData{
          
              self.sectionsDisctionary = [NSMutableDictionary dictionary];
          
              NSArray * sections = [self sections];
          
              for (NSNumber * section in sections) {
          
              NSArray * sectionObjects = [self objectsForSection:section.integerValue];
          
              [self.sectionsDisctionary setObject:[NSMutableDictionary dictionaryWithDictionary:@{@"visible" : @YES, @"objects" : sectionObjects}] forKey:section];
              }
          }
          
          -(NSArray *)objectsForSection:(NSInteger)section{
          
              NSArray * objects;
          
              switch (section) {
          
                  case TableViewSection0:
          
                      objects = @[] // objects for section 0;
                      break;
          
                  case TableViewSection1:
          
                      objects = @[] // objects for section 1;
                      break;
          
                  case TableViewSection2:
          
                      objects = @[] // objects for section 2;
                      break;
          
                  default:
                      break;
              }
          
              return objects;
          }
          

          接下来的方法,将帮助您了解何时打开一个部分,以及如何响应 tableview 数据源:

          将部分响应数据源:

          /**
           *  Asks the delegate for a view object to display in the header of the specified section of the table view.
           *
           *  @param tableView The table-view object asking for the view object.
           *  @param section   An index number identifying a section of tableView .
           *
           *  @return A view object to be displayed in the header of section .
           */
          - (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
          
              NSString * headerName = [self titleForSection:section];
          
              YourCustomSectionHeaderClass * header = (YourCustomSectionHeaderClass *)[tableView dequeueReusableHeaderFooterViewWithIdentifier:YourCustomSectionHeaderClassIdentifier];
          
              [header setTag:section];
              [header addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]];
              header.title = headerName;
              header.collapsed = [self sectionIsOpened:section];
          
          
              return header;
          }
          
          /**
           * Asks the data source to return the number of sections in the table view
           *
           * @param An object representing the table view requesting this information.
           * @return The number of sections in tableView.
           */
          - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
              // Return the number of sections.
          
              return self.sectionsDisctionary.count;
          }
          
          /**
           * Tells the data source to return the number of rows in a given section of a table view
           *
           * @param tableView: The table-view object requesting this information.
           * @param section: An index number identifying a section in tableView.
           * @return The number of rows in section.
           */
          - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
          
              BOOL sectionOpened = [self sectionIsOpened:section];
              return sectionOpened ? [[self objectsForSection:section] count] : 0;
          }
          

          工具:

          /**
           Return the section at the given index
          
           @param index the index
          
           @return The section in the given index
           */
          -(NSMutableDictionary *)sectionAtIndex:(NSInteger)index{
          
              NSString * asectionKey = [self.sectionsDisctionary.allKeys objectAtIndex:index];
          
              return [self.sectionsDisctionary objectForKey:asectionKey];
          }
          
          /**
           Check if a section is currently opened
          
           @param section the section to check
          
           @return YES if is opened
           */
          -(BOOL)sectionIsOpened:(NSInteger)section{
          
              NSDictionary * asection = [self sectionAtIndex:section];
              BOOL sectionOpened = [[asection objectForKey:@"visible"] boolValue];
          
              return sectionOpened;
          }
          
          
          /**
           Handle the section tap
          
           @param tap the UITapGestureRecognizer
           */
          - (void)handleTapGesture:(UITapGestureRecognizer*)tap{
          
              NSInteger index = tap.view.tag;
          
              [self toggleSection:index];
          }
          

          切换部分可见性

          /**
           Switch the state of the section at the given section number
          
           @param section the section number
           */
          -(void)toggleSection:(NSInteger)section{
          
              if (index >= 0){
          
                  NSMutableDictionary * asection = [self sectionAtIndex:section];
          
                  [asection setObject:@(![self sectionIsOpened:section]) forKey:@"visible"];
          
                  [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
              }
          }
          

          【讨论】:

            【解决方案14】:

            扩展 this 用 Objective C 编写的答案,我为那些用 Swift 编写的人写了以下内容

            想法是使用表格中的部分,并在点击该部分的第一行时将部分中的行数设置为 1(折叠)和 3(展开)

            表格根据布尔值数组决定绘制多少行

            您需要在情节提要中创建两行并为它们提供重用标识符“CollapsingRow”和“GroupHeading”

            import UIKit
            
            class CollapsingTVC:UITableViewController{
            
                var sectionVisibilityArray:[Bool]!// Array index corresponds to section in table
            
                override func viewDidLoad(){
                    super.viewDidLoad()
                    sectionVisibilityArray = [false,false,false]
                }
            
                override func viewDidAppear(_ animated: Bool) {
                    super.viewDidAppear(animated)
                }
            
                override func numberOfSections(in tableView: UITableView) -> Int{
                    return sectionVisibilityArray.count
                }
                override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat{
                    return 0
                }
            
                // numberOfRowsInSection - Get count of entries
                override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                    var rowsToShow:Int = 0
                    if(sectionVisibilityArray[section]){
                        rowsToShow = 3 // Or however many rows should be displayed in that section
                    }else{
                        rowsToShow = 1
                    }
                    return rowsToShow
                }// numberOfRowsInSection
            
            
                override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
                    if(indexPath.row == 0){
                        if(sectionVisibilityArray[indexPath.section]){
                            sectionVisibilityArray[indexPath.section] = false
                        }else{
                            sectionVisibilityArray[indexPath.section] = true
                        }
                        self.tableView.reloadSections([indexPath.section], with: .automatic)
                    }
                }
            
                // cellForRowAtIndexPath - Get table cell corresponding to this IndexPath
                override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            
                    var cell:UITableViewCell
            
                    if(indexPath.row == 0){
                         cell = tableView.dequeueReusableCell(withIdentifier: "GroupHeading", for: indexPath as IndexPath)
                    }else{
                        cell = tableView.dequeueReusableCell(withIdentifier: "CollapsingRow", for: indexPath as IndexPath)
                    }
            
                    return cell
            
                }// cellForRowAtIndexPath
            
            }
            

            【讨论】:

              【解决方案15】:

              我用多个部分做了同样的事情。

              class SCTierBenefitsViewController: UIViewController {
                  @IBOutlet private weak var tblTierBenefits: UITableView!
                  private var selectedIndexPath: IndexPath?
                  private var isSelected:Bool = false
              
                  override func viewDidLoad() {
                      super.viewDidLoad()
              
                      tblTierBenefits.register(UINib(nibName:"TierBenefitsTableViewCell", bundle: nil), forCellReuseIdentifier:"TierBenefitsTableViewCell")
                      tblTierBenefits.register(UINib(nibName:"TierBenefitsDetailsCell", bundle: nil), forCellReuseIdentifier:"TierBenefitsDetailsCell")
              
                      tblTierBenefits.rowHeight = UITableViewAutomaticDimension;
                      tblTierBenefits.estimatedRowHeight = 44.0;
                      tblTierBenefits.tableFooterView = UIView()
                  }
              
                  override func didReceiveMemoryWarning() {
                      super.didReceiveMemoryWarning()
                  }
              
              }
              
              extension SCTierBenefitsViewController : UITableViewDataSource{
              
                  func numberOfSections(in tableView: UITableView) -> Int {
                      return 7
                  }
                  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                      return (isSelected && section == selectedIndexPath?.section) ? 2 : 1 
                  }
              
                  func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
                      return  0.01
                  }
              
                  func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
                      return nil
                  }
              
                  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                      switch indexPath.row {
                      case 0:
                          let cell:TierBenefitsTableViewCell = tableView.dequeueReusableCell(withIdentifier: "TierBenefitsTableViewCell")! as! TierBenefitsTableViewCell
                          cell.selectionStyle = .none
                          cell.contentView.setNeedsLayout()
                          cell.contentView.layoutIfNeeded()
                          return cell
              
                      case 1:
                          let cell:TierBenefitsDetailsCell = tableView.dequeueReusableCell(withIdentifier: "TierBenefitsDetailsCell")! as! TierBenefitsDetailsCell
                          cell.selectionStyle = .none
                          return cell
              
                      default:
                          break
                      }
              
                      return UITableViewCell()
                  }
              }
              
              extension SCTierBenefitsViewController : UITableViewDelegate{
              
                  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
                      if indexPath.row == 0 {
              
                          if let _selectedIndexPath = selectedIndexPath ,selectedIndexPath?.section == indexPath.section {
                              tblTierBenefits.beginUpdates()
                              expandCollapse(indexPath: _selectedIndexPath, isExpand: false)
                              selectedIndexPath = nil
                          }
                          else{
                              tblTierBenefits.beginUpdates()
                              if selectedIndexPath != nil {
                                  tblTierBenefits.reloadSections([(selectedIndexPath?.section)!], with: .none)
                              }
                              expandCollapse(indexPath: indexPath, isExpand: true)
                          }
                      }
                  }
              
                  private func  expandCollapse(indexPath: IndexPath?,isExpand: Bool){
                      isSelected = isExpand
                      selectedIndexPath = indexPath
                      tblTierBenefits.reloadSections([(indexPath?.section)!], with: .none)
                      tblTierBenefits.endUpdates()
                  }
              
              }
              

              【讨论】:

                【解决方案16】:

                为了完整起见,我添加了这个解决方案,并展示了如何使用节标题。

                import UIKit
                
                class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
                
                    @IBOutlet var tableView: UITableView!
                    var headerButtons: [UIButton]!
                    var sections = [true, true, true]
                
                    override func viewDidLoad() {
                        super.viewDidLoad()
                        tableView.dataSource = self
                        tableView.delegate = self
                
                        let section0Button = UIButton(type: .detailDisclosure)
                        section0Button.setTitle("Section 0", for: .normal)
                        section0Button.addTarget(self, action: #selector(section0Tapped), for: .touchUpInside)
                
                        let section1Button = UIButton(type: .detailDisclosure)
                        section1Button.setTitle("Section 1", for: .normal)
                        section1Button.addTarget(self, action: #selector(section1Tapped), for: .touchUpInside)
                
                        let section2Button = UIButton(type: .detailDisclosure)
                        section2Button.setTitle("Section 2", for: .normal)
                        section2Button.addTarget(self, action: #selector(section2Tapped), for: .touchUpInside)
                
                        headerButtons = [UIButton]()
                        headerButtons.append(section0Button)
                        headerButtons.append(section1Button)
                        headerButtons.append(section2Button)
                    }
                
                    func numberOfSections(in tableView: UITableView) -> Int {
                        return sections.count
                    }
                
                    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
                        return sections[section] ? 3 : 0
                    }
                
                    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                        let cellReuseId = "cellReuseId"
                        let cell = UITableViewCell(style: .default, reuseIdentifier: cellReuseId)
                        cell.textLabel?.text = "\(indexPath.section): \(indexPath.row)"
                        return cell
                    }
                
                    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
                        return headerButtons[section]
                    }
                
                    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
                        return 44
                    }
                
                    @objc func section0Tapped() {
                        sections[0] = !sections[0]
                        tableView.reloadSections([0], with: .fade)
                    }
                
                    @objc func section1Tapped() {
                        sections[1] = !sections[1]
                        tableView.reloadSections([1], with: .fade)
                    }
                
                    @objc func section2Tapped() {
                        sections[2] = !sections[2]
                        tableView.reloadSections([2], with: .fade)
                    }
                
                }
                

                要点链接:https://gist.github.com/pawelkijowskizimperium/fe1e8511a7932a0d40486a2669316d2c

                【讨论】:

                  【解决方案17】:

                  支持@jean.timex 解决方案,如果您想随时打开一个部分,请使用以下代码。创建一个变量,如:var expandSection = -1;

                  func toggleSection(_ header: CollapsibleTableViewHeader, section: Int) {
                      let collapsed = !sections[section].collapsed
                      // Toggle collapse
                      sections[section].collapsed = collapsed
                      header.setCollapsed(collapsed)
                      tableView.reloadSections(NSIndexSet(index: section) as IndexSet, with: .automatic)
                      if (expandedSection >= 0 && expandedSection != section){
                          sections[expandedSection].collapsed = true
                          tableView.reloadSections(NSIndexSet(index: expandedSection) as IndexSet, with: .automatic)
                      }
                      expandedSection = section;
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 2014-12-25
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2019-08-31
                    • 2015-06-27
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多