0

我遇到了自定义 UICollectionViewFlowLayout 的问题

就像这个视频显示问题视频一样,当我的单元格反弹回中心 (0:12 - 0:16) 时,我的变换插值失败,它跳到 1 帧的中心位置。

我隔离了这个问题,它在什么时候表现出来distanceToCenterX == 0.0f(下面的代码)

这是printfdistanceToCenterX中央单元格的此方法的多次调用:

-92.000000           
-91.500000           
-91.000000           
-90.500000           
-90.000000           
-89.500000           
-89.000000         
-88.500000
0.000000 

您可以看到它是如何从-88.50000.00非常突然地跳跃的,我可以做些什么来平滑过渡并避免 1 帧跳跃?

代码(免责声明,取自 Apple 示例和Github 项目

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

我能做些什么来避免这种情况发生?

4

1 回答 1

1

我在 Erica Sadun 的“iOS 6 Developer's Cookbook”(第 11 章,配方 5)中讨论了同样的问题。

在书中还有一个自定义 UICollectionViewFlowLayout 的示例,它展示了我遇到的相同问题。

我在 IRC 上和 Erica 谈过,我们一致认为 UICollectionViewLayout 中似乎有一个错误,她提到她前段时间在雷达上看到了类似的东西,所以它可能已经被报告了。

她在她的书中为她的开源代码做了一个或多或少丑陋的解决方法,实际上你可以在这里查看她的解决方案。它并不优雅,但它是一个完全有效的解决方法。

她基本上会在等于 0 或( )targetContentOffsetForProposedContentOffset:withScrollingVelocity:时发出通知proposedContentOffset.xcollectionViewContentSize.width - bounds.Size.widthboundsSize = 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.

- (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;
}

希望这对其他人有帮助。

于 2013-04-22T14:39:40.073 回答