ios – 如何使用UICollectionViewTransitionLayout插入自定义UICollectionViewLayoutAttributes属性

前端之家收集整理的这篇文章主要介绍了ios – 如何使用UICollectionViewTransitionLayout插入自定义UICollectionViewLayoutAttributes属性前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有两个使用自定义UICollectionViewLayoutAttributes子类的自定义UICollectionViewLayout对象.这些自定义属性添加了一个属性tintAlpha,它控制连接到每个集合视图单元格的色彩叠加视图的不透明度.

我现在想使用UICollectionViewTransitionLayout子类在这两个布局之间进行转换.如何配置转换布局子类以在自定义布局属性上插入自定义tintAlpha属性

我可以这样做:

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
     CustomLayoutAttributes *attr = [super layoutAttributesForItemAtIndexPath:indexPath];

     CustomLayoutAttributes *fromAttr = (CustomLayoutAttributes *)[self.currentLayout layoutAttributesForItemAtIndexPath:indexPath];
     CustomLayoutAttributes *toAttr = (CustomLayoutAttributes *)[self.nextLayout layoutAttributesForItemAtIndexPath:indexPath];

     CGFloat t = self.transitionProgress;
     attr.tintAlpha = (1.0f - t) * fromAttr.tintAlpha + t * toAttr.tintAlpha;

     return attr;
}

但是,这将忽略对initialLayoutAttributesForAppearingItemAtIndexPath中的属性应用的任何更改:& finalLayoutAttributesForDisappearingItemAtIndexPath:在当前或下一个布局中,因此实际上并不正确.据我所知,UICollectionViewTransitionLayout的默认实现确定了适当的from / to属性,并将它们缓存在prepareLayout或layoutAttributesForItemAtIndexPath:中.在UICollectionViewTransitionLayout上使用一些公共API可以让我们从/到属性对象访问这个方法是非常有用的,就好像我尝试实现我自己的逻辑关于是使用初始/最终属性还是绑定的标准属性与默认实现有一些差异.

在布局转换期间是否有更好的方法来插入这些自定义属性

更新:

我刚刚遇到了一个额外的问题,这种情况.在上面的代码中,当从Attt& toAttr直接从当前/下一个布局,collectionView对于当前布局为零(至少在第一个运行循环之外).如果布局完全取决于集合视图的边界 – 例如,可以考虑一个简单的封面流布局,那么,从安装程序将不正确.

我真的在为一个interpolatedLayoutAttributesFromLayoutAttributes:toLayoutAttributes:progress:在UICollectionViewTransitionLayout上可以被子类覆盖.

解决方法

在提出更好的解决方案之前,我已经实施了以下解决方法

默认实现调用到当前&下一个布局从[super prepareLayout]选择&缓存需要从/转换到的布局属性.因为我们没有访问这个缓存(我的主要抱怨!),我们不能直接在转换期间使用它.相反,当默认实现通过插值的布局属性调用时,我构造自己的这些属性缓存.这只能在layoutAttributesForElementsInRect中发生:(靠近currentLayout.collectionView == nil的问题),但幸运的是,似乎这个方法首先在与转换开始相同的运行循环中调用,并且在将CollectionView属性设置为nil之前.这样就可以建立我们的从/到布局属性,并在转换期间缓存它们.

@interface CustomTransitionLayout ()
@property(nonatomic,strong) NSMutableDictionary *transitionInformation;
@end

@implementation

- (void)prepareLayout
{
    [super prepareLayout];

    if (!self.transitionInformation) {
        self.transitionInformation = [NSMutableDictionary dictionary];
    }
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    // Let the super implementation tell us which attributes are required.
    NSArray *defaultLayoutAttributes = [super layoutAttributesForElementsInRect:rect];
    NSMutableArray *layoutAttributes = [NSMutableArray arrayWithCapacity:[defaultLayoutAttributes count]];
    for (UICollectionViewLayoutAttributes *defaultAttr in defaultLayoutAttributes) {
        UICollectionViewLayoutAttributes *attr = defaultAttr;
        switch (defaultAttr.representedElementCategory) {
            case UICollectionElementCategoryCell:
                attr = [self layoutAttributesForItemAtIndexPath:defaultAttr.indexPath];
                break;
            case UICollectionElementCategorySupplementaryView:
                attr = [self layoutAttributesForSupplementaryViewOfKind:defaultAttr.representedElementKind atIndexPath:defaultAttr.indexPath];
                break;
            case UICollectionElementCategoryDecorationView:
                attr = [self layoutAttributesForDecorationViewOfKind:defaultAttr.representedElementKind atIndexPath:defaultAttr.indexPath];
                break;
        }
        [layoutAttributes addObject:attr];
    }
    return layoutAttributes;
}

layoutAttributesForElementsInRect的替代:简单地调用layoutAttributesFor … atIndexPath:对于超级想返回属性的每个元素索引路径,缓存从/到属性属性.例如,layoutAttributesForItemAtIndexPath:方法看起来像这样:

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSIndexPath *indexPathKey = [indexPath collectionViewKey];

    NSMutableDictionary *info = self.transitionInformation[indexPathKey];
    if (!info) {
        info = [NSMutableDictionary dictionary];
        self.transitionInformation[indexPathKey] = info;
    }

    // Logic to choose layout attributes to interpolate from.
    // (This is not exactly how the default implementation works,but a rough approximation)
    MyLayoutAttributes *fromAttributes = info[TransitionInfoFromAttributesKey];
    if (!fromAttributes) {
        MyLayoutAttributes *standardToAttributes = (MyLayoutAttributes *)[self.nextLayout layoutAttributesForItemAtIndexPath:indexPathKey];
        MyLayoutAttributes *initialAttributes = (MyLayoutAttributes *)[self.nextLayout initialLayoutAttributesForAppearingItemAtIndexPath:indexPathkey];
        if (initialAttributes && ![initialAttributes isEqual:standardToAttributes]) {
            fromAttributes = [initialAttributes copy];
        } else {
            fromAttributes = [(MyLayoutAttributes *)[self.currentLayout layoutAttributesForItemAtIndexPath:indexPathKey] copy];
        }
        info[TransitionInfoFromAttributesKey] = fromAttributes;
    }

    MyLayoutAttributes *toAttributes = info[TransitionInfoToAttributesKey];
    if (!toAttributes) {
        // ... similar logic as for fromAttributes ...
        info[TransitionInfoToAttributesKey] = toAttributes;
    }

    MyLayoutAttributes *attributes = [self interpolatedLayoutAttributesFromLayoutAttributes:fromAttributes
                                                                         toLayoutAttributes:toAttributes
                                                                                   progress:self.transitionProgress];
    return attributes;
}

这只是留下一个实际插值的新方法,这就是你不仅要插入自定义布局属性属性,而且要重新实现默认插值(center / size / alpha / transform / transform3D):

- (MyLayoutAttributes *)interpolatedLayoutAttributesFromLayoutAttributes:(MyLayoutAttributes *)fromAttributes
                                                      toLayoutAttributes:(MyLayoutAttributes *)toAttributes
                                                                progress:(CGFloat)progress
{
    MyLayoutAttributes *attributes = [fromAttributes copy];

    CGFloat t = progress;
    CGFloat f = 1.0f - t;

    // Interpolate all the default layout attributes properties.
    attributes.center = CGPointMake(f * fromAttributes.x + t * toAttributes.center.x,f * fromAttributes.y + t * toAttributes.center.y);
    // ...

    // Interpolate any custom layout attributes properties.
    attributes.customProperty = f * fromAttributes.customProperty + t * toAttributes.customProperty;
    // ...

    return attributes;
}

综上所述…

那么令人沮丧的是,这是一个大量的代码(这里为了简洁起见,这里并没有显示出来),而且大多数代码只是复制或尝试复制默认的实现方式.如果UICollectionViewTransitionLayout暴露了一个单独的方法来覆盖,那么这样做会导致更差的性能,并浪费开发时间,如果真的要简单得多,比如:

- (UICollectionViewLayoutAttributes *)interpolatedLayoutAttributesFromLayoutAttributes:(UICollectionViewLayoutAttributes *)fromAttributes
                                                                    toLayoutAttributes:(UICollectionViewLayoutAttributes *)toAttributes
                                                                              progress:(CGFloat)progress
{
    MyLayoutAttributes *attributes = (MyLayoutAttributes *)[super interpolatedLayoutAttributesFromLayoutAttributes:fromAttributes toLayoutAttributes:toAttributes progress:progress];
    attributes.customProperty = (1.0f - progress) * fromAttributes.customProperty + progress * toAttributes.customProperty;
    return attributes;
}

这个解决方法的好处是,您不必重新实现代码,从而决定在转换的开始/结束时可以看到哪些布局属性 – 默认实现对我们来说是这样.每当布局无效时,我们也不必得到所有的属性,然后检查与可见直线相交的项目.

猜你在找的iOS相关文章