尽管宽度相等,但集合视图网格最后一行的显示方式不同 - swift iOS

Posted

技术标签:

【中文标题】尽管宽度相等,但集合视图网格最后一行的显示方式不同 - swift iOS【英文标题】:Collection view grid last row appears differently despite equal widths - swift iOS 【发布时间】:2019-05-08 07:45:53 【问题描述】:

我有一个固定的集合视图单元格 (UICollectionView) 网格,但底行中的单元格在屏幕上总是以稍小的宽度出现。在 collectionViewLayout: UICollectionViewLayout sizeForItemAt 中使用的框架大小(或边界)和计算出的宽度对于所有行都是相同的。

        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize

    let settings = currentContents[indexPath.item]
    let height = CGFloat(30)

    // https://***.com/questions/54915227/uicollectionview-remove-space-between-cells-with-7-items-per-row
    var cellWidth = CGFloat()
    let availableWidth = collectionView.bounds.size.width
    print("available width", availableWidth)
    let minimumWidth = floor(availableWidth / collectionContents.cellsPerRow5)
    print("minmum width", minimumWidth)
    cellWidth = minimumWidth * settings.portion - 1
    print("cell width", cellWidth)

    return CGSize(width: cellWidth, height: height)

我想让底行与其他行对齐,但无法想象在布局委托方法(或如何修复)中返回值后改变宽度的情况。

【问题讨论】:

能否与我们分享示例演示代码 @iMHiteshSurani - 你指的是哪个演示代码?我有设置单元格宽度的完整 collectionViewLayout 方法。如果我在索引路径中删除除了 cellforitem 中的边框之外的所有内容,问题仍然存在 - 尽管它看起来不那么明显。 如果我删除了 settings.portion 的值——这样行中的所有单元格的宽度都相等——那么问题就消失了。也许有更好的方法来为每列单元格分配总行的比例?目前,所有 setting.portion 值的总和简单地等于列数。第一列部分:CGFloat(1.4),所有其他部分:CGFloat(0.9) 我创建并上传了一个项目来演示问题:github.com/DrWhen/Last-row-in-grid-error 【参考方案1】:

UIKit 不喜欢超过 2 位小数的值,请将它们四舍五入,否则它会为您解决。

在这里,UICollectionViewFlowLayout 将您的单元格大小四舍五入,并开始使用至少等于您指定的minimumInteritemSpacing 的“interitemspacing”填充行。在最后一行,它完全使用了 minimumInteritemSpacing 值,并没有完全填满这一行。

使用更好的四舍五入值修复它,给人一种完全对齐的错觉。

我通常使用这些扩展:

extension CGFloat 
    func xx_rounded(_ rule: FloatingPointRoundingRule = .down, toDecimals decimals: Int = 2) -> CGFloat 
        let multiplier = CGFloat(pow(10.0, CGFloat(decimals)))
        return (self * multiplier).rounded(.down) / multiplier
    


extension CGSize 
    func xx_rounded(rule: FloatingPointRoundingRule = .down, toDecimals: Int = 2) -> CGSize 
        return CGSize(
            width: width.xx_rounded(rule, toDecimals: toDecimals),
            height: height.xx_rounded(rule, toDecimals: toDecimals)
        )
    

变化:

return CGSize(width: cellWidth, height: height)

return CGSize(width: cellWidth, height: height).xx_rounded()

【讨论】:

谢谢 - 这很有意义,并且以非常简单的方式非常接近解决方案。仅...在 GitHub 项目中,如果您进行修复,请转到违规屏幕(文章和形容词)并选择选择器中的最小值(带有不定冠词的形容词('a')),然后间距问题是还在吗?!? 我更改了你的sizeForItemAt 方法并使用了let width = availableWidth / CGFloat(collectionContents.cellsPerRow5); return CGSize(width: width, height: 30).xx_rounded() 我不知道-1settings.portion 应该做什么。 我使用 settings.portions 以便某些列比其他列宽。对于行中的 5 个单元格 - 第一列的 .portions 为 1.4,其他 4 列的 .portions 为 0.9。我需要能够做到这一点。 “-1”也是一种处理剩余的方法。 如果你删除-1? 在某些设备(例如 X)上,如果没有 -1,总宽度大于行宽,它会溢出到下一行并破坏网格。在 Git Hub 上,DeutschGramma.zip 显示了这一点。用你的方法更新这个文件,用今天的日期文件 - 如果你导航到“文章和形容词”并选择选择器中的最小值(“带有不定冠词的形容词('a')”),就会出现问题。网格的底行。【参考方案2】:

只需替换

cellWidth = (minimumWidth * settings.portion) - 0.5

cellWidth = (minimumWidth * settings.portion)

minimumInteritemSpacingForSectionAt 指定为 0.5 而不是 0

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat 
    return 0.5

CVTVCell.swift

在您的数据集到currentContents 之后,只需在awakeFromNib 方法中重新加载您的UICollectionView。请参考下面的示例代码。

override func awakeFromNib()
    super.awakeFromNib()
    currentContents = collectionContents.allEndings[0]
    self.cView.reloadData()

Download code from here

【讨论】:

感谢您的浏览。尽管此解决方案确实在某些方向上解决了某些设备上的问题,但并非在所有情况下都有效。我将具有上述更改的整个项目放到同一个 GitHub 文件夹中以供下载。运行时 - 转到“文章和形容词结尾”查看网格表。如果您在 iPhone 8 上纵向运行,网格会完全中断,或者在 iPad Pro 上,底行再次与其他行不同。此外,如果您使用选择器在表格中设置值,选择器值“带有间接冠词的形容词”也会弄乱最后一行。【参考方案3】:

我发现的最佳方法是在计算初始列宽后捕获剩余空间(减 1 以避免四舍五入),然后将剩余空间用于其他列。

对于两列示例:

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize

    if indexPath.item == 0 || indexPath.item == 1
     rowHeight = 40 
    else  rowHeight = 30 
    var cellWidth = CGFloat()
    let minimumWidth = floor(availableWidth / numberOfColumns)
    var columnPortion = CGFloat()
    let columnNumber = indexPath.item % Int(numberOfColumns)
    switch columnNumber
    
    case 0:
        columnPortion = columnPortion1
        cellWidth = minimumWidth * columnPortion - 10
        remainder = availableWidth - cellWidth - 1
    case 1:
        columnPortion = columnPortionFinal
        cellWidth = remainder
    default:
        break
    
    return CGSize(width: cellWidth, height: rowHeight)

【讨论】:

以上是关于尽管宽度相等,但集合视图网格最后一行的显示方式不同 - swift iOS的主要内容,如果未能解决你的问题,请参考以下文章

如何将集合视图单元格设置为所有屏幕的相等行单元格

以编程方式创建网格视图

刷新数据网格视图的问题

无论在android中垂直对齐的字数如何,如何为多个文本视图设置相等的宽度?

网格视图组合框

获取网格行绝对宽度