从 UICollectionView 中的 UIAttachmentBehavior 中删除振荡

Posted

技术标签:

【中文标题】从 UICollectionView 中的 UIAttachmentBehavior 中删除振荡【英文标题】:Remove Oscillation from UIAttachmentBehavior in UICollectionView 【发布时间】:2015-07-23 21:17:49 【问题描述】:

我正在尝试重新创建您在我的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】:

您可以通过 2 个步骤来修复它。 1. 为behavior添加动作,以确保在动画期间单元格的中心不会改变


springBehaviour.action = ^
            CGPoint itemCenter = item.center;
            itemCenter.x = center.x;
            item.center = itemCenter;
        ;
    删除/重新添加collectionview 停止滚动时的行为。为此,您需要实现一个滚动视图委托方法,并在此方法中删除/重新添加行为。
- (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];

顺便说一句,如果有办法改变阻尼来修复,想听听!

【讨论】:

以上是关于从 UICollectionView 中的 UIAttachmentBehavior 中删除振荡的主要内容,如果未能解决你的问题,请参考以下文章

从 UICollectionView 宽度设置 Ancor 约束中的宽度

无法从 json 响应中设置部分中的 UICollectionView 项目数

如何从嵌入在 UITableViewCell (Swift) 中的 UICollectionView 的单元格中分离出来?

CCS+C6678LE开发记录12:UIA组件的安装

从 xib 加载单元格时删除 UICollectionView 中的边框

将数据从自定义表格单元中的 uicollectionview 传递到 viewcontroller