首页 > 解决方案 > UITableView在插入时重复行

问题描述

我有一个表格视图控制器,它通过使用带有嵌入 segue 的 UIContainerView 显示在垂直堆栈视图中。这一切都很好。问题是,如果我尝试插入一行,我希望它为新行设置动画并更新堆栈视图中容器视图的高度,但问题是当它这样做时,它似乎重复了底行。

这是一个动画,显示正在发生的事情。在动画中的“项目 1”和项目 2 之间插入了一个新项目。该动画效果很好,但是如果您查看表格的底部,“项目 3”似乎被简单地复制了。这就是我正在尝试的修理。

显示表格动画行为的动画图像

这是显示视图结构的文档大纲。基本上有一个滚动视图,里面有一个堆栈视图。然后堆栈视图管理不同的视图,例如表格视图。现在,大多数视图只是彩色的 UIViews,但最终我希望它们都是加载外部视图控制器的 UIViewContainers,类似于现在对表视图控制器所做的事情。目标是让我可以在他们自己的视图控制器中实现每个部分,并将它们“插入”到堆栈视图或表格视图或其他任何东西中。

文件大纲

但我真正需要能够支持的一件事是让子视图控制器能够垂直调整大小,并在父视图控制器或 UIContainerView 中重新调整大小。这就是我遇到的问题,我无法弄清楚为什么会暂时复制这一行。

这是包含滚动视图和堆栈视图的视图控制器类。然后,堆栈视图包含 UIContainerView,该 UIContainerView 具有到表视图控制器的嵌入 segue(在代码中称为 MyTableViewController)。

MyStackViewScrollableViewController.m

#import "MyStackViewScrollableViewController.h"
#import "MyTableViewController.h"

@interface MyStackViewScrollableViewController ()
@property (weak, nonatomic) MyTableViewController *myTableViewController;
@end

@implementation MyStackViewScrollableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (IBAction)addARow:(id)sender {
    [self.myTableViewController insertRow];
}

- (void)preferredContentSizeDidChangeForChildContentContainer:(id<UIContentContainer>)container {
    [super preferredContentSizeDidChangeForChildContentContainer:container];
    
    if ([container isKindOfClass:[MyTableViewController class]]) {
        MyTableViewController *viewController = (MyTableViewController *)container;
        [UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{
            self.myTableViewControllerSectionHeightConstraint.constant = viewController.preferredContentSize.height;
            [self.view layoutIfNeeded];
        } completion:nil];
    }
}


#pragma mark - Navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"myTableViewControllerEmbedSegue"]) {
        self.myTableViewController = segue.destinationViewController;
    }
}

@end

这是表视图控制器类。这是由父视图(前一个类)通过来自 UIContainerView 的故事板嵌入 segue 加载的(我只是将容器视图拖到堆栈视图中,然后控制拖动到表视图控制器并为 segue 选择嵌入)。

MyTableViewController.m

#import "MyTableViewController.h"

@interface MyTableViewController ()
@property (strong, nonatomic) NSMutableArray<NSString *> *items;
@end

@implementation MyTableViewController

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    CGRect frame = self.tableView.frame;
    frame.size.height = [self.tableView sizeThatFits:CGSizeMake(frame.size.width, CGFLOAT_MAX)].height;
    
    self.preferredContentSize = frame.size;
}

- (void)insertRow {
    NSUInteger rowIndex = self.items.count == 0 ? 0 : 1;
    
    [self.items insertObject:[NSString stringWithFormat:@"New item %lu", self.items.count + 1] atIndex:rowIndex];
    
    [UIView beginAnimations:@"twisterTableAnimationId" context:nil];
    [UIView setAnimationDuration:1.0f];
    [CATransaction begin];
    [CATransaction setCompletionBlock:^{
        NSLog(@"animation complete");
    }];
    
    [self.tableView beginUpdates];
    [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:rowIndex inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
    [self.tableView endUpdates];
    
    [CATransaction commit];
    [UIView commitAnimations];
    
    CGRect frame = self.tableView.frame;
    frame.size.height = [self.tableView sizeThatFits:CGSizeMake(frame.size.width, CGFLOAT_MAX)].height;
    self.preferredContentSize = frame.size;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.items = [NSMutableArray arrayWithArray:@[@"Item 1", @"Item 2", @"Item 3"]];
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.items.count;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    CGSize preferredContentSize = self.preferredContentSize;
    self.preferredContentSize = CGSizeMake(preferredContentSize.width, preferredContentSize.height + 50);
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"StringCell" forIndexPath:indexPath];
    cell.textLabel.text = self.items[indexPath.row];
    return cell;
}

@end

有谁知道我可能做错了什么或如何在动画期间修复重复的底行?

标签: iosobjective-cuitableviewuistackviewuicontainerview

解决方案


推荐阅读