移动时,将自定义单元格的大小保留在UICollectionView中

时间:2017-07-06 19:41:20

标签: ios swift uicollectionview uicollectionviewlayout

我有一个水平集合视图,每个单元格都有自己的宽度。我使用默认的UICollectionViewFlowLayout。重新排列时,细胞继承了在此运动过程中覆盖的细胞宽度,这是我不想要的。任何想法,如何避免这种行为?

2 个答案:

答案 0 :(得分:3)

因此,如果您使用不同大小的单元格的UICollectionView,并且您希望在使用标准UICollectionViewFlowLayout移动时保持其大小,请使用:

extension UICollectionViewFlowLayout {

@available(iOS 9.0, *)
open override func invalidationContext(forInteractivelyMovingItems targetIndexPaths: [IndexPath], withTargetPosition targetPosition: CGPoint, previousIndexPaths: [IndexPath], previousPosition: CGPoint) -> UICollectionViewLayoutInvalidationContext {

    let context = super.invalidationContext(forInteractivelyMovingItems: targetIndexPaths, withTargetPosition: targetPosition, previousIndexPaths: previousIndexPaths, previousPosition: previousPosition)

    //Check that the movement has actually happeneds
    if previousIndexPaths.first!.item != targetIndexPaths.first!.item {
        collectionView?.dataSource?.collectionView?(collectionView!, moveItemAt: previousIndexPaths.first!, to: targetIndexPaths.last!)
    }

    return context
}

open override func invalidationContextForEndingInteractiveMovementOfItems(toFinalIndexPaths indexPaths: [IndexPath], previousIndexPaths: [IndexPath], movementCancelled: Bool) -> UICollectionViewLayoutInvalidationContext {
    return super.invalidationContextForEndingInteractiveMovementOfItems(toFinalIndexPaths: indexPaths, previousIndexPaths: previousIndexPaths, movementCancelled: movementCancelled)
}

@available(iOS 9.0, *) //If you'd like to apply some formatting as the dimming of the movable cell
open override func layoutAttributesForInteractivelyMovingItem(at indexPath: IndexPath, withTargetPosition position: CGPoint) -> UICollectionViewLayoutAttributes {
    let attributes = super.layoutAttributesForInteractivelyMovingItem(at: indexPath, withTargetPosition: position)
    attributes.alpha = 0.8
    return attributes
}

}

在你的控制器的moveItemAt方法中,不要忘记检查压力状态是否改变如下:

override func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath,
                             to destinationIndexPath: IndexPath) {

    if #available(iOS 9.0, *) {

        if self.longPressureGestureRecognizer.state == .ended {
            return
        }

        //Update your data
        data.moveItem(at: sourceIndexPath.row, to: destinationIndexPath.row)

    }
}

答案 1 :(得分:0)

我通过使用collectionView:targetIndexPathForMoveFromItemAtIndexPath:toProposedIndexPath:来解决这个问题,如果我的行/部分数据的副本不存在,我会创建它,然后更新副本,就好像建议的移动是实际移动一样。我的collectionView:layout:sizeForItemAtIndexPath:会使用该副本(如果存在)。我会在collectionView:moveItemAtIndexPath:toIndexPath:中将副本设置为nil,以便视图将返回使用“原始”行/节数据进行大小调整。因此,在移动之前,期间和之后,所有尺寸看起来都是正确的。

根据要求,这是我的代码:

- (NSIndexPath *)collectionView:(UICollectionView *)collectionView targetIndexPathForMoveFromItemAtIndexPath:(NSIndexPath *)originalIndexPath toProposedIndexPath:(NSIndexPath *)proposedIndexPath
{
    if (nil == _movingSections)
        _movingSections = [_sections copy];
    NSMutableArray *section = [_movingSections.sections objectAtIndex:originalIndexPath.section];
    id obj = [section objectAtIndex:originalIndexPath.row];

    [section removeObjectAtIndex:originalIndexPath.row];

    section = [_movingSections.sections objectAtIndex:proposedIndexPath.section];
    if (proposedIndexPath.row < [section count])
        [section insertObject:obj atIndex:proposedIndexPath.row];
    else
        [section addObject:obj];

    return proposedIndexPath;
}

当_movingSections为非零时,我还更新了collectionView:layout:sizeForItemAtIndexPath:以使用_movingSections而不是_sections。在collectionView:moveItemAtIndexPath:toIndexPath:中,我将_movingSections设置为nil。就是这样!

我应该补充一点,我最终放弃了这个方法,因为我的部分可以比设备宽度更宽,这可以正常工作,直到你移动东西,并且在那一点上UICollectionViewFlowLayout想要均匀地分隔单元格而不管你的宽度提供了。相反,我转而使用UIScrollView,现在我的代码更简单,而且我不再与UICollectionViewFlowLayout抗争。我考虑过滚动自己的UICollectionViewLayout,但这并没有使我的代码更简单。