首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >无子类化UICollectionViewFlowLayout的targetContentOffsetForProposedContentOffset:withScrollingVelocity

无子类化UICollectionViewFlowLayout的targetContentOffsetForProposedContentOffset:withScrollingVelocity
EN

Stack Overflow用户
提问于 2012-11-21 19:12:55
回答 13查看 72.5K关注 0票数 103

我的应用程序中有一个非常简单的collectionView (只有一排正方形的缩略图)。

我想截取滚动,以便偏移量始终在左侧留下完整的图像。此时,它会滚动到任何位置,并会留下截取的图像。

无论如何,我知道我需要使用函数

代码语言:javascript
复制
- (CGPoint)targetContentOffsetForProposedContentOffset:withScrollingVelocity

这样做,但我只是使用标准的UICollectionViewFlowLayout。我不会对它进行子类化。

有没有办法在不对UICollectionViewFlowLayout进行子类化的情况下拦截它

谢谢

EN

回答 13

Stack Overflow用户

回答已采纳

发布于 2012-11-21 20:52:10

好吧,答案是否定的,没有子类化UICollectionViewFlowLayout是无法做到这一点的。

然而,对于将来阅读这篇文章的任何人来说,将其子类化是非常容易的。

首先,我设置了一个名为MyCollectionViewFlowLayout的子类,然后在接口构建器中,我将集合视图布局更改为自定义,并选择了我的流布局子类。

因为你是这样做的,你不能指定项目的大小,等等。在IB中,所以在MyCollectionViewFlowLayout.m中,我有这个...

代码语言:javascript
复制
- (void)awakeFromNib
{
    self.itemSize = CGSizeMake(75.0, 75.0);
    self.minimumInteritemSpacing = 10.0;
    self.minimumLineSpacing = 10.0;
    self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    self.sectionInset = UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0);
}

这为我设置了所有的大小和滚动方向。

然后..。

代码语言:javascript
复制
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
    CGFloat offsetAdjustment = MAXFLOAT;
    CGFloat horizontalOffset = proposedContentOffset.x + 5;

    CGRect targetRect = CGRectMake(proposedContentOffset.x, 0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);

    NSArray *array = [super layoutAttributesForElementsInRect:targetRect];

    for (UICollectionViewLayoutAttributes *layoutAttributes in array) {
        CGFloat itemOffset = layoutAttributes.frame.origin.x;
        if (ABS(itemOffset - horizontalOffset) < ABS(offsetAdjustment)) {
            offsetAdjustment = itemOffset - horizontalOffset;
        }
    }

    return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
}

这可确保滚动在左侧边缘的边距为5.0时结束。

这就是我需要做的一切。我根本不需要在代码中设置流布局。

票数 117
EN

Stack Overflow用户

发布于 2014-03-07 07:28:19

丹的解决方案有缺陷。它不能很好地处理用户的轻弹。当用户快速轻拍和滚动没有移动太多的情况下,动画故障。

我提出的替代实现具有与前面提出的相同的分页,但处理用户在页面之间的闪烁。

代码语言:javascript
复制
 #pragma mark - Pagination
 - (CGFloat)pageWidth {
     return self.itemSize.width + self.minimumLineSpacing;
 }

 - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
 {           
        CGFloat rawPageValue = self.collectionView.contentOffset.x / self.pageWidth;
        CGFloat currentPage = (velocity.x > 0.0) ? floor(rawPageValue) : ceil(rawPageValue);
        CGFloat nextPage = (velocity.x > 0.0) ? ceil(rawPageValue) : floor(rawPageValue);

        BOOL pannedLessThanAPage = fabs(1 + currentPage - rawPageValue) > 0.5;
        BOOL flicked = fabs(velocity.x) > [self flickVelocity];
        if (pannedLessThanAPage && flicked) {
            proposedContentOffset.x = nextPage * self.pageWidth;
        } else {
            proposedContentOffset.x = round(rawPageValue) * self.pageWidth;
        }

        return proposedContentOffset;
 }

 - (CGFloat)flickVelocity {
     return 0.3;
 }
票数 67
EN

Stack Overflow用户

发布于 2013-01-12 15:15:40

虽然this answer对我有很大的帮助,但当你在很小的距离上快速滑动时,会有明显的闪烁。在设备上重现它要容易得多。

我发现当collectionView.contentOffset.x - proposedContentOffset.xvelocity.x有不同的声音时,总是会发生这种情况。

我的解决方案是确保如果速度为正,proposedContentOffset大于contentOffset.x,如果速度为负,则小于。它是用C#编写的,但转换成Objective C应该相当简单:

代码语言:javascript
复制
public override PointF TargetContentOffset (PointF proposedContentOffset, PointF scrollingVelocity)
{
    /* Determine closest edge */

    float offSetAdjustment = float.MaxValue;
    float horizontalCenter = (float) (proposedContentOffset.X + (this.CollectionView.Bounds.Size.Width / 2.0));

    RectangleF targetRect = new RectangleF (proposedContentOffset.X, 0.0f, this.CollectionView.Bounds.Size.Width, this.CollectionView.Bounds.Size.Height);
    var array = base.LayoutAttributesForElementsInRect (targetRect);

    foreach (var layoutAttributes in array) {
        float itemHorizontalCenter = layoutAttributes.Center.X;
        if (Math.Abs (itemHorizontalCenter - horizontalCenter) < Math.Abs (offSetAdjustment)) {
            offSetAdjustment = itemHorizontalCenter - horizontalCenter;
        }
    }

    float nextOffset = proposedContentOffset.X + offSetAdjustment;

    /*
     * ... unless we end up having positive speed
     * while moving left or negative speed while moving right.
     * This will cause flicker so we resort to finding next page
     * in the direction of velocity and use it.
     */

    do {
        proposedContentOffset.X = nextOffset;

        float deltaX = proposedContentOffset.X - CollectionView.ContentOffset.X;
        float velX = scrollingVelocity.X;

        // If their signs are same, or if either is zero, go ahead
        if (Math.Sign (deltaX) * Math.Sign (velX) != -1)
            break;

        // Otherwise, look for the closest page in the right direction
        nextOffset += Math.Sign (scrollingVelocity.X) * SnapStep;
    } while (IsValidOffset (nextOffset));

    return proposedContentOffset;
}

bool IsValidOffset (float offset)
{
    return (offset >= MinContentOffset && offset <= MaxContentOffset);
}

这段代码使用了MinContentOffsetMaxContentOffsetSnapStep,这对你来说应该是微不足道的。在我的案例中,它们被证明是

代码语言:javascript
复制
float MinContentOffset {
    get { return -CollectionView.ContentInset.Left; }
}

float MaxContentOffset {
    get { return MinContentOffset + CollectionView.ContentSize.Width - ItemSize.Width; }
}

float SnapStep {
    get { return ItemSize.Width + MinimumLineSpacing; }
}
票数 22
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13492037

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档