3

我正在尝试在水平 UICollectionView 中模拟消息应用程序弹簧动画

我在 UICollectionViewFlowLayout 子类中使用了 UIAttachmentBehavior。但问题是当我水平滚动时,单元格也会以某种方式垂直和水平移动!

在此处输入图像描述

在此处输入图像描述

我遵循了本教程:
使用 uikitdynamics 实现有弹性的 uicollectionviewlayout

并在我的 collectionView 中使用。我还关注了 WWDC 2013 session 217-Exploring Scroll Views on iOS 7。但问题仍然存在!
有谁知道我应该如何解决这个问题?

-(id)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if (self){
    _dynamicAnimator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self];
}
return self;
}

- (void)prepareLayout{

    [super prepareLayout];

    CGSize contentSize = [self collectionViewContentSize];
    NSArray *items = [super layoutAttributesForElementsInRect:CGRectMake(0, 0, contentSize.width, 500)];

    if (items.count != _dynamicAnimator.behaviors.count) {
        [_dynamicAnimator removeAllBehaviors];

        for (UICollectionViewLayoutAttributes *item in items) {
            UIAttachmentBehavior *springBehavior = [[UIAttachmentBehavior alloc] initWithItem:item attachedToAnchor:item.center];
            springBehavior.length = 0.f;
            springBehavior.damping = 0.5f;
            springBehavior.frequency = 0.8f;

            [_dynamicAnimator addBehavior:springBehavior];
        }
    }
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
    return [_dynamicAnimator itemsInRect:rect];
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
    return [_dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath];
}

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
    CGFloat scrollDelta = newBounds.origin.x - self.collectionView.bounds.origin.x;
    CGPoint touchLocation = [self.collectionView.panGestureRecognizer locationInView:self.collectionView];

for (UIAttachmentBehavior *springBehavior in _dynamicAnimator.behaviors) {
    CGPoint anchorPoint = springBehavior.anchorPoint;
    CGFloat touchDistance = fabsf(touchLocation.x - anchorPoint.x);
    CGFloat resistanceFactor = 0.002;

    UICollectionViewLayoutAttributes *attributes = springBehavior.items.firstObject;

    CGPoint center = attributes.center;

    float resistedScroll = scrollDelta * touchDistance * resistanceFactor;
    float simpleScroll = scrollDelta;

    float actualScroll = MIN(abs(simpleScroll), abs(resistedScroll));
    if(simpleScroll < 0){
        actualScroll *= -1;
    }

    center.x += actualScroll;
    attributes.center = center;

    [_dynamicAnimator updateItemUsingCurrentState:attributes];
}

    return NO;
}
4

3 回答 3

3

我在我的应用程序中遇到了同样的问题。问题是这一行: UIAttachmentBehavior *springBehavior = [[UIAttachmentBehavior alloc] initWithItem:item attachedToAnchor:item.center];

问题是该项目的中心正在返回一个带小数的浮点数。iOS 然后将它们四舍五入为小数为 0 的浮点数,导致锚点无法很好地居中,因此项目反弹。

解决方案是在锚定它之前确保您的项目的框架在高度和宽度上可以被 2 整除。然后验证 item.center 返回的 X 和 Y 值是没有小数的浮点数,并且动画可以正常工作。

注意:即使在 iOS7 中运行完美,我在 iOS8 中也看到与此类似的问题,并且此解决方案不起作用。

于 2014-07-03T23:08:09.190 回答
1

好吧,我遇到了这个问题-iOS8。

多亏了这篇文章,现在它已经消失了。

我正在将补充视图添加到 UICollectionView 已经让 UIDynamics 运行良好。然后我添加了一些基于常规单元格的补充视图。计算将返回高度的浮点数(不是 0 位小数)。而且我想就像 Pauls 所说的那样,iOS 必须进行一些舍入,这会创建一个我不想要的 y-delta。这就是引发振荡运动的原因。
通过舍入我的补充视图高度,问题就消失了。我得到了 7.5 的一致中心,所以我的身高不能被 2 整除,但它仍然有效。

现在我的supplementaryViews是如何计算的

UICollectionViewLayoutAttributes *attributes = [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath];
// put supp view at beginning of cell
// round off height or wierd oscillations will begin as iOS must round also
CGRect suppViewFrame = CGRectMake(attributes.frame.origin.x - 44.0 / 2,
                                  attributes.frame.origin.y - 44.0,
                                  44.0,
                                  roundf(44.0 + attributes.frame.size.height / 2));

我添加的只是 CGRect 计算的高度部分的roundf。
瞧 - 它正在工作。
希望这可以帮助某人-快乐的编码

于 2015-04-29T01:08:20.747 回答
0

我在 iOS 8 中看到了完全相同的问题 - 似乎 UICollisionBehavior 允许创建边界,但 UIAttachmentBehavior 不存在相同的问题(尽管类文档中提到了 UIAttachmentBehavior)。我认为短期解决方案可能只是转移到 UIDynamicItemBehavior,这似乎更灵活。然而,有兴趣知道从 iOS 7 到 iOS 8 的变化。

于 2014-07-07T17:33:50.850 回答