Ios 如何使用UICollectionViewTransitionLayout插入自定义UICollectionViewLayoutAttribute属性
我有两个自定义的Ios 如何使用UICollectionViewTransitionLayout插入自定义UICollectionViewLayoutAttribute属性,ios,transitions,uicollectionviewlayout,Ios,Transitions,Uicollectionviewlayout,我有两个自定义的UICollectionViewLayout对象,它们使用自定义的uiCollectionViewLayoutAttribute子类。这些自定义属性添加单个属性tintAlpha,用于控制附着到每个集合视图单元的着色覆盖视图的不透明度 现在,我想使用UICollectionViewTransitionLayout子类在这两个布局之间进行转换。如何配置转换布局子类以在自定义布局属性上插入自定义tintAlpha属性 我可以这样做: - (UICollectionViewLayout
UICollectionViewLayout
对象,它们使用自定义的uiCollectionViewLayoutAttribute
子类。这些自定义属性添加单个属性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:
和finallayoutAttributesforIsAppearinGiteMatIndexPath:
中的属性所做的任何更改,因此实际上并不正确。据我所知,UICollectionViewTransitionLayout
的默认实现确定了适当的from/to属性,并将它们缓存在prepareLayout
或layouttributesforItemAtIndexPath:
中。如果在UICollectionViewTransitionLayout
上有一些公共API,允许我们访问这些从/到属性对象,这将非常有用,就好像我尝试实现自己的逻辑,即是否使用初始/最终属性与标准属性相比,与默认实现必然存在一些差异
在布局转换期间,是否有更好的方法插入这些自定义属性
更新: 我刚刚遇到了这个场景的另一个问题。在上面的代码中,当直接从当前/下一个版面获取从ATTR到ATTR的
时,当前版面的集合视图
为nil
(至少超出转换的第一次运行循环)。如果布局完全取决于集合视图的边界-例如考虑一个简单的覆盖流布局——那么<代码> FROMATTR 将是不正确的。
我真的很渴望在UICollectionViewTransitionLayout
上有一个可以被子类覆盖的InterpolatedLayoutAttribute fromLayoutAttribute:toLayoutAttributes:progress:
。在提出更好的解决方案之前,我已经实现了以下解决方法。。。
默认实现从[super prepareLayout]
调用当前和下一个布局,以选择和缓存需要从/转换到的布局属性。因为我们不能访问这个缓存(我的主要抱怨!),所以在转换过程中我们不能直接使用它们。相反,当默认实现调用插值布局属性时,我构建这些属性的自己的缓存。这只能发生在layouttributesforementsinrect:
(接近于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;
}
layouttributesforementsinrect:
的覆盖只需为super
要返回属性的每个元素索引路径调用layouttributesfor…atIndexPath:
,该路径将缓存from/to属性。例如,layouttributesforItemAtIndexPath:
方法如下所示:
这就留下了一个新的方法来进行实际的插值,在这个方法中,不仅要插值自定义布局属性属性,还要重新实现默认插值(center
/size
/alpha
/transform
/transform3D
):
总之。。。
因此,令人沮丧的是,这是一个庞大的代码量(为了简洁起见,这里没有显示太多),而且大多数代码只是复制或试图复制默认实现正在做的事情。这会导致性能下降,并浪费开发时间,因为如果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;
}
这种变通方法的好处是,您不必重新实现决定在转换开始/结束时哪些布局属性可见的代码——默认实现为我们做到了这一点。我们也不必在每次布局失效时获取所有内容的属性,然后检查与可见矩形相交的项。就是我用于此的。希望蒂莫西·穆斯会来,并提出一个很好的解释,要求他的赏金。否则,我会找到一个答案Thank@jrturton——我以前在遇到UICollectionView
(例如)的其他问题时,确实看过这个项目,但我决定编写自己的子类。如果我错了,请纠正我,但Timothy的代码也存在上述相同的问题-即,没有考虑初始/最终布局属性,并且他的prepareLayout
本质上是对插值UICollectionViewTransitionLayout
的重写。在每次失效时,它也会非常低效地为每一项准备属性(不适合我的情况)。我现在已经做了类似的解决方法(根据[super-layouttributesforementsinrect:
返回的属性缓存from/to属性),这允许我插入自定义属性。但我已经尝试复制决定是否使用初始/最终的逻辑
- (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;
}
- (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;
}