UICollectionView水平分页未居中

mle*_*evi 38 uiscrollview ios uicollectionview

我有一个水平滚动collectionView,每个单元格都是视图的大小.当我浏览collectionView时,它不会逐个页面.单元格不在屏幕的中心.我已经尝试了很多东西试图解决它,并没有任何运气.以下是该问题的视频:https: //www.youtube.com/watchv = tXsxWelk16w有什么想法吗?

Vla*_*lad 122

删除项目之间的空格.对于水平滚动集合视图,将最小行间距设置为0.您可以使用界面生成器或UICollectionViewDelegateFlowLayout协议方法执行此操作:

- (CGFloat)collectionView:(UICollectionView *)collectionView 
                   layout:(UICollectionViewLayout *)collectionViewLayout 
        minimumLineSpacingForSectionAtIndex:(NSInteger)section {
    return 0;    
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

另一种方法是使单元格的宽度小于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);
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

第三种方法:在scrollViewDidEndDecelerating:方法中操纵collectionView滚动:

- (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];
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 另一种方法:使单元格的宽度=(collectionView宽度-minimumLineSpacing)并添加一个部分插入,左右插入等于minimumLineSpacing / 2。 (2认同)
  • 我用这个解决方案更新了我的答案. (2认同)

小智 33

Swift 3中进行演示:https: //github.com/damienromito/CollectionViewCustom

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
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特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
}
Run Code Online (Sandbox Code Playgroud)

  • Swift 4代码在这里https://github.com/damienromito/CollectionViewCustom/blob/master/CollectionViewCustom/ViewController.swift (3认同)
  • 我如何控制它滚动的速度?我想增加它。 (2认同)
  • 为了工作,您必须在集合视图中禁用“启用分页” (2认同)

Ale*_*nko 14

Swift版@vlad-che接受了答案:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 6

斯威夫特 3

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)
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 它有效,但每次从页面移动到页面时,您都会看到一些奇怪的视觉效果。 (2认同)

Dal*_*son 5

能够使单元格较小的单元格collectionView与单元格之间留有空间,可以向用户暗示其他任何单元格都可以滚动到其中,这对于UX来说是一个巨大的胜利。但是,页面居中无法按预期工作,随着用户滚动,每个单元格逐渐变得越来越偏移。我发现以下方法可以很好地工作。用户几乎看不见每个单元格上的居中/捕捉动画,因为它只是调整collectionView滚动自然结束的位置,而不是抽动它collectionView快速滚动到另一个indexPath。拥有仍然很重要,sectionInset属性设置得足够大,以使单元格不会粘附到包含的框架边缘,。另外,由于单元之间存在空间,因此目标可以降落在indexPath的值是nil,这会导致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;
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

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
Run Code Online (Sandbox Code Playgroud)


Tej*_*ces 5

Swift 4解决方案,删除行距以保持单元居中:

public func collectionView(_ collectionView: UICollectionView, layout 
collectionViewLayout: UICollectionViewLayout, 
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 0
}
Run Code Online (Sandbox Code Playgroud)


Kev*_*oek 5

collectionView.isPagingEnabled如果您在设置 contentInset 或间距时追求(因此具有“适当的惯性感”等)但没有错误的偏移量的行为,那么这就是您所需要的:

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
}
Run Code Online (Sandbox Code Playgroud)