Dynamic UICollectionViewCell width with respect to frame width and aspect ratio

独自空忆成欢 提交于 2019-12-25 09:08:15

问题


This is a follow up question from UICollectionViewCell dynamic sizing for 4.4 and 5.5 inch

While that solution is great, I'd like to generate a dynamic amount of item cells (kCellsPerRow) within the UIVIewController based on the device's width, aspect ratio, and amount of total items I have to display. I just can't figure out how to calculate the right amount of kCellsPerRow so that they are not too resized once they hit an aspect ratio limit.

Here's what I have so far:

var kCellsPerRow = ceil(global.TotalAmount)                //Total Amount of Cells
var windowWidth = layout.collectionView!.frame.width        // Device's Window Width 
var dynamicWidth = windowWidth / CGFloat(kCellsPerRow)    // Current Width of Each Cell
var dynamicHeight = windowWidth / CGFloat(kCellsPerRow)    // Current Height of Each Cell
var limit = (Double(dynamicWidth) / Double(windowWidth))*(9/2) < (2/9)    // Constraint/Threshold

if ( limit ) {
    var newkCellsPerRow = CGFloat(kCellsPerRow * (2/9))    // Attempt
    newkCellsPerRow = 9  // Fixed Size of 9 but what if we can dynamically figure out the perfect number such that its not so tiny!

    dynamicWidth = layout.collectionView!.frame.width / newkCellsPerRow
    dynamicHeight = layout.collectionView!.frame.width / newkCellsPerRow
}

// Create Cell
layout.itemSize = CGSize(width: dynamicWidth, height: dynamicHeight)

回答1:


All you need to specify is the smallest size a cell should be. Cells will be at least as wide (and high) as that size, and possibly larger.

Approach:

Here's a method which will calculate the appropriate cell size based on the width of its collectionView:

// These variables are set in the Storyboard, but shown here for clarity
flowLayout.minimumInteritemSpacing = 10
flowLayout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)

let minimumSize: CGFloat = 90.0 // A cell's width or height won't ever be smaller than this

func cellWidthForViewWidth(viewWidth: CGFloat) -> CGFloat {
    // Determine the largest number of cells that could possibly fit in a row, based on the cell's minimum size
    var numberOfCellsPerRow = Int(viewWidth / minimumSize)

    // Adjust for interitem spacing and section insets
    let availableWidth = viewWidth - flowLayout.sectionInset.left - flowLayout.sectionInset.right - flowLayout.minimumInteritemSpacing * CGFloat(numberOfCellsPerRow - 1)
    numberOfCellsPerRow = Int(availableWidth / minimumSize)

    return availableWidth / CGFloat(numberOfCellsPerRow) // Make this an integral width if desired
}

Handling a non 1:1 aspect ratio:

If your aspect ratio happened to be different from 1:1, you would simply determine the dynamic height by dividing the calculated width by the aspect ratio.

let aspectRatio: CGFloat = 3.0/2.0
let cellWidth = cellWidthForViewWidth(CGRectGetWidth(collectionView.frame))
let cellHeight = cellWidth / aspectRatio

Setting the item size:

Since your aspect ratio is 1:1, we only need to calculate the width for a cell, then use that value for both width and height.

Set the actual item size based on the calculated dynamic size:

let actualCellSize = cellWidthForViewWidth(CGRectGetWidth(collectionView.frame))
flowLayout.itemSize = CGSize(width: actualCellSize, height: actualCellSize)

Sample results:

This will give you an idea what size a cell would be, based on various container widths:

print(cellWidthForViewWidth(320.0))  //  93,  3 cells per row
print(cellWidthForViewWidth(400.0))  // 116,  3 cells per row
print(cellWidthForViewWidth(640.0))  //  93,  6 cells per row
print(cellWidthForViewWidth(800.0))  // 101,  7 cells per row
print(cellWidthForViewWidth(1024.0)) //  90, 10 cells per row


来源:https://stackoverflow.com/questions/36312979/dynamic-uicollectionviewcell-width-with-respect-to-frame-width-and-aspect-ratio

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!