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

3

我想使用动画来展开/折叠我的UITableView部分。 我使用了这个答案,并且现在它可以通过调用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 }
}

谢谢。

嘿!看看这个链接: https://dev59.com/iXI-5IYBdhLWcg3wQWGc?rq=1这个很老了,但可能会对你有所帮助。 - iOS_DEV
我使用了这个答案来设置一切。但是这个答案没有使用动画。我还将这个答案链接到了我的问题中。 - Mike_NotGuilty
非常抱歉,我没有在你的问题中看到链接。我稍后会发布我在某个项目中使用的代码。它在展开/折叠时使用动画效果。 - iOS_DEV
4个回答

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

2
快速提醒,你的 if ausgeklappt[tag]... 可以写成 ausgeklappt[tag] = !ausgeklappt[tag]; 来反转一个布尔值(假设这是一个 BOOL 数组)。 - Olie
Swift3: self.tableView.reloadSections(NSIndexSet(index: tag) as IndexSet, with: .automatic) Swift3:self.tableView.reloadSections(NSIndexSet(index:tag)as IndexSet,with:.automatic) - Tinkerbell
节省了我的时间 (y) - Darshan Mothreja

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的标签。


找到了答案。请查看我的回答 :-) 谢谢 - Mike_NotGuilty

1
基本上,当部分行模型发生更改并且我们更新、删除或插入几行时,tableview beginupdates & endplates 被使用。

然而,您的问题可能来自于 cellforHeight 或 cellforRowAtIndex,您需要在其中将部分放入 switch case 中。

谢谢


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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接