UICollectionView Horizontal Paging not centered

前端 未结 11 1640
感动是毒
感动是毒 2020-12-02 09:32

I have a horizontal scrolling collectionView with each cell the size of the view. When I page through the collectionView it doesn\'t page by cell. The cells aren\'t in the c

相关标签:
11条回答
  • 2020-12-02 09:33

    The code I just saw from Apple Official Guides and Sample Code:

    AssetViewController.swift:

    self.collectionView?.isPagingEnabled = true
    self.collectionView?.frame = view.frame.insetBy(dx: -20.0, dy: 0.0)
    

    this code enlarges the collection view so that it extends out of the screen, while the content is just within the screen edges

    0 讨论(0)
  • 2020-12-02 09:35

    After having a similar issue, I fixed mine by realizing that when using horizontal scrolling the height is now the width and the width is now the height because the default is set for vertical scrolling. Try switching the values and see if that helps. https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/UsingtheFlowLayout/UsingtheFlowLayout.html

    0 讨论(0)
  • 2020-12-02 09:39

    Swift 3.0 set your own 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
    
    0 讨论(0)
  • 2020-12-02 09:41

    Demo here in 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
    }
    

    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
    }
    
    0 讨论(0)
  • 2020-12-02 09:41

    Swift 3 solution based on @Santos's answer, for use if if you have a regular horizontally paging collection view without a page control like Paolo was using in his Swift 3 example.

    I used this to solve an issue where a horizontally paging cell full screen cells with a custom UICollectionViewFlowLayout animator didn't finish rotating AND ended up offset so that the the edges of a full screen cell frame were increasingly horizontally off set from the collection view's bounds as you scrolled (like in the video OP shared).

     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
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-02 09:44

    Remove spaces between items. For horizontal scrolling collection view set minimum line spacing to 0. You can do this with interface builder or with method of UICollectionViewDelegateFlowLayout protocol:

    - (CGFloat)collectionView:(UICollectionView *)collectionView 
                       layout:(UICollectionViewLayout *)collectionViewLayout 
            minimumLineSpacingForSectionAtIndex:(NSInteger)section {
        return 0;    
    }
    

    enter image description here

    Another way is making your cell's width less than collectionView's width for a value of horizontal space between items. Then add section insets with left and right insets that equal a half of horizontal space between items. For example, your minimum line spacing is 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);
    }
    

    enter image description here

    And third way: manipulate collectionView scroll in scrollViewDidEndDecelerating: 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];
        }
    }
    

    enter image description here

    0 讨论(0)
提交回复
热议问题