基于视图的 NSTableView 的过滤和动画

9
我有一个基于视图的NSTableView,有时会使用NSPredicate进行筛选。有没有办法通过在tableview中动态添加/删除/重新排序项来实现与beginUpdatesendUpdatesinsertRowsAtIndexes:withAnimation相同的效果?
我已经尝试了手动过滤数组的方法,但是尝试都失败了。因此,我想知道是否有更好(或内置的)方法来做到这一点。我在想NSArrayController是否会自动处理这个问题,但我认为它不会这样做。

2
很抱歉,没有内置的功能。 - Max Seelemann
NSCollectionView支持此功能! - bijan
我见过的最接近的东西是针对基于单元格的表格:http://www.mactech.com/articles/mactech/Vol.18/18.11/1811TableTechniques/index.html - sbooth
我在那个页面上看不到任何关于过滤器或谓词的内容 - 你指的是什么? - Bryan
1个回答

5

我已经编写了相关代码 - 给定“before”和“after”数组,计算出需要插入的行数、删除的行数等参数来使用insertRowsAtIndexPaths:deleteRowsAtIndexPaths:等函数。这段代码有些繁琐,可能存在一些错误 - 请谨慎使用!

@interface NSArray (ArrayDifference)
  - (void) computeDifferenceTo:(NSArray *)newArray returningAdded:(NSMutableArray **)rowsAdded andDeleted:(NSMutableArray **)rowsDeleted;
@end

@implementation NSArray (ArrayDifference)

// Given two arrays that are expected have items added or removed but not re-ordered, compute the differences
// in a way usable for UITable insertRows and deleteRows
- (void) computeDifferenceTo:(NSArray *)newArray returningAdded:(NSMutableArray **)rowsAdded andDeleted:(NSMutableArray **)rowsDeleted
{
  NSArray *oldArray = self;
  *rowsAdded = [[[NSMutableArray alloc] init] autorelease];
  *rowsDeleted = [[[NSMutableArray alloc] init] autorelease];

  NSUInteger oldCount = [oldArray count];
  NSUInteger newCount = [newArray count];
  // Step through the two arrays
  NSInteger oldIndex = 0, newIndex=0;
  for (; newIndex < newCount && oldIndex < oldCount; )
  {
    id newItem = [newArray objectAtIndex:newIndex];
    id oldItem = [oldArray objectAtIndex:oldIndex];
    // If the two objects match, we step forward on both sides
    if (newItem == oldItem) {
        ++newIndex;
        ++oldIndex;
    }
    else {
        // Look for the old item to appear later in the new array, which would mean we have to add the rows in between
        NSRange range = { newIndex+1, newCount - newIndex-1 };
        NSUInteger foundIndex = [newArray indexOfObject:oldItem inRange:range];
        if (foundIndex != NSNotFound)
            for (; newIndex < foundIndex; ++newIndex)
                [*rowsAdded addObject:[NSIndexPath indexPathForRow:newIndex inSection:0]];
        else {
            // Look for the new item to appear later in the old array, which would mean we have to remove the rows in between
            NSRange range = { oldIndex+1, oldCount - oldIndex-1 };
            NSUInteger foundIndex = [oldArray indexOfObject:newItem inRange:range];
            if (foundIndex != NSNotFound)
                for (; oldIndex < foundIndex; ++oldIndex)
                    [*rowsDeleted addObject:[NSIndexPath indexPathForRow:oldIndex inSection:0]];
            else {
                // Old item must be removed and new item added, then we carry on
                [*rowsAdded addObject:[NSIndexPath indexPathForRow:newIndex++ inSection:0]];
                [*rowsDeleted addObject:[NSIndexPath indexPathForRow:oldIndex++ inSection:0]];
            }
        }
    }
  }
  // Once the loop is finished, add in what's left in the new array and remove what is left in the old array
  for (; newIndex < newCount; ++newIndex)
    [*rowsAdded addObject:[NSIndexPath indexPathForRow:newIndex inSection:0]];
  for (; oldIndex < oldCount; ++oldIndex)
    [*rowsDeleted addObject:[NSIndexPath indexPathForRow:oldIndex inSection:0]];
}

@end

然后您可以这样调用它:
    NSMutableArray *rowsAdded=nil, *rowsDeleted=nil;
    [myArray computeDifferenceTo:newArray returningAdded:&rowsAdded andDeleted:&rowsDeleted];
    [myTableView beginUpdates];
    [myTableView insertRowsAtIndexPaths:rowsAdded withRowAnimation:UITableViewRowAnimationBottom];
    [myTableView deleteRowsAtIndexPaths:rowsDeleted withRowAnimation:UITableViewRowAnimationFade];
    [myTableView endUpdates];

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