Ios UICollectionView水平分页未居中
我有一个水平滚动的collectionView,每个单元格都有视图的大小。当我在collectionView中翻页时,它不会逐单元格翻页。单元格不在屏幕中央。我已经尝试了很多方法来修复它,但没有任何运气。 下面是一段关于这个问题的视频:Ios UICollectionView水平分页未居中,ios,uiscrollview,uicollectionview,Ios,Uiscrollview,Uicollectionview,我有一个水平滚动的collectionView,每个单元格都有视图的大小。当我在collectionView中翻页时,它不会逐单元格翻页。单元格不在屏幕中央。我已经尝试了很多方法来修复它,但没有任何运气。 下面是一段关于这个问题的视频: 有什么想法吗?删除项目之间的空格。对于水平滚动集合视图,将最小行距设置为0。您可以使用interface builder或使用UICollectionViewDelegateFlowLayout协议的方法执行此操作: - (CGFloat)collectionV
有什么想法吗?删除项目之间的空格。对于水平滚动集合视图,将最小行距设置为0。您可以使用interface builder或使用
UICollectionViewDelegateFlowLayout
协议的方法执行此操作:
- (CGFloat)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 0;
}
另一种方法是使单元格的宽度小于项目之间水平间距值的collectionView宽度。然后添加具有左、右插图的剖面插图,这些插图等于项目之间水平空间的一半。例如,最小行距为10:
- (CGFloat)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(collectionView.frame.size.width - 10, collectionView.frame.size.height);
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(0, 5, 0, 5);
}
第三种方法:在ScrollViewDiEndDecelling:
method:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
if (scrollView == self.collectionView) {
CGPoint currentCellOffset = self.collectionView.contentOffset;
currentCellOffset.x += self.collectionView.frame.size.width / 2;
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:currentCellOffset];
[self.collectionView scrollToItemAtIndexPath:indexPath
atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
animated:YES];
}
}
能够在
collectionView
框架中使用更小的单元格,并且单元格之间留有空间,这样就可以向用户暗示,两边都有其他单元格可以滚动,这是用户体验的一大胜利。但是,页面的居中并不像预期的那样工作,随着用户滚动,每个单元格的偏移量逐渐增大。我发现以下方法很有效。用户几乎看不到每个单元格上的居中/捕捉动画,因为它只是调整collectionView
滚动自然结束的位置,而不是猛拉collectionView
快速滚动到另一个indexPath
。将sectionInset
属性设置得足够大,以允许单元格不粘附到包含的帧边缘,这一点仍然很重要。此外,由于单元格之间有空格,目标可能会降落在一个为nil的indepath
上,这将导致collectionView
回滚到起始位置。我已经修复了一点偏移,然后再试一次,但是这里可以采取不同的方法
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset
{
//Ensure the scrollview is the collectionview we care about
if (scrollView == self.collectionView) {
// Find cell closest to the frame centre with reference from the targetContentOffset.
CGPoint frameCentre = self.collectionView.center;
CGPoint targetOffsetToCentre = CGPointMake((* targetContentOffset).x + frameCentre.x, (* targetContentOffset).y + frameCentre.y);
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:targetOffsetToCentre];
//Check for "edgecase" that the target will land between cells and then find a close neighbour to prevent scrolling to index {0,0}.
while (!indexPath) {
targetOffsetToCentre.x += ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).minimumInteritemSpacing;
indexPath = [self.collectionView indexPathForItemAtPoint:targetOffsetToCentre];
}
// Find the centre of the target cell
CGPoint centreCellPoint = [self.collectionView layoutAttributesForItemAtIndexPath:indexPath].center;
// Calculate the desired scrollview offset with reference to desired target cell centre.
CGPoint desiredOffset = CGPointMake(centreCellPoint.x - frameCentre.x, centreCellPoint.y - frameCentre.y);
*targetContentOffset = desiredOffset;
}
}
Swift 3.0设置您自己的UICollectionViewFlowLayout
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
let width = UIScreen.main.bounds.width
layout.itemSize = CGSize(width: width, height: 154)
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.scrollDirection = .horizontal
collectionView?.collectionViewLayout = layout
雨燕3中的演示:
func-scrollViewWillendDraging(scrollView:UIScrollView,withVelocity:CGPoint,targetContentOffset:UnsafemeutablePointer){
让pageWidth=浮动(itemWidth+itemSpacing)
让targetXContentOffset=Float(targetContentOffset.pointee.x)
让contentWidth=Float(collectionView!.contentSize.width)
var newPage=Float(self.pageControl.currentPage)
如果速度.x==0{
新建页面=地板((targetXContentOffset-浮动(页面宽度)/2)/浮动(页面宽度))+1.0
}否则{
newPage=Float(velocity.x>0?self.pageControl.currentPage+1:self.pageControl.currentPage-1)
如果newPage<0{
newPage=0
}
如果(新建页面>内容宽度/页面宽度){
newPage=ceil(contentWidth/pageWidth)-1.0
}
}
self.pageControl.currentPage=Int(newPage)
设point=CGPoint(x:CGFloat(newPage*pageWidth),y:targetContentOffset.pointee.y)
targetContentOffset.pointee=点
}
Swift 4:
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let pageWidth = Float(itemWidth + itemSpacing)
let targetXContentOffset = Float(targetContentOffset.pointee.x)
let contentWidth = Float(collectionView!.contentSize.width )
var newPage = Float(self.pageControl.currentPage)
if velocity.x == 0 {
newPage = floor( (targetXContentOffset - Float(pageWidth) / 2) / Float(pageWidth)) + 1.0
} else {
newPage = Float(velocity.x > 0 ? self.pageControl.currentPage + 1 : self.pageControl.currentPage - 1)
if newPage < 0 {
newPage = 0
}
if (newPage > contentWidth / pageWidth) {
newPage = ceil(contentWidth / pageWidth) - 1.0
}
}
self.pageControl.currentPage = Int(newPage)
let point = CGPoint (x: CGFloat(newPage * pageWidth), y: targetContentOffset.pointee.y)
targetContentOffset.pointee = point
}
func-scrollViewWillendDraging(scrollView:UIScrollView,withVelocity:CGPoint,targetContentOffset:UnsafemeutablePointer){
让pageWidth=浮动(itemWidth+itemSpacing)
让targetXContentOffset=Float(targetContentOffset.pointee.x)
让contentWidth=Float(collectionView!.contentSize.width)
var newPage=Float(self.pageControl.currentPage)
如果速度.x==0{
新建页面=地板((targetXContentOffset-浮动(页面宽度)/2)/浮动(页面宽度))+1.0
}否则{
newPage=Float(velocity.x>0?self.pageControl.currentPage+1:self.pageControl.currentPage-1)
如果newPage<0{
newPage=0
}
如果(新建页面>内容宽度/页面宽度){
newPage=ceil(contentWidth/pageWidth)-1.0
}
}
self.pageControl.currentPage=Int(newPage)
设point=CGPoint(x:CGFloat(newPage*pageWidth),y:targetContentOffset.pointee.y)
targetContentOffset.pointee=点
}
在遇到类似问题后,我修复了我的问题,因为我意识到使用水平滚动时,高度现在是宽度,宽度现在是高度,因为默认设置为垂直滚动。尝试切换这些值,看看是否有帮助。
Swift 3解决方案基于@Santos的答案,如果您有一个常规的水平分页集合视图,而没有页面控件,则可以使用,就像Paolo在他的Swift 3示例中使用的那样 我用它来解决一个问题,即带有自定义UICollectionViewFlowLayout动画师的水平分页单元格全屏单元格没有完成旋转,并最终偏移,因此当您滚动时,全屏单元格帧的边缘越来越水平地偏离集合视图的边界(如在视频OP共享中)
func-scrollViewWillendDraging(scrollView:UIScrollView,withVelocity:CGPoint,targetContentOffset:UnsafemeutablePointer){
//确保scrollview是我们所关心的collectionView中的一个
if(scrollView==self.collectionView){
//从targetContentOffset中查找最靠近帧中心的单元格。
让frameCenter:CGPoint=self.collectionView.center
var targetOffsetToCenter:CGPoint=CGPoint(x:targetContentOffset.pointee.x+frameCenter.x,y:targetContentOffset.pointee.y+frameCenter.y)
变量indexPath:indexPath?=self.collectionView.indexPathForItem(位于:targetOffsetToCenter)
//检查“边缘情况”,目标将正好落在单元格和下一个相邻单元格之间,以防止滚动到索引{0,0}。
而indexPath==nil{
targetOffsetToCenter.x+=10
indexPath=self.collection
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let pageWidth = Float(itemWidth + itemSpacing)
let targetXContentOffset = Float(targetContentOffset.pointee.x)
let contentWidth = Float(collectionView!.contentSize.width )
var newPage = Float(self.pageControl.currentPage)
if velocity.x == 0 {
newPage = floor( (targetXContentOffset - Float(pageWidth) / 2) / Float(pageWidth)) + 1.0
} else {
newPage = Float(velocity.x > 0 ? self.pageControl.currentPage + 1 : self.pageControl.currentPage - 1)
if newPage < 0 {
newPage = 0
}
if (newPage > contentWidth / pageWidth) {
newPage = ceil(contentWidth / pageWidth) - 1.0
}
}
self.pageControl.currentPage = Int(newPage)
let point = CGPoint (x: CGFloat(newPage * pageWidth), y: targetContentOffset.pointee.y)
targetContentOffset.pointee = point
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
// Ensure the scrollview is the one on the collectionView we care are working with
if (scrollView == self.collectionView) {
// Find cell closest to the frame centre with reference from the targetContentOffset.
let frameCenter: CGPoint = self.collectionView.center
var targetOffsetToCenter: CGPoint = CGPoint(x: targetContentOffset.pointee.x + frameCenter.x, y: targetContentOffset.pointee.y + frameCenter.y)
var indexPath: IndexPath? = self.collectionView.indexPathForItem(at: targetOffsetToCenter)
// Check for "edge case" where the target will land right between cells and then next neighbor to prevent scrolling to index {0,0}.
while indexPath == nil {
targetOffsetToCenter.x += 10
indexPath = self.collectionView.indexPathForItem(at: targetOffsetToCenter)
}
// safe unwrap to make sure we found a valid index path
if let index = indexPath {
// Find the centre of the target cell
if let centerCellPoint: CGPoint = collectionView.layoutAttributesForItem(at: index)?.center {
// Calculate the desired scrollview offset with reference to desired target cell centre.
let desiredOffset: CGPoint = CGPoint(x: centerCellPoint.x - frameCenter.x, y: centerCellPoint.y - frameCenter.y)
targetContentOffset.pointee = desiredOffset
}
}
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if scrollView == self.collectionView {
var currentCellOffset = self.collectionView.contentOffset
currentCellOffset.x += self.collectionView.frame.width / 2
if let indexPath = self.collectionView.indexPathForItem(at: currentCellOffset) {
self.collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
}
}
self.collectionView?.isPagingEnabled = true
self.collectionView?.frame = view.frame.insetBy(dx: -20.0, dy: 0.0)
extension GoodsViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let frameSize = collectionView.frame.size
return CGSize(width: frameSize.width - 10, height: frameSize.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
}
}
public func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let itemWidth = cellSize.width + spacing
let inertialTargetX = targetContentOffset.pointee.x
let offsetFromPreviousPage = (inertialTargetX + collectionView.contentInset.left).truncatingRemainder(dividingBy: itemWidth)
// snap to the nearest page
let pagedX: CGFloat
if offsetFromPreviousPage > itemWidth / 2 {
pagedX = inertialTargetX + (itemWidth - offsetFromPreviousPage)
} else {
pagedX = inertialTargetX - offsetFromPreviousPage
}
let point = CGPoint(x: pagedX, y: targetContentOffset.pointee.y)
targetContentOffset.pointee = point
}