UITableView中的moveRowAtIndexPath导致不正确的动画 [英] moveRowAtIndexPath in UITableView causes incorrect animation

查看:743
本文介绍了UITableView中的moveRowAtIndexPath导致不正确的动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的UITableView控制器显示CoreData。我试图实现 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath;并有动画的麻烦。



如何让动画正确反映核心数据对象发生的变化?



例如:



初始订单:





第2项到顶部:





或,初始订单:





将项目1移动到位置3后:





以下是相关代码:

   - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
// this实现是从本教程:http://www.cimgf.com/2010/06/05/re-ordering-nsfetchedresultscontroller/
NSMutableArray * things = [[fetchedResultsController fetchedObjects] mutableCopy];

//抓取我们正在移动的项目。
NSManagedObject * thing = [fetchedResultsController objectAtIndexPath:fromIndexPath];

//删除我们从数组中移动的对象。
[things removeObject:thing];
//现在重新插入到目的地。
[things insertObject:thing atIndex:[toIndexPath row]];

//所有对象现在都处于正确的顺序。通过遍历数组更新每个
//对象的displayOrder字段。


int i = 0;
for(NSManagedObject * mo in things)
{
[mo setValue:[NSNumber numberWithInt:i ++] forKey:@order];
}


NSLog(@things:%@,things);
[things release],things = nil;

[managedObjectContext save:nil];
}

和委托:



(NSFetchedResultsChangeType)类型newIndexPath:(NSIndexPath *)newIndexPath {NSFetchedResultsController *)控制器didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:
NSLog(@didChangeObject:);
UITableView * tableView = self.tableView;

switch(type){
case NSFetchedResultsChangeInsert:
NSLog(@ResultsChangeInsert:);
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;

case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;

case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}


解决方案

问题是由代理干扰我的重排序实现造成的。
在保存ManagedObjectContext之前添加了一个bool:


reordering = YES;
[managedObjectContext save:nil];


并使用它跳过任何FetchedResultsController委托函数。不是最好的解决方案,但它适用于这个实现。我会感谢任何评论/答案解释为什么这种情况发生。

  / ** 
委派NSFetchedResultsController的方法来响应添加,删除等。
* /

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {

if(!reordering){

提取控制器即将开始发送更改通知,因此请准备表视图以进行更新。
NSLog(@controllerWillChangeContent:);

[self.tableView beginUpdates];

}

}


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath: NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
if(!reordering){

NSLog(@didChangeObject:);
UITableView * tableView = self.tableView;

switch(type){
case NSFetchedResultsChangeInsert:
NSLog(@ResultsChangeInsert:);
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;

case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;

/ * case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break; * /
}

}
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection: < NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
if(!reordering){

NSLog(@didChangeSelection:
switch(type){
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;

case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
if(!reordering){

NSLog(@didChangeContent:);
//获取控制器已发送所有当前更改通知,因此请告知表视图来处理所有更新。
[self.tableView endUpdates];
} else {
reordering = NO;
}

}


I have a simple UITableView Controller that shows CoreData. I'm trying to implement - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath; and having trouble with the animation. The Core Data store gets updated, but the animation is not working.

How can I get the animation to correctly reflect the changes that are happening to the core data objects?

For example:

Initial order:

After item 2 to the top:

or, Initial Order:

After moving item 1 to position 3:

Here's the relevant code:

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
//this implementation is from this tutorial: http://www.cimgf.com/2010/06/05/re-ordering-nsfetchedresultscontroller/
NSMutableArray *things = [[fetchedResultsController fetchedObjects] mutableCopy];

// Grab the item we're moving.
NSManagedObject *thing = [fetchedResultsController objectAtIndexPath:fromIndexPath];

// Remove the object we're moving from the array.
[things removeObject:thing];
// Now re-insert it at the destination.
[things insertObject:thing atIndex:[toIndexPath row]];

// All of the objects are now in their correct order. Update each
// object's displayOrder field by iterating through the array.


int i = 0;
for (NSManagedObject *mo in things)
{
    [mo setValue:[NSNumber numberWithInt:i++] forKey:@"order"];
}


NSLog(@"things: %@", things);
[things release], things = nil; 

[managedObjectContext save:nil];            
}

and the delegate:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
NSLog(@"didChangeObject:");
UITableView *tableView = self.tableView;

switch(type) {
    case NSFetchedResultsChangeInsert:
        NSLog(@"ResultsChangeInsert:");
        [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeDelete:
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeMove:
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;
}
}

解决方案

The problem was caused by the delegate interfering with my reordering implementation. I added a bool before saving my ManagedObjectContext:

reordering = YES; [managedObjectContext save:nil];

and used it to skip out of any of the FetchedResultsController Delegate functions. Not the best solution, but it works for this implementation. I'd be grateful for any comments / answers explaining why this happened.

/**
Delegate methods of NSFetchedResultsController to respond to additions, removals and so  on.
*/

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {

if (!reordering) {

// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
NSLog(@"controllerWillChangeContent:");

[self.tableView beginUpdates];

}

}


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
if (!reordering) {

    NSLog(@"didChangeObject:");
    UITableView *tableView = self.tableView;

    switch(type) {
        case NSFetchedResultsChangeInsert:
            NSLog(@"ResultsChangeInsert:");
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        /*case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;*/
    }

}
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
if (!reordering) {

    NSLog(@"didChangeSelection:");
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
if (!reordering) {

    NSLog(@"didChangeContent:");
    // The fetch controller has sent all current change notifications, so tell the table view to process all updates.
    [self.tableView endUpdates];
}else {
    reordering = NO;
}

}

这篇关于UITableView中的moveRowAtIndexPath导致不正确的动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆