簡體   English   中英

如何在 Swift3.0 中居中對齊 UICollectionView 的單元格?

[英]How to center align the cells of a UICollectionView in Swift3.0?

說明:

Objective-CSwift2.0如何將Swift2.0 的單元格居中對齊?

我通常會嘗試將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.0居中對齊UICollectionView的單元格?

(適用於 iOS 和 tvOS 的簡單通用的解決方案將是完美的)

這最終成為我使用的解決方案。 閱讀代碼注釋以獲得更好的理解。 斯威夫特 5

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 UIEdgeInsets(top: 0, left: padding, bottom: 0, right: 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 UIEdgeInsets(top: 0, left: 40, bottom: 0, right: 40)
        }
    }
    return UIEdgeInsets.zero
}

雖然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
}

注意:此代碼段僅適用於水平滾動,但可以輕松調整。

對@rottenoats 的回答略有調整。 這是更通用的。

最重要的是記住讓你的視圖控制器符合 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
}

這是最近的解決方案,適用於 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)
    }
}

您正在尋找的方法在Swift 3具有不同的簽名。 新簽名是這樣的:

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

PS:此方法存在於UICollectionViewDelegateFlowLayout協議中。
希望這會有所幫助。

假設您符合UICollectionViewDelegateFlowLayout ,它應該是:

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

您需要符合UICollectionViewDelegateFlowLayout協議才能找到collectionView(_:layout:insetForSectionAt:)方法,它在那里定義。 以下實現在 swift 4 中適用於水平 collectionView

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

即使在Swift 4.0 中有額外的項目,此代碼也應將任何類型的集合視圖水平居中:

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協議

使用此解決方案進行居中對齊的水平滾動。

let totalCellWidth = Int(collectionView.frame.height * CGFloat(numberOfItems()))

        // if total width is greater than collection's width, then no need to align center
        if totalCellWidth > Int(collectionView.frame.width) {
            return UIEdgeInsets.zero
        }

        let totalSpacingWidth = cellSpacing * (numberOfItems() - 1)
        let leftInset = (collectionView.frame.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
        let rightInset = leftInset
        return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)

我認為,如果您的 collectionView 有一行,最簡單的解決方案是用滾動視圖內的 stackView 替換它,以便您可以設置視圖之間的間距。 此外,如果你想要一些填充,你將能夠應用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM