UICollectionView将项目移动到新部分

时间:2015-11-12 22:58:03

标签: ios objective-c uicollectionview

我遇到了UICollectionView动画的严重问题,类似于此处提到的问题:UICollectionView crashes when rearranging items between sections

假设我有一个带有5个不同部分的UICollectionView,每个部分有10个单元格。 我想用动画更新CollectionView,因此单元格将被重新排序为10个部分。不会添加包含新内容的单元格,也不会删除现有单元格。

因此我正在执行批量更新:

 [_resultCollectionView performBatchUpdates:^{

        [_resultCollectionView insertSections:insertSections];
        [_resultCollectionView deleteSections:deleteSections];

        //[_resultCollectionView insertItemsAtIndexPaths:insertIndexPaths];
        //[_resultCollectionView deleteItemsAtIndexPaths:deleteIndexPaths];

        for (all items which need to be moved...) {
            [_resultCollectionView moveItemAtIndexPath:sourcePath toIndexPath:destinationPath];
        }

    } completion:^(BOOL finished) {
        //[_resultCollectionView reloadData];
        nil;
    }];

如果执行块执行 insertSections,deleteSections,insertItemsAtIndexPath,deleteItemsAtIndexPath和reloadData ,一切正常,这意味着我的dataSource和委托在理论上正常工作。除了它还没有动画......

如果我执行 insertSections,deleteSections和moveItemAtIndexPath (这应该可以工作,因为单元格只能重新排列)我得到这个小错误: 无法将行移动到新插入的部分(5)

如果我执行 insertSections,deleteSections和moveItemAtIndexPath 但排除任何移动到新插入的部分,我显然会在部分中获得无效的项目数。

有没有人能解决这个问题?

1 个答案:

答案 0 :(得分:0)

我遵循了john1034的链接并找到了一个非常棘手的方法。你必须分三步拆分工作:

  1. 必要时添加新部分。新的部分将首先为空。
  2. 在新部分和现有部分中添加,移除和移动单元格。
  3. 如有必要,删除部分。
  4. 确定有很多行可以进一步改进。特别是搜索功能效率很低......

    static BOOL addingSections = NO;
    static BOOL updatingCollectionView = NO;
    static BOOL removingSections = NO;
    
    - (void)reloadResultCollectionView
    
        //IndexUnloadedArray: a link to my CollectionViewData before the update
        //IndexArray: a link to my CollectionViewData after the update
    
        //start only if something changed
        if (![IndexArray isEqual:IndexUnloadedArray]) {
            NSMutableIndexSet *deleteSections = [[NSMutableIndexSet alloc] init];
            NSMutableIndexSet *insertSections = [[NSMutableIndexSet alloc] init];
            NSMutableArray *deleteIndexPaths = [[NSMutableArray alloc] init];
            NSMutableArray *insertIndexPaths = [[NSMutableArray alloc] init];
    
            //step 1 - add collectionView sections
    
            for (int i = 0; i < IndexArray.count; i++) {
                if (i >= IndexUnloadedArray.count) {
                    [insertSections addIndex:i];
                }
            }
            NSLog(@"insert sections:%@", insertSections);
    
            _sectionAmount = (int)_distanceUnloadedArray.count + (int)insertSections.count;
    
            addingSections = YES;
            [_resultCollectionView performBatchUpdates:^{
                [_resultCollectionView insertSections:insertSections];
            } completion:^(BOOL finished) {
                nil;
            }];
            addingSections = NO;
    
            //step 2 - update collectionView
    
            //adding cells if there are not enough
            for (int i = 0; i < IndexArray.count; i++) {
                for (int j = 0; j < (int)[[IndexArray objectAtIndex:i] count]; j++) {
                    NSNumber *searchIndex = [[IndexArray objectAtIndex:i] objectAtIndex:j];
                    bool found = NO;
    
                    for (int k = 0; k < IndexUnloadedArray.count; k++) {
                        if ([[IndexUnloadedArray objectAtIndex:k] containsObject:searchIndex]) {
                            found = YES;
                            k = (int)IndexUnloadedArray.count;
                        }
                    }
    
                    if (!found) {
                        [insertIndexPaths addObject:[NSIndexPath indexPathForRow:j inSection:i]];
                    }
                }
            }
            NSLog(@"insert cells:%@", insertIndexPaths);
    
            //deleting cells if there are too many
            for (int i = 0; i < IndexUnloadedArray.count; i++) {
                if (![deleteSections containsIndex:i]) {
                    for (int j = 0; j < (int)[[IndexUnloadedArray objectAtIndex:i] count]; j++) {
                        NSNumber *searchIndex = [[IndexUnloadedArray objectAtIndex:i] objectAtIndex:j];
                        bool found = NO;
    
                        for (int k = 0; k < IndexArray.count; k++) {
                            if ([[IndexArray objectAtIndex:k] containsObject:searchIndex]) {
                                found = YES;
                                k = (int)IndexArray.count;
                            }
                        }
    
                        if (!found) {
                            [deleteIndexPaths addObject:[NSIndexPath indexPathForRow:j inSection:i]];
                        }
                    }
                }
            }
            NSLog(@"deleting cells:%@", deleteIndexPaths);
    
            updatingCollectionView = YES;
            [_resultCollectionView performBatchUpdates:^{
                [_resultCollectionView insertItemsAtIndexPaths:insertIndexPaths];
                [_resultCollectionView deleteItemsAtIndexPaths:deleteIndexPaths];
    
                for (int i = 0; i < IndexUnloadedArray.count; i++) {
                    for (int j = 0; j < [[IndexUnloadedArray objectAtIndex:i] count]; j++) {
                        NSIndexPath *sourcePath = [NSIndexPath indexPathForRow:(j) inSection:i];
                        NSNumber *searchIndex = [[IndexUnloadedArray objectAtIndex:i] objectAtIndex:j];
                        NSIndexPath *destinationPath;
    
                        for (int k = 0; k < IndexArray.count; k++) {
                            if ([[IndexArray objectAtIndex:k] containsObject:searchIndex]) {
                                NSInteger *row = [[IndexArray objectAtIndex:k] indexOfObject:searchIndex];
                                destinationPath = [NSIndexPath indexPathForItem:row inSection:k];
    
                                if (sourcePath != destinationPath) {
                                    NSLog(@"moving cell from %ld.%ld to %ld.%ld (%@)", (long)sourcePath.section, (long)sourcePath.row, (long)destinationPath.section, (long)destinationPath.row);
                                    [_resultCollectionView moveItemAtIndexPath:sourcePath toIndexPath:destinationPath];
                                } else {
                                    NSLog(@"object %ld.%ld stays in position", (long)sourcePath.section, (long)sourcePath.row);
                                }
                            }
                        }
                    }
                }
    
            } completion:^(BOOL finished) {
                nil;
            }];
            updatingCollectionView = NO;
    
            //step 3 - deleting sections if there are too many
            for (int i = 0; i < IndexUnloadedArray.count; i++) {
                if (i >= IndexArray.count) {
                    [deleteSections addIndex:i];
                }
            }
            NSLog(@"delete sections:%@", deleteSections);
    
            _sectionAmount = (int)_distanceArray.count;
    
            removingSections = YES;
            [_resultCollectionView performBatchUpdates:^{
                [_resultCollectionView deleteSections:deleteSections];
            } completion:^(BOOL finished) {
                //update table header and footer
                [_resultCollectionView reloadData];
            }];
            removingSections = NO;
    
        }
    }
    
    
    - (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView
    {
        return _sectionAmount;
    }
    
    
    - (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section
    {
        if (addingSections) {
            if (section < _distanceUnloadedArray.count) {
                return [[_distanceUnloadedArray objectAtIndex:section] count];
            } else {
                return 0;
            }
        }
    
        if (updatingCollectionView) {
            if (section < _distanceArray.count) {
                return [[_distanceArray objectAtIndex:section] count];
            } else {
                return 0;
            }
        }
    
        if (removingSections) {
            return [[_distanceArray objectAtIndex:section] count];
        }
    
    
        return [[_distanceArray objectAtIndex:section] count];
    }