从UICollectionView中的UIAttachmentBehavior中删除振荡

时间:2015-07-23 21:17:50

标签: uicollectionview uicollectionviewlayout uikit-dynamics uidynamicanimator uiattachmentbehavior

我正在尝试重新创建您在UICollectionView的iOS消息应用中看到的弹簧行为。与消息类似,它将根据文本大小具有各种单元格大小。我创建了一个自定义UICollectionViewFlowLayout,它确实将行为添加到UICollectionView但是在用户停止滚动后消息气泡继续略微振荡。我在lengthdampingspring值中尝试了任意数量的组合,但振荡永远不会消失。

在阅读了其他堆栈问题后,我确实找到了这条评论

  

为了防止振荡,随着附着的视图越来越接近它们的附着点,在二次刻度上动态地增加阻尼因子是必要的。 <

但我不确定从哪里开始实现我现有的东西。任何帮助或指导将不胜感激。

以下是我在创建当前效果的UICollectionViewFlowLayout上的代码。

- (void) prepareLayout {
[super prepareLayout];

CGRect originalRect = (CGRect){.origin = self.collectionView.bounds.origin, .size = self.collectionView.frame.size};
CGRect visibleRect = CGRectInset(originalRect, -50, -50);

NSArray *itemsInVisibleRectArray = [super layoutAttributesForElementsInRect:visibleRect];
NSSet *itemsIndexPathsInVisibleRectSet = [NSSet setWithArray:[itemsInVisibleRectArray valueForKey:@"indexPath"]];


NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(UIAttachmentBehavior *behaviour, NSDictionary *bindings) {
    BOOL currentlyVisible = [itemsIndexPathsInVisibleRectSet member:[[[behaviour items] firstObject] indexPath]] != nil;
    return !currentlyVisible;
}];
NSArray *noLongerVisibleBehaviours = [self.animator.behaviors filteredArrayUsingPredicate:predicate];

[noLongerVisibleBehaviours enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) {
    [self.animator removeBehavior:obj];
    [self.visibleIndexPathsSet removeObject:[[[obj items] firstObject] indexPath]];
}];


NSPredicate *newPredicate = [NSPredicate predicateWithBlock:^BOOL(UICollectionViewLayoutAttributes *item, NSDictionary *bindings) {
    BOOL currentlyVisible = [self.visibleIndexPathsSet member:item.indexPath] != nil;
    return !currentlyVisible;
}];
NSArray *newlyVisibleItems = [itemsInVisibleRectArray filteredArrayUsingPredicate:newPredicate];
CGPoint touchLocation = [self.collectionView.panGestureRecognizer locationInView:self.collectionView];



[newlyVisibleItems enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *item, NSUInteger idx, BOOL *stop) {
    CGPoint center = item.center;
    UIAttachmentBehavior *springBehaviour = [[UIAttachmentBehavior alloc] initWithItem:item attachedToAnchor:center];

    springBehaviour.length = 0.1f;
    springBehaviour.damping = 3.0f;
    springBehaviour.frequency = 2.8f;

    if (!CGPointEqualToPoint(CGPointZero, touchLocation)) {
        CGFloat yDistanceFromTouch = fabs(touchLocation.y - springBehaviour.anchorPoint.y);
        CGFloat xDistanceFromTouch = fabs(touchLocation.x - springBehaviour.anchorPoint.x);
        CGFloat scrollResistance = (yDistanceFromTouch + xDistanceFromTouch) / 1500.0f;

        if (self.latestDelta < 0) {
            center.y += MAX(self.latestDelta, self.latestDelta*scrollResistance);
        }
        else {
            center.y += MIN(self.latestDelta, self.latestDelta*scrollResistance);
        }
        item.center = center;
    }

    [self.animator addBehavior:springBehaviour];
    [self.visibleIndexPathsSet addObject:item.indexPath];
}];
}

1 个答案:

答案 0 :(得分:1)

您可以通过两个步骤进行修复 1.在缩写时为行为添加操作,以确保在动画期间单元格的中心不会发生变化


springBehaviour.action = ^{
            CGPoint itemCenter = item.center;
            itemCenter.x = center.x;
            item.center = itemCenter;
        };
  1. 在collectionview停止滚动时删除/重新添加行为。为此,您需要实现scrollview委托方法,并在此方法中删除/重新添加行为。
  2. 
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    {
        ZZHCollectionFlowLayout *flowLayout = self.collectionView.collectionViewLayout;
        if ([flowLayout isKindOfClass:[ZZHCollectionFlowLayout class]])
        {
            [flowLayout removeAnimationBehavior];
        }
        else
        {
            // Your NSAssertionHandler
        }
    }
    
    - (void)removeAnimationBehavior
    {
        NSArray *behaviors = self.dynamicAnimator.behaviors;
        [self.dynamicAnimator removeAllBehaviors];
        for (UIDynamicBehavior *obj in behaviors)
        {
            [self.dynamicAnimator addBehavior:obj];
        }
    }
    
    
    顺便说一句,如果有改变阻尼的方法来修复,想听听它!