我的应用程序中有一个非常简单的collectionView (只有一排正方形的缩略图)。
我想截取滚动,以便偏移量始终在左侧留下完整的图像。此时,它会滚动到任何位置,并会留下截取的图像。
无论如何,我知道我需要使用函数
- (CGPoint)targetContentOffsetForProposedContentOffset:withScrollingVelocity
这样做,但我只是使用标准的UICollectionViewFlowLayout
。我不会对它进行子类化。
有没有办法在不对UICollectionViewFlowLayout
进行子类化的情况下拦截它
谢谢
发布于 2012-11-21 20:52:10
好吧,答案是否定的,没有子类化UICollectionViewFlowLayout是无法做到这一点的。
然而,对于将来阅读这篇文章的任何人来说,将其子类化是非常容易的。
首先,我设置了一个名为MyCollectionViewFlowLayout
的子类,然后在接口构建器中,我将集合视图布局更改为自定义,并选择了我的流布局子类。
因为你是这样做的,你不能指定项目的大小,等等。在IB中,所以在MyCollectionViewFlowLayout.m中,我有这个...
- (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);
}
这为我设置了所有的大小和滚动方向。
然后..。
- (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时结束。
这就是我需要做的一切。我根本不需要在代码中设置流布局。
发布于 2014-03-07 07:28:19
丹的解决方案有缺陷。它不能很好地处理用户的轻弹。当用户快速轻拍和滚动没有移动太多的情况下,动画故障。
我提出的替代实现具有与前面提出的相同的分页,但处理用户在页面之间的闪烁。
#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;
}
发布于 2013-01-12 15:15:40
虽然this answer对我有很大的帮助,但当你在很小的距离上快速滑动时,会有明显的闪烁。在设备上重现它要容易得多。
我发现当collectionView.contentOffset.x - proposedContentOffset.x
和velocity.x
有不同的声音时,总是会发生这种情况。
我的解决方案是确保如果速度为正,proposedContentOffset
大于contentOffset.x
,如果速度为负,则小于。它是用C#编写的,但转换成Objective C应该相当简单:
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);
}
这段代码使用了MinContentOffset
、MaxContentOffset
和SnapStep
,这对你来说应该是微不足道的。在我的案例中,它们被证明是
float MinContentOffset {
get { return -CollectionView.ContentInset.Left; }
}
float MaxContentOffset {
get { return MinContentOffset + CollectionView.ContentSize.Width - ItemSize.Width; }
}
float SnapStep {
get { return ItemSize.Width + MinimumLineSpacing; }
}
https://stackoverflow.com/questions/13492037
复制相似问题