【问题标题】:iOS - Expand/Collapse UITableView section with animationsiOS - 展开/折叠带有动画的 UITableView 部分
【发布时间】:2014-12-25 04:16:13
【问题描述】:

我想用动画展开/折叠我的UITableView 部分。我使用了this 的答案,如果我打电话给self.tableView.reloadData(),它现在可以工作了。但是我希望当我点击我的自定义 UITableView- 标题时,该部分的单元格应该向下/向上滑动并带有漂亮的动画。我尝试使用self.tableView.beginUpdates()self.tableView.endUpdates(),但出现此错误:

Invalid update: invalid number of rows in section 0.  The number of rows contained in an 
existing section after the update (8) must be equal to the number of rows contained in that 
section before the update (0), plus or minus the number of rows inserted or deleted from 
that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out 
of that section (0 moved in, 0 moved out).

这里有一些代码。点击该部分时调用的方法:

func expand(sender:UITapGestureRecognizer){

    let tag = (sender.view?.tag)!

    self.tableView.beginUpdates()
    if ausgeklappt[tag] { ausgeklappt[tag] = false }
    else { ausgeklappt[tag] = true }

    self.tableView.endUpdates()
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // Return the number of rows in the section.
    let keyDerSection = sortSpieleDict.keys.array[section]
    let arrayDerSection = sortSpieleDict[keyDerSection]!
    if ausgeklappt[section] == false { return 0 } 
    else { return arrayDerSection.count }
}

谢谢。

【问题讨论】:

  • 嘿!查看此链接:stackoverflow.com/questions/1938921/… 这个很旧,但可能会对您有所帮助。
  • 我用这个答案来设置一切。但答案不使用动画。我还将答案链接到我的问题中。
  • 抱歉,我没有看到您问题中的链接。我将在一段时间内发布我在我的一个项目中使用的代码。它使用动画展开/折叠。

标签: ios iphone uitableview animation swift


【解决方案1】:

感谢 iOS_DEV,我找到了解决方案: 只需一行代码就可以解决问题。我刚刚用reloadSections() 方法替换了beginUpdates()endUpdates()。现在它工作正常!

    func expand(sender:UITapGestureRecognizer){

        let tag = (sender.view?.tag)! // The tag value is the section of my custom UITabelView header view.

        if ausgeklappt[tag] { ausgeklappt[tag] = false }
        else { ausgeklappt[tag] = true }

        // The next line did the trick! 
        self.tableView.reloadSections(NSIndexSet(index: tag), withRowAnimation: UITableViewRowAnimation.Automatic)
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Return the number of rows in the section.
        let keyDerSection = sortSpieleDict.keys.array[section]
        let arrayDerSection = sortSpieleDict[keyDerSection]!

        if ausgeklappt[section] == false 
        { 
             return 0 
        } 
        else 
        { 
             return arrayDerSection.count 
        }
    }

【讨论】:

  • 快速注意,您的 if ausgeklappt[tag]... 反转 bool 可以写成 ausgeklappt[tag] = !ausgeklappt[tag]; (假设这是一个 BOOL 数组。)
  • swift3: self.tableView.reloadSections(NSIndexSet(index: tag) as IndexSet, with: .automatic)
  • 节省了我的时间 (y)
【解决方案2】:

我使用 NSMutableSet 来跟踪点击的标题。我在响应以下事件的每个标题上放置了一个 UIButton:

#pragma mark - Header Clicked
-(void) headerClicked:(UIButton *) sender{

    if ([set_OpenIndex containsObject:[NSNumber numberWithUnsignedInteger:sender.tag]]) {
        [set_OpenIndex removeObject:[NSNumber numberWithUnsignedInteger:sender.tag]];
        [tableview_Main reloadSections:[NSIndexSet indexSetWithIndex:sender.tag] withRowAnimation:UITableViewRowAnimationAutomatic];
    }
    else{

        if (set_OpenIndex.count > 0) {
            //--- a header is opened already, close the previous one before opening the other

            [UIView animateWithDuration:0.5 animations:^{
                [set_OpenIndex enumerateObjectsUsingBlock:^(id obj, BOOL *stop){
                    [set_OpenIndex removeObject:obj];
                    [tableview_Main reloadSections:[NSIndexSet indexSetWithIndex:[obj integerValue]] withRowAnimation:UITableViewRowAnimationAutomatic];

                }];
            } completion:^(BOOL finished){

                [set_OpenIndex addObject:[NSNumber numberWithUnsignedInteger:sender.tag]];
                [tableview_Main reloadSections:[NSIndexSet indexSetWithIndex:sender.tag] withRowAnimation:UITableViewRowAnimationAutomatic];

            }];
        }
        else{
            [set_OpenIndex addObject:[NSNumber numberWithUnsignedInteger:sender.tag]];
            [tableview_Main reloadSections:[NSIndexSet indexSetWithIndex:sender.tag] withRowAnimation:UITableViewRowAnimationAutomatic];
        }
    }
}

只需设置行数如下:

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

    if ([set_OpenIndex containsObject:[NSNumber numberWithInteger:section]]) {
            return 5; // or what ever is the number of rows
        }

        return 0;
}

我已经用 Objective-C 编写了这段代码,因为我对 swift 的了解不多。这只是为了逻辑。请根据需要转换代码。

注意:不要忘记根据节号在header中设置UIButton的标签。

【讨论】:

  • 找到了答案。在下面检查我的答案:-) 谢谢
【解决方案3】:

基本上 tableview beginupdates & endplates 用于当 section-row 模型发生变化并且我们更新删除或插入几行时。

但是,您的问题必须来自您需要将部分放入 switch case 的 cellforHeight 或 cellforRowAtIndex。

谢谢

【讨论】:

    【解决方案4】:
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        [self initialization];
    }
    
    #pragma  mark - Initialization
    
    -(void)initialization
    {
        arrayForBool=[[NSMutableArray alloc]init];
        dic_data =[[NSMutableDictionary alloc]init];
        [dic_data setValue:@[@"1",@"2"] forKey:@"Section"];
        [dic_data setValue:@[@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8"] forKey:@"Section1"];
        [dic_data setValue:@[@"1",@"2",@"3",@"4"] forKey:@"Section2"];
    
        for (int i=0; i<dic_data.allKeys.count; i++) {
            [arrayForBool addObject:[NSNumber numberWithBool:NO]];
        }
    }
    
    
    #pragma mark -
    #pragma mark TableView DataSource and Delegate Methods
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
    
        if ([[arrayForBool objectAtIndex:section] boolValue]) {
            NSString *str =[dic_data.allKeys objectAtIndex:section];
            return [[dic_data valueForKey:str]count];
        }
        else
        return 0;
    
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *cellid=@"hello";
        UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellid];
        if (cell==nil) {
            cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellid];
        }
        NSString *str =[dic_data.allKeys objectAtIndex:indexPath.section];
    
        cell.textLabel.text = [[dic_data valueForKey:str]objectAtIndex:indexPath.row];
        return cell;
    }
    
    
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return dic_data.allKeys.count;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
    
        /*************** Close the section, once the data is selected ***********************************/
        [arrayForBool replaceObjectAtIndex:indexPath.section withObject:[NSNumber numberWithBool:NO]];
    
         [_expandableTableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationAutomatic];
    
    }
    
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if ([[arrayForBool objectAtIndex:indexPath.section] boolValue]) {
            return 40;
        }
        return 0;
    
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
    {
        return 40;
    }
    
    #pragma mark - Creating View for TableView Section
    
    - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
    {
    
        UIView *sectionView=[[UIView alloc]initWithFrame:CGRectMake(0, 0, 280,40)];
        sectionView.tag=section;
        UILabel *viewLabel=[[UILabel alloc]initWithFrame:CGRectMake(10, 0, _expandableTableView.frame.size.width-10, 40)];
        viewLabel.backgroundColor=[UIColor clearColor];
        viewLabel.textColor=[UIColor blackColor];
        viewLabel.font=[UIFont systemFontOfSize:15];
        NSString *str =[dic_data.allKeys objectAtIndex:section];
    
        viewLabel.text=[NSString stringWithFormat:@"List of %@",str];
        [sectionView addSubview:viewLabel];
    
        /********** Add UITapGestureRecognizer to SectionView   **************/
        UITapGestureRecognizer  *headerTapped   = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(sectionHeaderTapped:)];
        [sectionView addGestureRecognizer:headerTapped];
    
        return  sectionView;
    
    
    }
    
    
    #pragma mark - Table header gesture tapped
    
    - (void)sectionHeaderTapped:(UITapGestureRecognizer *)gestureRecognizer{
    
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:gestureRecognizer.view.tag];
        if (indexPath.row == 0) {
            BOOL collapsed  = [[arrayForBool objectAtIndex:indexPath.section] boolValue];
            for (int i=0; i<dic_data.allKeys.count; i++) {
                if (indexPath.section==i) {
                    [arrayForBool replaceObjectAtIndex:i withObject:[NSNumber numberWithBool:!collapsed]];
                }
            }
            [_expandableTableView reloadSections:[NSIndexSet indexSetWithIndex:gestureRecognizer.view.tag] withRowAnimation:UITableViewRowAnimationTop];
    
        }
    
    }
    

    我已经用 Objective-C 编写了这段代码,因为我对 swift 的了解不多。这只是为了逻辑。请根据需要转换代码。

    【讨论】:

      猜你喜欢
      • 2010-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-29
      • 1970-01-01
      • 2016-04-01
      • 1970-01-01
      相关资源
      最近更新 更多