在 commitEditingStyle 中延迟模型和 table 视图更改
Delaying the model and table view change in commitEditingStyle
模型变化和行动画是否必须直接从commitEditingStyle
开始,还是可以在以后的运行循环迭代中完成?
我问是因为它似乎在 iOS 10 上有效,但在 iOS 11 上它至少破坏了删除动画。它只是 iOS 11 中的一个错误还是一般来说是个坏主意?
是否有更好的方法来触发异步删除操作并在完成时为 table 视图更改设置动画?
第一张图片显示了它如何在 iOS 11 处中断(删除按钮与下一个单元格重叠)。第二张图片显示了它在 iOS 10 上的表现如何。
这是有趣的片段:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
dispatch_async(dispatch_get_main_queue(), ^{
[_model removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
});
}
}
如果我删除 dispatch_async(...
,它会在 iOS 10 和 11 上按预期工作。第一张图片显示 iOS 11,第二张图片显示 iOS 10。
这是用于测试它的 table 视图控制器的完整代码:
#import "TableViewController.h"
@implementation TableViewController {
NSMutableArray<NSString *>* _model;
}
- (void)viewDidLoad {
[super viewDidLoad];
_model = [[NSMutableArray alloc] init];
[self.tableView registerClass:UITableViewCell.class forCellReuseIdentifier:@"cell"];
for (NSInteger i = 0; i < 200; i++) {
[_model addObject:[NSString stringWithFormat:@"Test Row %ld Test Test Test Test Test", (long)i]];
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _model.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
cell.textLabel.text = _model[indexPath.row];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
dispatch_async(dispatch_get_main_queue(), ^{
[_model removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
});
}
}
@end
更新:
将此方法添加到 table 视图控制器可修复 iOS 11 并允许延迟模型更改和行动画。 (感谢 ChrisHaze)
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(11_0) {
UIContextualAction* deleteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"Delete" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
dispatch_async(dispatch_get_main_queue(), ^{
[_model removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
completionHandler(YES);
});
}];
UISwipeActionsConfiguration* config = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction]];
return config;
}
iOS11 中的 UITable 视图似乎发生了变化。
Apple 的构建版本说明:
"The behavior of the delete swipe action has been changed.When implementing commitEditingStyle: to delete a swiped row, delete the row in the data source and call deleteRowsAtIndexPaths: on the table view to show the swipe delete animation."
经过进一步研究,我发现必须在调用 deleteRowAtIndexPath:
方法之前调用 beginUpdates
,然后再调用 endUpdates
方法。
根据 Apple 的 documentation,不调用这些 tableView 方法将导致潜在的数据模型问题并影响删除动画。
话虽如此,有一个 answer 包含 Apple 开发论坛上一个问题所需的代码,该问题解决了一个非常相似的问题。
回答您的实际问题:
- 需要在 beginUpdates 和 endUpdates 块之前调用模型更改,其中将发生 UI 更改。
- 更新 UITable 视图将缓解 synchronization/animation 问题。
---------------------------- additional details------------ --------------
在查看了您评论中的详细信息后,我提供了一个 link(上图),这是 Apple 提供的最新 Table 查看编程指南。它将带您或遇到此问题的任何其他人到指南的部分,其中包含您添加到问题中的详细信息。
还有一个方便的 note,其中包括如何在必须时从 commitEditingStyle
方法中进行 deleteRowAtIndexPath
调用。
模型变化和行动画是否必须直接从commitEditingStyle
开始,还是可以在以后的运行循环迭代中完成?
我问是因为它似乎在 iOS 10 上有效,但在 iOS 11 上它至少破坏了删除动画。它只是 iOS 11 中的一个错误还是一般来说是个坏主意?
是否有更好的方法来触发异步删除操作并在完成时为 table 视图更改设置动画?
第一张图片显示了它如何在 iOS 11 处中断(删除按钮与下一个单元格重叠)。第二张图片显示了它在 iOS 10 上的表现如何。
这是有趣的片段:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
dispatch_async(dispatch_get_main_queue(), ^{
[_model removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
});
}
}
如果我删除 dispatch_async(...
,它会在 iOS 10 和 11 上按预期工作。第一张图片显示 iOS 11,第二张图片显示 iOS 10。
这是用于测试它的 table 视图控制器的完整代码:
#import "TableViewController.h"
@implementation TableViewController {
NSMutableArray<NSString *>* _model;
}
- (void)viewDidLoad {
[super viewDidLoad];
_model = [[NSMutableArray alloc] init];
[self.tableView registerClass:UITableViewCell.class forCellReuseIdentifier:@"cell"];
for (NSInteger i = 0; i < 200; i++) {
[_model addObject:[NSString stringWithFormat:@"Test Row %ld Test Test Test Test Test", (long)i]];
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _model.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
cell.textLabel.text = _model[indexPath.row];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
dispatch_async(dispatch_get_main_queue(), ^{
[_model removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
});
}
}
@end
更新:
将此方法添加到 table 视图控制器可修复 iOS 11 并允许延迟模型更改和行动画。 (感谢 ChrisHaze)
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(11_0) {
UIContextualAction* deleteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"Delete" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
dispatch_async(dispatch_get_main_queue(), ^{
[_model removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
completionHandler(YES);
});
}];
UISwipeActionsConfiguration* config = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction]];
return config;
}
iOS11 中的 UITable 视图似乎发生了变化。
Apple 的构建版本说明:
"The behavior of the delete swipe action has been changed.When implementing commitEditingStyle: to delete a swiped row, delete the row in the data source and call deleteRowsAtIndexPaths: on the table view to show the swipe delete animation."
经过进一步研究,我发现必须在调用 deleteRowAtIndexPath:
方法之前调用 beginUpdates
,然后再调用 endUpdates
方法。
根据 Apple 的 documentation,不调用这些 tableView 方法将导致潜在的数据模型问题并影响删除动画。
话虽如此,有一个 answer 包含 Apple 开发论坛上一个问题所需的代码,该问题解决了一个非常相似的问题。
回答您的实际问题:
- 需要在 beginUpdates 和 endUpdates 块之前调用模型更改,其中将发生 UI 更改。
- 更新 UITable 视图将缓解 synchronization/animation 问题。
---------------------------- additional details------------ --------------
在查看了您评论中的详细信息后,我提供了一个 link(上图),这是 Apple 提供的最新 Table 查看编程指南。它将带您或遇到此问题的任何其他人到指南的部分,其中包含您添加到问题中的详细信息。
还有一个方便的 note,其中包括如何在必须时从 commitEditingStyle
方法中进行 deleteRowAtIndexPath
调用。