在水平分页滚动视图中UICollectionViewalignment逻辑丢失

我有一个UICollectionView ,它工作正常,直到我开始滚动。 这里有一些照片第一: 在这里输入图像说明

正如你所看到的那样很好。 当我开始滚动(启用分页)第一个有点偏离屏幕: 在这里输入图像说明

这就是问题。 本来我的观点有3个意见,我想滚动和只显示3个意见。 但是当它滚动(启用分页)时,它隐藏了第一个视图的一点点,并显示下一个页面的下一个第一个视图的一点点。

这里是一个video,因为它很难解释: 问题的video(Dropbox)

这是我的UICollectionView设置的图片: 在这里输入图像说明

如果有人可以帮助,这将是非常好的!

根本问题是stream布局不支持分页。 为了达到寻呼效果,你将不得不牺牲单元之间的空间。 并仔细计算单元格框架,并使其可以被收集视图框架划分而不剩余。 我会解释原因。

说下面的布局是你想要的。

在这里输入图像说明

请注意,最左侧的边距(绿色)不是单元格间距的一部分。 它由stream程布局部分插入确定。 由于stream布局不支持异构间距值。 这不是一件小事。

因此,设置间距和插入后。 以下布局是你会得到的。

在这里输入图像说明

滚动到下一页后。 你的细胞显然不像你所期望的那样alignment。

在这里输入图像说明

使单元格间距为0可以解决此问题。 但是,如果您希望页面上有额外的边距,则会限制您的devise,尤其是如果边距与单元格间距不同。 它还要求视图框架必须可以被单元框架整除。 有时,如果您的视图框架不固定(考虑旋转情况),这是一个痛苦。

真正的解决scheme是inheritanceUICollectionViewFlowLayout并覆盖以下方法

 - (CGSize)collectionViewContentSize { // Only support single section for now. // Only support Horizontal scroll NSUInteger count = [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:0]; CGSize canvasSize = self.collectionView.frame.size; CGSize contentSize = canvasSize; if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal) { NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1; NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1; NSUInteger page = ceilf((CGFloat)count / (CGFloat)(rowCount * columnCount)); contentSize.width = page * canvasSize.width; } return contentSize; } - (CGRect)frameForItemAtIndexPath:(NSIndexPath *)indexPath { CGSize canvasSize = self.collectionView.frame.size; NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1; NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1; CGFloat pageMarginX = (canvasSize.width - columnCount * self.itemSize.width - (columnCount > 1 ? (columnCount - 1) * self.minimumLineSpacing : 0)) / 2.0f; CGFloat pageMarginY = (canvasSize.height - rowCount * self.itemSize.height - (rowCount > 1 ? (rowCount - 1) * self.minimumInteritemSpacing : 0)) / 2.0f; NSUInteger page = indexPath.row / (rowCount * columnCount); NSUInteger remainder = indexPath.row - page * (rowCount * columnCount); NSUInteger row = remainder / columnCount; NSUInteger column = remainder - row * columnCount; CGRect cellFrame = CGRectZero; cellFrame.origin.x = pageMarginX + column * (self.itemSize.width + self.minimumLineSpacing); cellFrame.origin.y = pageMarginY + row * (self.itemSize.height + self.minimumInteritemSpacing); cellFrame.size.width = self.itemSize.width; cellFrame.size.height = self.itemSize.height; if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal) { cellFrame.origin.x += page * canvasSize.width; } return cellFrame; } - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewLayoutAttributes * attr = [super layoutAttributesForItemAtIndexPath:indexPath]; attr.frame = [self frameForItemAtIndexPath:indexPath]; return attr; } - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { NSArray * originAttrs = [super layoutAttributesForElementsInRect:rect]; NSMutableArray * attrs = [NSMutableArray array]; [originAttrs enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * attr, NSUInteger idx, BOOL *stop) { NSIndexPath * idxPath = attr.indexPath; CGRect itemFrame = [self frameForItemAtIndexPath:idxPath]; if (CGRectIntersectsRect(itemFrame, rect)) { attr = [self layoutAttributesForItemAtIndexPath:idxPath]; [attrs addObject:attr]; } }]; return attrs; } 

注意,上面的代码片段只支持单段和水平滚动方向。 但是扩展并不难。

另外,如果你没有数百万的细胞。 caching这些UICollectionViewLayoutAttributes可能是一个好主意。

您可以禁用UICollectionView上的分页,并实现自定义页面宽度/偏移量的自定义水平滚动/分页机制,如下所示:

 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { float pageWidth = 210; float currentOffset = scrollView.contentOffset.x; float targetOffset = targetContentOffset->x; float newTargetOffset = 0; if (targetOffset > currentOffset) newTargetOffset = ceilf(currentOffset / pageWidth) * pageWidth; else newTargetOffset = floorf(currentOffset / pageWidth) * pageWidth; if (newTargetOffset < 0) newTargetOffset = 0; else if (newTargetOffset > scrollView.contentSize.width) newTargetOffset = scrollView.contentSize.width; targetContentOffset->x = currentOffset; [scrollView setContentOffset:CGPointMake(newTargetOffset, 0) animated:YES]; } 

这个答案是晚了,但我刚刚玩过这个问题,发现漂移的原因是行间距 。 如果您希望UICollectionView / FlowLayout以您的单元格宽度的精确倍数进行分页,则必须设置:

 UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)collectionView.collectionViewLayout; flowLayout.minimumLineSpacing = 0.0; 

你不会觉得行间距在水平滚动中起作用,但显然它确实如此。

在我的情况下,我正在尝试从左到右分页,一次一个单元,单元之间没有空格。 页面的每一个页面都会从所需的位置引入一点点漂移,并且它看起来是线性积聚的。 〜10.0点/回合 我意识到10.0是stream布局中minimumLineSpacing的默认值。 当我将其设置为0.0时 ,没有漂移,当我将其设置为边界宽度的一半时,每个页面漂移额外一半的边界。

更改minimumInteritemSpacing 不起作用

编辑 – 从UICollectionViewFlowLayout的文档:

@property(非primefaces)CGFloat minimumLineSpacing;

讨论

对于垂直滚动网格,此值表示连续行之间的最小间距。 对于水平滚动网格,此值表示连续列之间的最小间距。 此间距不适用于标题和第一行之间或最后一行和页脚之间的空间。

该属性的默认值是10.0。

在这里输入图像说明

下面的文章解决scheme是优雅和简单的。 主要的想法是在您的collectionView顶部创buildscrollView并传递所有contentOffset值。

http://b2cloud.com.au/tutorial/uiscrollview-paging-size/

应该说实施这个方法:

 - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity; 

我没有实现像使用pagingEnabled = YES的平滑animation。

我知道这个问题是古老的,但是对于偶然发生的事情。

所有你需要做的改正这是设置MinimumInterItemSpacing为0,并减less内容的框架。

我想我明白了这个问题。 我会尽力让你明白。

如果你仔细观察,那么你会看到这个问题只是逐渐发生,而不仅仅是在第一页刷卡。

在这里输入图像说明

如果我理解正确,在您的应用程序中,目前,每个UICollectionView项目都是我们所看到的那些圆形框,并且在它们之间有一些不变的边界/余量。 这是造成这个问题的原因。

相反,你应该做的是制作一个UICollectionView项目,它是整个视图宽度的三分之一,然后在里面添加这个舍入的图像视图。 要引用图像,绿色应该是你的UICollectionViewItem而不是黑色的。

@devdavid是在flowLayout.minimumLineSpacing零点上。

也可以在布局编辑器中完成,将行的最小间距设置为0:

更简单的方法

你有自己的UICollectionViewFlowLayout吗?

如果是这样的话,添加-(CGPoint) targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity将帮助您计算滚动视图应该停止的位置。

这可能工作(NB:UNTESTED!):

 -(CGPoint) targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { CGFloat offsetAdjustment = MAXFLOAT; CGFloat targetX = proposedContentOffset.x + self.minimumInteritemSpacing + self.sectionInset.left; CGRect targetRect = CGRectMake(proposedContentOffset.x, 0.0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height); NSArray *array = [super layoutAttributesForElementsInRect:targetRect]; for(UICollectionViewLayoutAttributes *layoutAttributes in array) { if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) { CGFloat itemX = layoutAttributes.frame.origin.x; if (ABS(itemX - targetX) < ABS(offsetAdjustment)) { offsetAdjustment = itemX - targetX; } } } return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y); } 

我的答案是基于回答https://stackoverflow.com/a/27242179/440168但更简单。;

在这里输入图像说明

你应该把UIScrollView放在UICollectionView上面,给它们相同的大小:

 @property (nonatomic, weak) IBOutlet UICollectionView *collectionView; @property (nonatomic, weak) IBOutlet UIScrollView *scrollView; 

然后configuration集合视图的contentInset ,例如:

 CGFloat inset = self.view.bounds.size.width*2/9; self.collectionView.contentInset = UIEdgeInsetsMake(0, inset, 0, inset); 

contentSize

 self.scrollView.contentSize = CGSizeMake(self.placesCollectionView.bounds.size.width*[self.collectionView numberOfItemsInSection:0],0); 

不要忘记设置滚动视图的代表:

 self.scrollView.delegate = self; 

并实施主魔术:

 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView == self.scrollView) { CGFloat inset = self.view.bounds.size.width*2/9; CGFloat scale = (self.placesCollectionView.bounds.size.width-2*inset)/scrollView.bounds.size.width; self.collectionView.contentOffset = CGPointMake(scrollView.contentOffset.x*scale - inset, 0); } } 

你的UICollectionView的宽度应该是单元大小宽度+左右UICollectionView的精确乘积。 在你的例子中,如果单元格宽度是96,那么UICollectionView的宽度应该是(96 + 5 + 5) * 3 = 318 。 或者,如果你想保持UICollectionView的320宽度,你的单元格的宽度应该是320 / 3 - 5 - 5 = 96.666

如果这没有帮助,当应用程序运行时, UICollectionView的宽度可能与xib文件中设置的宽度不同。 要检查这一点 – 添加一个NSLog语句来在运行时打印视图的大小:

 NSLog(@"%@", NSStringFromCGRect(uiContentViewController.view.frame)); 

这是我遇到的同样的问题,我张贴在另一篇文章我的解决scheme,所以我会再次发布在这里。

我find了一个解决scheme,它涉及到UICollectionViewFlowLayout的子类化。

我CollectionViewCell大小为302 X 457,我设置我的最小行距为18(每个细胞9pix)

当你从这个类延伸时,有几个方法需要被覆盖。 其中之一是

  • (CGSize)collectionViewContentSize

在这个方法中,我需要加起来在UICollectionView中的总宽度。 包括([datasource count] * widthOfCollectionViewCell)+([datasource count] * 18)

这里是我自定义的UICollectionViewFlowLayout方法….

 -(id)init { if((self = [super init])){ self.itemSize = CGSizeMake(302, 457); self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10); self.minimumInteritemSpacing = 0.0f; self.minimumLineSpacing = 18.0f; [self setScrollDirection:UICollectionViewScrollDirectionHorizontal]; } return self; } -(CGSize)collectionViewContentSize{ return CGSizeMake((numCellsCount * 302)+(numCellsCount * 18), 457); } 

这对我有用,所以我希望别人觉得它有用!

您也可以将视图的宽度设置为“320 +间距”,然后将页面启用设置为是。 它会每次滚动“320 +间距”。 我认为这是因为页面启用将滚动视图的宽度,但不是屏幕的宽度。

我想我有这个问题的解决scheme。 但是,如果这是最好的,我不会。

UICollectionViewFlowLayout包含一个名为sectionInset的属性。 所以你可以设置部分插入任何你需要的是使1页等于一个部分。 因此,您的滚动应该自动适合页面(=部分)

我遇到了与分页类似的问题。 即使单元格插入全部为0,并且单元的宽度和高度与UICollectionView大小UICollectionView ,但分页并不合适。

我注意到这个版本中的错误( UICollectionView ,iOS 6):我可以看到,如果我使用宽度为310px或更高,高度为538px的UICollectionView,我遇到了麻烦。 但是,如果我把宽度减less到300px(相同的高度),那么我的工作就完美了!

对于一些未来的参考,我希望它有帮助!

当我尝试使用段插入和单元格和行间距对3 x 3网格单元格进行水平分页时,遇到了类似的问题。

我的答案(尝试了许多build议 – 包括UICollectionViewFlowLayout和各种UIScrollView委托解决scheme的子类)很简单。 我简单地使用了UICollectionView中的部分,将我的数据集分成9个部分(或更less),并使用numberOfSectionsInCollectionView和numberOfItemsInSection UICollectionView数据源方法。

UICollectionView的水平分页现在很漂亮。 我推荐这种方法给任何正在撕裂头发的人。

如果您为UICollectionView使用默认stream布局,并且不希望每个单元格之间有任何空格,则可以通过以下方法将其miniumumLineSpacing属性设置为0:

 ((UICollectionViewFlowLayout *) self.collectionView.collectionViewLayout).minimumLineSpacing = 0;