我遇到自定义UICollectionViewFlowLayout
的问题就像这个视频显示Issue Video一样,当我的单元格反弹回中心时(0:12-0:16),我的变换插值失败,并且它跳转到1帧的中心位置。
我隔离了这个问题,它在distanceToCenterX == 0.0f
(下面的代码)
对于中央单元格,此方法的多次调用是printf
distanceToCenterX
:
-92.000000
-91.500000
-91.000000
-90.500000
-90.000000
-89.500000
-89.000000
-88.500000
0.000000
你可以看到它突然从-88.5000
跳到0.00
,我能做些什么来平滑过渡并避免1帧跳跃?
代码(免责声明,取自Apple示例和Github Project)
static const CGfloat ACTIVE_DISTANCE = 100.0f
- (void)setCellAttributes:(UICollectionViewLayoutAttributes *)attributes forVisibleRect:(CGRect)visibleRect withCentralCellIndexPath:(NSIndexPath *)path
{
// First set the general position for the attributes
[self setGeneralPositionForAttributes:(HILayoutAttributes *)attributes withCentralAttributesIndexPath:path];
// Then adjust transforms
CGFloat distanceToCenterX = CGRectGetMidX(visibleRect) - attributes.center.x;
//
// The issue manifests when distanceToCenterX is 0
//
CGFloat normalizedDistance = distanceToCenterX / ACTIVE_DISTANCE;
BOOL isLeft = (((HILayoutAttributes *)attributes).generalPosition == kGeneralCellPosition_left) ? YES : NO;
CATransform3D transform = CATransform3DIdentity;
transform.m34 = -1 / (4.6777 * self.itemSize.width);
if (ABS(distanceToCenterX) < ACTIVE_DISTANCE) {
if (ABS(distanceToCenterX) < TRANSLATE_DISTANCE) {
transform = CATransform3DTranslate(CATransform3DIdentity,
((FLOW_OFFSET * ABS(distanceToCenterX)) / TRANSLATE_DISTANCE),
0,
(1 - ABS(normalizedDistance)) * 40000 + (isLeft ? 200 : 0));
}
transform.m34 = -1/(4.6777 * self.itemSize.width);
transform = CATransform3DRotate(transform, 1 * ABS(normalizedDistance) * 45 * M_PI / 180, 0, 1, 0);
} else {
transform = CATransform3DTranslate(transform, FLOW_OFFSET , 0, 0);
transform = CATransform3DRotate(transform, 1 * 45 * M_PI / 180, 0, 1, 0);
attributes.zIndex = 0;
}
attributes.transform3D = transform;
}
我该怎么做才能避免这种情况发生?
答案 0 :(得分:1)
我讨论了Erica Sadun在“iOS 6 Developer's Cookbook”(第11章,食谱5)中发生的同样问题。
在书中还有一个自定义UICollectionViewFlowLayout的例子,它表现出我遇到的同样问题。
我在IRC上与Erica讨论过这个问题,我们同意UICollectionViewLayout中似乎有一个错误,她提到她在前一段时间里看到了类似的东西,所以它已经可以报道了。
她在她的书中为她的开源代码做了一个或多或少丑陋的解决方法,实际上你可以查看她的解决方案here。它并不优雅,但却是一种完全有效的解决方法。
当targetContentOffsetForProposedContentOffset:withScrollingVelocity:
等于0或proposedContentOffset.x
(collectionViewContentSize.width - bounds.Size.width
)
boundsSize = self.collectionView.bounds.size
上发出通知
CGPoint desiredPoint = CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
if ((proposedContentOffset.x == 0) || (proposedContentOffset.x >= (self.collectionViewContentSize.width - boundsSize.width)))
{
NSNotification *note = [NSNotification notificationWithName:@"PleaseRecenter" object:[NSValue valueWithCGPoint:desiredPoint]];
[[NSNotificationCenter defaultCenter] postNotification:note];
return proposedContentOffset;
}
当scrollView结束减速到desiredPoint
时,控制器会监听该通知并基本上重新集中CollectionView。
- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
if (CGPointEqualToPoint(desiredPoint, CGRectNull.origin))
return;
CGRect rect = scrollView.bounds;
rect.origin = desiredPoint;
[self.collectionView scrollRectToVisible:rect animated:YES];
desiredPoint = CGRectNull.origin;
}
希望这有助于其他人。