前提:让 UICollectionView 实现像 UITableView 一样的拖拽效果,同时使用 CoreData 作为数据源,那么也需要使 NSFetchedResultsController能和 UICollectionView 很好地配合。在 Github 上找到了两个分别解决 NSFetchedResultsController配合与 cell 拖拽的方案,独自工作效果很好,但结合到一起就悲剧了。 UICollectionView + NSFetchedResultsController + CoreData 的适配方案在这里:https://github.com/AshFurrow/UICollectionView-NSFetchedResultsController 虽然我对其中一部分代码()有所怀疑,但是工作起来基本上没有问题。 也找到了这个来实现类似 UITableView 里的 cell 的拖拽移动:https://github.com/lukescott/DraggableCollectionView/blob/master/DraggableCollectionView/UICollectionView%2BDraggable.m。这个方案的代码我还没看明白,但是这个方案独自工作起来也没有问题。 DraggableCollectionView这个扩展是这样工作的
It works just like UITableView. The extended protocol contains similarly named methods related to drag and drop found in the UITableViewDataSource protocol. The moveItemAtIndexPath:toIndexPath method is only called once - when the user lifts their finger. This is acomplished by "warping" the cells by modifying the output from the layoutAttributesForElementsInRect method. This allows you to physically move the cells around without touching the data source.
在 UICollectionView的 moveItemAtIndexPath:toIndexPath:方法移动 cell之前,需要将 data source 做对应调整:
- (void)collectionView:(LSCollectionViewHelper *)collectionView moveItemAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *data1 = [sections objectAtIndex:fromIndexPath.section];
NSMutableArray *data2 = [sections objectAtIndex:toIndexPath.section];
NSString *index = [data1 objectAtIndex:fromIndexPath.item];
[data1 removeObjectAtIndex:fromIndexPath.item];
[data2 insertObject:index atIndex:toIndexPath.item];
}
为了满足我的需求,我将UICollectionView 的 data source 从一个 NSArray 切换到 CoreData 和 NSFetchedResultController。之前的效果如下:
我新建了 Serail 这个 NSManagedObject 这个子类,其属性如下: @property (nonatomic, retain) NSString * alphabeticPart; @property (nonatomic) int32_t number; @property (nonatomic) double orderPart;
在 NSFetchedResultsController中如此设置,利用alphabeticPart来作为 section的 key,在 section 中利用 orderPart 来决定顺序,移动 cell 的位置后orderPart 设为前后 cell 的 orderPart 值的中间值已保证在同一个 section 内的顺序依然是通过 orderPart 的升序排列的。
这么左后,移动cell 后会出现同样的两个 cell,只有调用[self.collectionview reloadData]后才显示正常,而移动到其他 section 后会收到 layout 的错误导致崩溃。
类似这样:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to move index path (