UICollectionView 将项目移动到新部分

Posted

技术标签:

【中文标题】UICollectionView 将项目移动到新部分【英文标题】:UICollectionView move items to new section 【发布时间】:2015-11-12 22:58:03 【问题描述】:

我在 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,一切正常,这意味着我的数据源和委托在理论上可以正常工作。除了它还没有动画...

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

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

有人有解决这个问题的方法吗?

【问题讨论】:

你检查过这个问题吗?我觉得@sponessuck 的答案可以解决您的问题。 ***.com/questions/26299502/… 【参考方案1】:

我按照 john1034 的链接找到了一个非常棘手的方法。您必须将工作分成三个步骤:

    如有必要,添加新部分。新部分将首先为空。 在新的和现有的部分中添加、删除和移动单元格。 必要时删除部分。

当然有很多行可以进一步改进。尤其是搜索功能相当低效...

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];

【讨论】:

以上是关于UICollectionView 将项目移动到新部分的主要内容,如果未能解决你的问题,请参考以下文章

将现有的 GitLab 项目移动到新的子组中

将 VB.NET 项目移动到新计算机后日期无法正常工作[关闭]

UICollectionView。如何在幕后插入新项目?

如何将 SQL Server LocalDB 数据库移动到新计算机

如果项目未移动,是不是有方法检查 UICollectionView 项目拖动取消?

滑动时如何使用左右移动的项目制作 UICollectionview?