web-dev-qa-db-ja.com

UICollectionView水平ページングが中央に配置されていません

各セルがビューのサイズで水平にスクロールするcollectionViewがあります。 collectionViewをページングするとき、セルごとにページングしません。セルは画面の中央にはありません。私はそれを修正するためにたくさんのことを試しましたが、運がありませんでした。問題のビデオは次のとおりです。 https://www.youtube.com/watch?v=tXsxWelk16w アイデアはありますか?

35
mlevi

アイテム間のスペースを削除します。水平スクロールコレクションビューの場合、最小行間隔を0に設定します。これは、インターフェイスビルダーまたはUICollectionViewDelegateFlowLayoutプロトコルのメソッドを使用して実行できます。

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

enter image description here

別の方法は、アイテム間の水平方向のスペースの値に対してセルの幅を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);
}

enter image description here

3番目の方法: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];
    }
}

enter image description here

116
Vlad

ここのデモSwift 3https://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
}
31
Paolo Musolino

@ vlad-cheのSwiftバージョンは回答を受け入れました:

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)
    }
}
12

行間隔を削除してセルを中央に保持するSwift 4ソリューション:

public func collectionView(_ collectionView: UICollectionView, layout 
collectionViewLayout: UICollectionViewLayout, 
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 0
}
4
TejAces

セルの間にスペースがあるcollectionViewフレームよりも小さいセルを使用できることにより、ユーザーに、どちらの側にもスクロールする他のセルがあることをユーザーに示唆できます。ただし、ページの中央揃えは期待どおりに機能しません。ユーザーがスクロールすると、各セルは徐々にオフセットが大きくなります。以下がうまく機能することがわかりました。各セルのセンタリング/スナップアニメーションは、collectionViewのスクロールが自然に終了する場所を微調整するだけなので、collectionViewをすばやく動かして別のindexPathプロパティを十分に大きく設定して、セルが含まれるフレームのエッジに貼り付かないようにすることが重要です。また、セル間にスペースがあるため、ターゲットはsectionInsetをnilのindexPathに着陸させ、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;
    }
}
3
Dallas Johnson

スイフト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)
            }
        }
    }
2
Umesh Verma

Apple公式ガイドとサンプルコードから見たコード:

AssetViewController.Swift:

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

同様の問題が発生した後、水平スクロールを使用する場合、デフォルトは垂直スクロールに設定されているため、高さは幅になり、幅は高さになります。値を切り替えてみて、それが役立つかどうかを確認してください。 https://developer.Apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/UsingtheFlowLayout/UsingtheFlowLayout.html

0
user6520705

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
0
santos