iOS - 使用动画展开/折叠UITableView部分

时间:2014-10-29 12:44:56

标签: ios iphone uitableview animation swift

我想用动画展开/展开我的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 }
}

感谢。

4 个答案:

答案 0 :(得分:10)

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

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

答案 1 :(得分: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的知识。这只是为了逻辑。请根据您的需要转换代码。

注意:不要忘记根据章节编号在标题中设置UIButton的标记。

答案 2 :(得分:1)

当截面行模型发生变化并且我们更新删除或插入几行时,将使用基本的tableview beginupdates和endplates。

但是,您的问题必须出在cellforHeight或cellforRowAtIndex处,您需要将该部分放在切换大小写中。

谢谢

答案 3 :(得分:0)

- (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还不太了解。这只是为了逻辑。请根据您的需要转换代码。