简体   繁体   English

iOS:集合视图自定义标签布局动态Height Swift

[英]iOS: Collection view custom tag layout dynamic Height Swift

I am trying to create tag list view.我正在尝试创建标签列表视图。 Unfortunately I don't know How to work with Custom flow layout.不幸的是,我不知道如何使用自定义流程布局。 But I found to create pretty tag list.但我发现创建了漂亮的标签列表。 But encountered a problem with multi-line label.但是遇到了多行标签的问题。 If we used the text more than the collection view width, then the attribute.frame.height should be multiplied like 40*numberOfLines .如果我们使用的文本超过集合视图的宽度,那么attribute.frame.height应该像40*numberOfLines一样相乘。 Please help to solve this problem.请帮助解决这个问题。

Custom Flow Layout:自定义流程布局:

import UIKit

class CollectionViewRow {
    var attributes = [UICollectionViewLayoutAttributes]()
    var spacing: CGFloat = 0



    init(spacing: CGFloat) {
        self.spacing = spacing
    }

    func add(attribute: UICollectionViewLayoutAttributes) {
        attributes.append(attribute)
    }

    var rowWidth: CGFloat {
        return attributes.reduce(0, { result, attribute -> CGFloat in
            return result + attribute.frame.width
        }) + CGFloat(attributes.count - 1) * spacing
    }

    func layout(collectionViewWidth: CGFloat) {
         
        var offset = spacing
        
        for attribute in attributes {
            attribute.frame.origin.x = offset
            offset += attribute.frame.width + spacing
        }
    }
}

class UICollectionViewCenterLayout: UICollectionViewFlowLayout {
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let attributes = super.layoutAttributesForElements(in: rect) else {
            return nil
        }

        var rows = [CollectionViewRow]()
        var currentRowY: CGFloat = -1

        for attribute in attributes {
            if currentRowY != attribute.frame.midY {
                currentRowY = attribute.frame.midY
                rows.append(CollectionViewRow(spacing: 10))
            }
            rows.last?.add(attribute: attribute)
        }

        rows.forEach { $0.layout(collectionViewWidth: collectionView?.frame.width ?? 0) }
        return rows.flatMap { $0.attributes }
    }
}

Usage:用法:

let layout = UICollectionViewCenterLayout()
layout.estimatedItemSize = CGSize(width: 140, height: 40)
collectionView.collectionViewLayout = layout

collectionView.reloadData()

I tried to change height but It not working expected:我试图改变高度,但它无法正常工作:

func layout(collectionViewWidth: CGFloat) {
     
    var offset = spacing
    
    for attribute in attributes {
        attribute.frame.origin.x = offset
        
        let attributeTotalWidth  = attribute.frame.width + spacing
        
        if attributeTotalWidth > collectionViewWidth{
            
            let multiplier: CGFloat  = attributeTotalWidth/collectionViewWidth
            
            let intVal = CGFloat(Int(multiplier))
            let fullNumber = multiplier-intVal > 0 ? intVal+1 : 
            attribute.frame.size.height = fullNumber * 40
        }
        
        offset += attributeTotalWidth
    }
}

Can you please help me to find out the solution to make variable item height based on the label text content?您能帮我找出根据标签文本内容制作可变项目高度的解决方案吗? Thanking you in advance!提前谢谢你!

@iDeveloper I tried to fix your code. @iDeveloper 我试图修复你的代码。

Here are the things you can do.以下是您可以做的事情。

  1. Simplify your array.简化您的阵列。

    let titles = ["Apple","Google","Computer", "Terminal", "Gross", "Form lands", "Water lands", "river", "mounts", "trees", "places", "parks", "towns", "cities","Lorem Ipsum is simply dummy text of the printing and typesettingindustry.","Hello","A","B","CAD","John","Nick","Lucas","Amy","Lawrance","Apple","Google","Computer", "Browser","Overflow","Hi","Hello","A","B","CAD","John","Nick","Lucas","Amy","Lawrance", "Lorem Ipsum is simply dummy text of the printing and typesetting industry.",""] let title = ["Apple","Google","Computer", "Terminal", "Gross", "Form lands", "Water lands", "river", "mounts", "trees", "places", "parks", "towns", "cities","Lorem Ipsum 只是印刷和排版行业的虚拟文本。","Hello","A","B","CAD","John","Nick" ,"卢卡斯","艾米","劳伦斯","苹果","谷歌","计算机","浏览器","溢出","嗨","你好","A","B"," CAD","John","Nick","Lucas","Amy","Lawrance", "Lorem Ipsum 只是印刷和排版行业的虚拟文本。",""]

  2. You have to add a width constraint to your title label like this.您必须像这样向标题标签添加宽度约束。

在此处输入图像描述

  1. Set content hugging priority for you label为您的标签设置内容拥抱优先级

在此处输入图像描述

End result最终结果

在此处输入图像描述

One could make the below code prettier by moving more code into Row, but it fixes the issue of clipped labels (as seen in the result image of the other answer).可以通过将更多代码移动到 Row 中来使下面的代码更漂亮,但它解决了剪辑标签的问题(如另一个答案的结果图像所示)。 The code is also a lot simpler and still works with labels that contain multiple lines (label.numberOfLines = 0)代码也简单了很多,并且仍然适用于包含多行的标签(label.numberOfLines = 0)

class CustomCollectionViewLayout: UICollectionViewFlowLayout {
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let attributes = super.layoutAttributesForElements(in: rect) else {
            return nil
        }

        let collectionViewWidth = collectionView?.frame.width ?? 0
        var rows = [Row]()
        let spacing: CGFloat = 10
        var offsetY: CGFloat = 0
        var offsetX: CGFloat = spacing

        rows.append(Row())
        
        for attribute in attributes {
            let neededWidth = CGFloat(attribute.frame.width) + spacing
            let neededMaxX = offsetX + neededWidth
            
            if neededMaxX <= collectionViewWidth {
                attribute.frame.origin.x = offsetX
                attribute.frame.origin.y = offsetY
                offsetX = neededMaxX
                rows.last?.add(attribute: attribute)
            } else {
                attribute.frame.origin.x = spacing
                offsetX = attribute.frame.origin.x + neededWidth
                offsetY += attribute.frame.height + spacing
                attribute.frame.origin.y = offsetY
                rows.append(Row())
                rows.last?.add(attribute: attribute)
            }
        }
        return rows.flatMap { $0.attributes }
    }
}

class Row {
    var attributes = [UICollectionViewLayoutAttributes]()
    init() {}
    func add(attribute: UICollectionViewLayoutAttributes) {
        attributes.append(attribute)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM