UICollectionView水平分页与3项

我需要在UICollectionView中显示3个项目,使用这种方式启用分页

在这里输入图像说明

但我越来越喜欢这个 在这里输入图像说明

我做了自定义stream程,加上分页启用,但无法得到我所需要的。 我该如何做到这一点,或者我应该看看哪个委托,或者指引我从哪里获得帮助。

- (void)awakeFromNib { self.itemSize = CGSizeMake(480, 626); self.minimumInteritemSpacing = 112; self.minimumLineSpacing = 112; self.scrollDirection = UICollectionViewScrollDirectionHorizontal; self.sectionInset = UIEdgeInsetsMake(0, 272, 0, 272); } 

编辑 :演示链接: https : //github.com/raheelsadiq/UICollectionView-horizo​​ntal-paging-with-3-items

经过大量的search,我做到了,find下一个点滚动到并禁用分页。 在scrollviewWillEndDragging中滚动到下一个单元格x。

 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { float pageWidth = 480 + 50; // width + space 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, scrollView.contentOffset.y) animated:YES]; } 

我也不得不使左右小,中心大,所以我做了变形。 问题是find索引,所以很难find。

在这个相同的方法中左右变换使用newTargetOffset

 int index = newTargetOffset / pageWidth; if (index == 0) { // If first index UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; [UIView animateWithDuration:ANIMATION_SPEED animations:^{ cell.transform = CGAffineTransformIdentity; }]; cell = [self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index + 1 inSection:0]]; [UIView animateWithDuration:ANIMATION_SPEED animations:^{ cell.transform = TRANSFORM_CELL_VALUE; }]; }else{ UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; [UIView animateWithDuration:ANIMATION_SPEED animations:^{ cell.transform = CGAffineTransformIdentity; }]; index --; // left cell = [self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; [UIView animateWithDuration:ANIMATION_SPEED animations:^{ cell.transform = TRANSFORM_CELL_VALUE; }]; index ++; index ++; // right cell = [self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; [UIView animateWithDuration:ANIMATION_SPEED animations:^{ cell.transform = TRANSFORM_CELL_VALUE; }]; } 

并在cellForRowAtIndex中添加

 if (indexPath.row == 0 && isfirstTimeTransform) { // make a bool and set YES initially, this check will prevent fist load transform isfirstTimeTransform = NO; }else{ cell.transform = TRANSFORM_CELL_VALUE; // the new cell will always be transform and without animation } 

添加这两个macros也可以同时处理这两个macros

 #define TRANSFORM_CELL_VALUE CGAffineTransformMakeScale(0.8, 0.8) #define ANIMATION_SPEED 0.2 

最终的结果是

在这里输入图像说明

第一部分@Raheel SadiqSwift 3中回答,没有变换。

 func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { let pageWidth: Float = Float(self.collectionView.frame.width / 3) //480 + 50 // width + space let currentOffset: Float = Float(scrollView.contentOffset.x) let targetOffset: Float = Float(targetContentOffset.pointee.x) var newTargetOffset: Float = 0 if targetOffset > currentOffset { newTargetOffset = ceilf(currentOffset / pageWidth) * pageWidth } else { newTargetOffset = floorf(currentOffset / pageWidth) * pageWidth } if newTargetOffset < 0 { newTargetOffset = 0 } else if (newTargetOffset > Float(scrollView.contentSize.width)){ newTargetOffset = Float(Float(scrollView.contentSize.width)) } targetContentOffset.pointee.x = CGFloat(currentOffset) scrollView.setContentOffset(CGPoint(x: CGFloat(newTargetOffset), y: scrollView.contentOffset.y), animated: true) } 

您将不得不覆盖stream布局的targetContentOffsetForProposedContentOffset:withScrollingVelocity:方法。 这样你可以捕捉滚动视图的停止点。

 -(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { CGFloat yOffset = MAXFLOAT; CGRect proposedRect; proposedRect.origin = proposedContentOffset; proposedRect.size = self.collectionView.bounds.size; CGPoint proposedCenterPoint = CGPointMake(CGRectGetMidX(proposedRect), CGRectGetMidY(proposedRect)) ; NSArray *array = [super layoutAttributesForElementsInRect:proposedRect]; for (UICollectionViewLayoutAttributes *attributes in array) { CGFloat newOffset = attributes.center.y - proposedCenterPoint.y; if ( fabsf(newOffset) < fabs(yOffset)) { yOffset = newOffset; } } return CGPointMake(proposedContentOffset.x, proposedContentOffset.y + yOffset); } 

你也可以设置stream布局的sectionInset来居中第一个单元格和最后一个单元格。 我的例子是高度,但很容易切换到宽度。

 CGFloat height = (self.collectionView.bounds.size.height / 2.0 ) - (self.itemSize.height / 2.0) ; self.sectionInset = UIEdgeInsetsMake(height, 30.0, height, 30.0) ; 

Swift 3.0基于Raheel Sadiq的完整解决scheme

 var isfirstTimeTransform:Bool = true func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell : UICollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCustomViewCell", for: indexPath) if (indexPath.row == 0 && isfirstTimeTransform) { isfirstTimeTransform = false }else{ cell.transform = CGAffineTransform(scaleX: 0.8, y: 0.8) } return cell } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: collectionView.bounds.width/3, height: collectionView.bounds.height) } func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { // Simulate "Page" Function let pageWidth: Float = Float(self.collectionView.frame.width/3 + 20) let currentOffset: Float = Float(scrollView.contentOffset.x) let targetOffset: Float = Float(targetContentOffset.pointee.x) var newTargetOffset: Float = 0 if targetOffset > currentOffset { newTargetOffset = ceilf(currentOffset / pageWidth) * pageWidth } else { newTargetOffset = floorf(currentOffset / pageWidth) * pageWidth } if newTargetOffset < 0 { newTargetOffset = 0 } else if (newTargetOffset > Float(scrollView.contentSize.width)){ newTargetOffset = Float(Float(scrollView.contentSize.width)) } targetContentOffset.pointee.x = CGFloat(currentOffset) scrollView.setContentOffset(CGPoint(x: CGFloat(newTargetOffset), y: scrollView.contentOffset.y), animated: true) // Make Transition Effects for cells let duration = 0.2 var index = newTargetOffset / pageWidth; var cell:UICollectionViewCell = self.collectionView.cellForItem(at: IndexPath(row: Int(index), section: 0))! if (index == 0) { // If first index UIView.animate(withDuration: duration, delay: 0.0, options: [ .curveEaseOut], animations: { cell.transform = CGAffineTransform.identity }, completion: nil) index += 1 cell = self.collectionView.cellForItem(at: IndexPath(row: Int(index), section: 0))! UIView.animate(withDuration: duration, delay: 0.0, options: [ .curveEaseOut], animations: { cell.transform = CGAffineTransform(scaleX: 0.8, y: 0.8) }, completion: nil) }else{ UIView.animate(withDuration: duration, delay: 0.0, options: [ .curveEaseOut], animations: { cell.transform = CGAffineTransform.identity; }, completion: nil) index -= 1 // left if let cell = self.collectionView.cellForItem(at: IndexPath(row: Int(index), section: 0)) { UIView.animate(withDuration: duration, delay: 0.0, options: [ .curveEaseOut], animations: { cell.transform = CGAffineTransform(scaleX: 0.8, y: 0.8); }, completion: nil) } index += 1 index += 1 // right if let cell = self.collectionView.cellForItem(at: IndexPath(row: Int(index), section: 0)) { UIView.animate(withDuration: duration, delay: 0.0, options: [ .curveEaseOut], animations: { cell.transform = CGAffineTransform(scaleX: 0.8, y: 0.8); }, completion: nil) } } }