web-dev-qa-db-ja.com

Swift3.0でUICollectionViewのセルを中央揃えにする方法は?

説明:

Objective-CおよびSwift2.0に対する回答: ICollectionViewのセルを中央揃えにする方法

私は通常、Swift2.0回答をSwift3.0ソリューションに変換しようとしますが、方法は次のとおりです。

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
        let edgeInsets = (screenWight - (CGFloat(elements.count) * 50) - (CGFloat(elements.count) * 10)) / 2
        return UIEdgeInsetsMake(0, edgeInsets, 0, 0);
    }

Swift3.0には存在していないようで、私が見つけた他の便利な方法は次のとおりです。

func collectionView(_ collectionView: UICollectionView, transitionLayoutForOldLayout fromLayout: UICollectionViewLayout, newLayout toLayout: UICollectionViewLayout) -> UICollectionViewTransitionLayout {
        <#code#>
}

しかし、私はそれを正しく実装する方法がわかりません。

質問:

Swift3.0UICollectionViewのセルを中央揃えにする方法

(iOSおよびtvOSのシンプルで一般的なソリューションは完璧でしょう)

10
kemicofa

これが最終的に私が使用したソリューションになりました。コードのコメントを読んで理解を深めてください。 Swift 3.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

        //Where elements_count is the count of all your items in that
        //Collection view...
        let cellCount = CGFloat(elements_count)

        //If the cell count is zero, there is no point in calculating anything.
        if cellCount > 0 {
            let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
            let cellWidth = flowLayout.itemSize.width + flowLayout.minimumInteritemSpacing

            //20.00 was just extra spacing I wanted to add to my cell.
            let totalCellWidth = cellWidth*cellCount + 20.00 * (cellCount-1)
            let contentWidth = collectionView.frame.size.width - collectionView.contentInset.left - collectionView.contentInset.right

            if (totalCellWidth < contentWidth) {
                //If the number of cells that exists take up less room than the 
                //collection view width... then there is an actual point to centering them.

                //Calculate the right amount of padding to center the cells.
                let padding = (contentWidth - totalCellWidth) / 2.0
                return UIEdgeInsetsMake(0, padding, 0, padding)
            } else {
                //Pretty much if the number of cells that exist take up
                //more room than the actual collectionView width, there is no
                // point in trying to center them. So we leave the default behavior.
                return UIEdgeInsetsMake(0, 40, 0, 40)
            }
        }

        return UIEdgeInsets.zero
    }
17
kemicofa

rottenoats の答えは素晴らしいですが、余分なスペースのバグがあり、利用可能なSwift 3構文の多くを使用しません。これを修正し、数を減らしました。ローカル変数への依存関係。

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

    // Make sure that the number of items is worth the computing effort.
    guard let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout,
        let dataSourceCount = collectionView.dataSource?.collectionView(collectionView, numberOfItemsInSection: section),
        dataSourceCount > 0 else {
            return .zero
    }


    let cellCount = CGFloat(dataSourceCount)
    let itemSpacing = flowLayout.minimumInteritemSpacing
    let cellWidth = flowLayout.itemSize.width + itemSpacing
    var insets = flowLayout.sectionInset


    // Make sure to remove the last item spacing or it will
    // miscalculate the actual total width.
    let totalCellWidth = (cellWidth * cellCount) - itemSpacing
    let contentWidth = collectionView.frame.size.width - collectionView.contentInset.left - collectionView.contentInset.right


    // If the number of cells that exist take up less room than the
    // collection view width, then center the content with the appropriate insets.
    // Otherwise return the default layout inset.
    guard totalCellWidth < contentWidth else {
        return insets
    }


    // Calculate the right amount of padding to center the cells.
    let padding = (contentWidth - totalCellWidth) / 2.0
    insets.left = padding
    insets.right = padding
    return insets
}

N.B .:このスニペットは水平スクロールに対してのみ機能しますが、簡単に調整できます。

17
jbouaziz

@rottenoats回答のわずかな適応。これはより一般的です。

最も重要なことは、View ControllerをUICollectionViewDelegateFlowLayoutプロトコルに準拠させることです。

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

    guard let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout else {
        return .zero
    }

    let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))

    if cellCount > 0 {
        let cellWidth = flowLayout.itemSize.width + flowLayout.minimumInteritemSpacing

        let totalCellWidth = cellWidth * cellCount
        let contentWidth = collectionView.frame.size.width - collectionView.contentInset.left - collectionView.contentInset.right - flowLayout.headerReferenceSize.width - flowLayout.footerReferenceSize.width

        if (totalCellWidth < contentWidth) {
            let padding = (contentWidth - totalCellWidth + flowLayout.minimumInteritemSpacing) / 2.0
            return UIEdgeInsetsMake(0, padding, 0, 0)
        }
    }

    return .zero
}
7
mm282

ICollectionViewDelegateFlowLayout に準拠していると仮定すると、次のようになります。

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let edgeInsets = (screenWight - (CGFloat(elements.count) * 50) - (CGFloat(elements.count) * 10)) / 2
    return UIEdgeInsets(top: 0, left: edgeInsets, bottom: 0, right: 0)
}
3
Ahmad F

お探しのメソッドは、Swift 3。新しい署名は次のとおりです。

optional public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets

P.S:このメソッドはUICollectionViewDelegateFlowLayoutプロトコルに存在します。
これが役立つことを願っています。

3
Adeel
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {

let allCellWidth = KcellWidth * numberOfCell
let cellSpacingWidth = CellSpacing * (numberOfCell - 1)

let leftInset = (collectionViewWidth - CGFloat(allCellWidth + cellSpacingWidth)) / 2
let rightInset = leftInset

return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}
1
yogesh wadhwa

ここに最近の解決策があり、Swift 5.0

extension YourViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAt section: Int) -> UIEdgeInsets {
        let itemWidth = 80
        let spacingWidth = 4
        let numberOfItems = collectionView.numberOfItems(inSection: section)
        let cellSpacingWidth = numberOfItem * spacingWidth
        let totalCellWidth = numberOfItems * itemWidth + cellSpacingWidth
        let inset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth)) / 2
        return UIEdgeInsets(top: 5, left: inset, bottom: 5, right: inset)
    }
}
1

collectionView(_:layout:insetForSectionAt:)メソッドを見つけるにはUICollectionViewDelegateFlowLayoutプロトコルにconformする必要があり、そこで定義されています。次の実装は、Swift 4で水平コレクションビューで正常に動作します

extension YourViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        let cellWidth = CGFloat(integerLiteral: YourCellsWidth)
        let count = self.YourCollectionViewDataSource.count
        let top = CGFloat(integerLiteral: 0)    // I don't need to set top and bottom spacing
        let cellsAccumulatedWidth = CGFloat(integerLiteral: count) * cellWidth
        let cellsSpacingAccumulatedWidth = CGFloat(integerLiteral: (count - 1) * 5)
        let left = (self.collectionView.frame.size.width - cellsAccumulatedWidth - cellsSpacingAccumulatedWidth) / 2
        let bottom = top
        let right = left

        return UIEdgeInsetsMake(top, left, bottom, right);
    }
}
0
Mehdi

このコードは、Swift 4.に追加のアイテムがある場合でも、あらゆるタイプのコレクションビューを水平方向に中央に配置する必要があります。

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let cellWidth: CGFloat = flowLayout.itemSize.width
    let cellSpacing: CGFloat = flowLayout.minimumInteritemSpacing
    let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
    var collectionWidth = collectionView.frame.size.width
    if #available(iOS 11.0, *) {
        collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
    }
    let totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
    if totalWidth <= collectionWidth {
        let edgeInset = (collectionWidth - totalWidth) / 2
        return UIEdgeInsetsMake(flowLayout.sectionInset.top, edgeInset, flowLayout.sectionInset.bottom, edgeInset)
    } else {
        return flowLayout.sectionInset
    }
}

UICollectionViewControllerをサブクラス化しない場合は忘れないでください。クラスがUICollectionViewDelegateFlowLayoutプロトコルに準拠していることを確認してください

0
Saeed Ir