如何实现类似于Mail的UITableView行动画

Posted

技术标签:

【中文标题】如何实现类似于Mail的UITableView行动画【英文标题】:How to achieve UITableView row animation similar to Mail 【发布时间】:2014-06-20 16:51:21 【问题描述】:

在 Mail 中,如果您通过 pull to refresh 手动刷新邮箱,如果您没有任何新电子邮件,则视图会向后滑动以隐藏微调器,但现有单元格的外观不会改变 - 它们不会t 动画。但是,如果您确实有新的电子邮件,它们会从顶部开始显示。如果您在刷新之前没有列出任何电子邮件,那么所有单元格的动画效果都非常好。此外,如果您刷新并且现有电子邮件已被删除,它的消失是动画的,但除了整个表格向上移动以取代已删除的单元格之外,其他单元格都没有动画。我想在我的应用中实现同样的行为。

目前,当我的数据第一次被提取时,它立即出现在表格中,没有任何动画。如果某些数据被删除并且用户手动刷新,整个表格会立即更新,因此不会出现单元格消失的动画,它会立即被其下方的行替换。如果单元格已经显示并且刷新导致新数据被添加到表格中,则会发生相同的行为 - 它只是立即出现。

reloadData时如何实现单元格出现和消失的动画?但如果它们不改变,则不会为现有单元格设置动画。

我的设置是获取数据,将 JSON 解析为数据结构(数组或字典),然后调用reloadData,然后cellForRowAtIndexPath 从结构中获取数据。当用户刷新时,它会再次执行相同的步骤。

到目前为止,我的尝试都没有成功。我试过而不是简单地调用reloadData,而是调用[self.tableView reloadSections:[NSIndexSet indexsetWithIndex:0] withRowAnimation:UITableViewRowAnimationTop];,但这只会对第一部分进行动画处理,并且它始终会对其进行动画处理,即使没有任何数据发生变化。我的其他尝试也总是对其进行动画处理:

[self.tableView beginUpdates];
[self.tableView deleteSections:[NSIndexSet indexsetWithIndex:0] withRowAnimation:YES];
[self.tableView insertSections:[NSIndexSet indexsetWithIndex:0] withRowAnimation:YES];
[self.tableView endUpdates];

【问题讨论】:

【参考方案1】:

插入行时,将插入的索引路径保持在数组中,然后:

[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:arrayOfInsertedIndexPaths withRowAnimation: UITableViewRowAnimationTop];
[self.tableView endUpdates];

我还没有直接确认,但我很确定当现在插入时这会按照你的意愿行事。

编辑 - 行准确的动画将需要有关模型变化的行准确的知识。如何获取插入的索引路径取决于您获取数据的方式。在最艰难的情况下,您只是获得了一个新系列,需要自己弄清楚发生了什么变化。您的模型对象可能需要实现等价性**,因此您可以得出结论,应该将不同的实例视为相同。

** 就像NSString isEqualToString: 中的一样,这是一个等价测试,而不是顾名思义的等价测试。

我们比较的是对象本身,而不是行索引,因此了解删除很困难,但并不比了解插入更难。举个例子,这是我为 NSMutableArray 创建的一个类别,它只处理插入(它是电子邮件或其他时间线类型的应用程序的理想选择,它期待新的东西,而不是删除)。

#import "NSMutableArray+Inserts.h"

@implementation NSMutableArray (NSMutableArray_Inserts)

// insert elements of array into the receiver, sorting on a key
// answer an array of index paths where the insertions happened

- (NSArray *)insertFromArray:(NSArray *)array sortedOn:(NSString *)key ascending:(BOOL)ascending 

    // first insert everything from array (preserving uniqueness according to shallow equality)
    for (id newElement in array) 
        NSInteger position = [self indexOfObject:newElement];
        if (position == NSNotFound) [self addObject:newElement];
    

    // now sort using key
    [self sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:key ascending:ascending]]];

    // now find the insertions using deep equality
    NSMutableArray *answer = [NSMutableArray array];
    for (id newElement in array) 
        NSInteger position = [self indexOfObject:newElement];
        id element = [self objectAtIndex:position];
        if (element == newElement) 
            [answer addObject:[NSIndexPath indexPathForRow:position inSection:0]];
        
        
    return [NSArray arrayWithArray:answer];

几个注意事项:1)我懒惰地将索引路径部分硬编码为 0。如果您的模型有多个部分,您需要为每个部分调用它并添加一个部分参数,以便获得良好的索引路径,2 ) 此排序插入功能与我的特定应用程序相关,您可能不需要它,只需删除这两个参数并删除 self sortUsing... 行。 3) 解决删除问题的一种方法是添加一个类似的方法来回答接收器中元素的索引路径,而不是在传递的数组中。

【讨论】:

这可能会奏效,但是如何知道正在插入(和删除)哪些索引路径?我必须解析旧结构并将其与新结构进行比较,如果不同,存储适当的索引路径吗?我只是不确定您如何知道一行何时被删除,因为它可能在以后存在。这是正确的方法吗? @Joey,是的 - 更流畅的 UI 需要有关插入的详细知识。请查看我的编辑。

以上是关于如何实现类似于Mail的UITableView行动画的主要内容,如果未能解决你的问题,请参考以下文章

如何使用子视图的延迟/动态加载实现自定义 UIView,类似于 UITableView

UITableView 滚动类似于 Frontback 应用

实现一个类似于 UITableView 将已创建的单元格出列的方式的系统

我们如何获得类似于 ios 6 的 ios 7 的分组 UITableview 样式

如何在 UITableView Cell 中实现类似于 iOS 邮件的从左向右滑动

Android ListView 风格类似于 iPhone Grouped UITableView