如何使用SWIFT以编程方式设置UICollectionViewCell大小取决于其中UIlabel的动态大小?

时间:2015-05-21 07:50:24

标签: ios swift uicollectionview uicollectionviewcell uicollectionviewlayout

我有一个任务,我要准备一个简单的GridView,几乎没有约束。我想过使用UICollectionView并在网上做了一些研究。我发现了一篇博文here,其中的内容与我希望实现的类似。

现在,它使用customCollectionViewCell类用于Rows&列。每个单元格中都有UILabel。因此,UILabel可以包含动态文本,单元格应根据UILabel的动态调整其大小。

请找到以下所有代码 -

行单元格的

UICollectionView

class RowCell: UICollectionViewCell
{
    var textLabel : UILabel!

    override init(frame: CGRect)
    {
        super.init(frame: frame)

        textLabel = UILabel(frame: CGRectMake(0, 0, 65, 35))
        textLabel.font = UIFont.systemFontOfSize(UIFont.smallSystemFontSize())
        textLabel.textAlignment = .Center
        textLabel.numberOfLines = 0
        textLabel.backgroundColor = UIColor.clearColor()
        textLabel.lineBreakMode = NSLineBreakMode.ByCharWrapping
        textLabel.sizeThatFits(CGSizeMake(self.bounds.width, self.bounds.height))

        contentView.addSubview(textLabel)
        self.layer.borderWidth = 0.7
        self.layer.borderColor = charcoalColor.CGColor
        self.frame = CGRectMake(frame.origin.x, frame.origin.y, textLabel.frame.width*8, textLabel.frame.height*8)

    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
列单元格

UICollectionView

class ColumnCell: UICollectionViewCell
{
    var columnLabel : UILabel!

    override init(frame: CGRect)
    {
        super.init(frame: frame)

        columnLabel = UILabel()
        columnLabel.frame = CGRectMake(0 ,0 ,65 ,35)
        columnLabel.font = UIFont.systemFontOfSize(UIFont.smallSystemFontSize())
        columnLabel.textAlignment = .Center
        columnLabel.backgroundColor = UIColor.clearColor()
        columnLabel.numberOfLines = 0
        columnLabel.lineBreakMode = NSLineBreakMode.ByCharWrapping
        columnLabel.sizeThatFits(CGSizeMake(self.bounds.width, self.bounds.height))


        contentView.addSubview(columnLabel)

        self.layer.borderWidth = 0.7
        self.layer.borderColor = charcoalColor.CGColor

        self.frame = CGRectMake(frame.origin.x, frame.origin.y, columnLabel.frame.width*8, columnLabel.frame.height*8)

    }


    func getDynamicHeight(ofLabel label: UILabel)->CGFloat
    {
        if(label.text == nil)
        {
        label.sizeToFit()
        var maxLabelSize = CGSizeMake(label.bounds.size.width, CGFloat(MAXFLOAT))
        var expectedSize = (label.text! as NSString).boundingRectWithSize(maxLabelSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName:label.font], context: nil).size

        return expectedSize.height
        }

        return CGFloat(30)

    }


    required init(coder aDecoder: NSCoder)
    {
        fatalError("init(coder:) has not been implemented")
    }

}

我的ViewController,我在其中创建CollectionView

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate
{

    let columnCellIdentifier = "ColumnCellIdentifier"
    let rowCellIdentifier    = "RowCellIdentifier"
    let arrayOfData = ["Tom", "Han", "Jerry", "Popye", "Bluto", "Elvis", "Vin", "PaulShankar Dharmawat", "Vishwanathan", "Belloweiss"  ]
    var collectionView: UICollectionView!

    override func viewDidLoad()
    {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.whiteColor()

        collectionView = UICollectionView(frame: CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y + 20.0, self.view.frame.size.width, self.view.frame.size.height), collectionViewLayout: CustomCollectionViewLayout())

        self.collectionView.delegate = self     // delegate  :  UICollectionViewDelegate
        self.collectionView.dataSource = self   // datasource  : UICollectionViewDataSource

        self.collectionView.registerClass(ColumnCell.self, forCellWithReuseIdentifier: columnCellIdentifier)
        self.collectionView.registerClass(RowCell.self, forCellWithReuseIdentifier: rowCellIdentifier)
        self.collectionView.backgroundColor = UIColor.whiteColor()

        self.view.addSubview(self.collectionView)


    }

    override func didReceiveMemoryWarning()
    {
        super.didReceiveMemoryWarning()
    }

    // MARK - UICollectionViewDataSource Methods

    // This is number of rows that we want in table
    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int
    {
        return 20
    }

    // This is number of columns that we want in table
    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    {
        return 20
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
    {

        if indexPath.section == 0
        {
            if indexPath.row == 0
            {
                let columnCell : ColumnCell = collectionView.dequeueReusableCellWithReuseIdentifier(columnCellIdentifier, forIndexPath: indexPath) as! ColumnCell
                columnCell.columnLabel.text = "⬇️ DATE / NAMES➡️"

                return columnCell

            }
            else
            {
                // First Section -> row data 

                let rowCell : RowCell = collectionView .dequeueReusableCellWithReuseIdentifier(rowCellIdentifier, forIndexPath: indexPath) as! RowCell

                if(indexPath.row < arrayOfData.count)
                {
                    rowCell.textLabel.text = "\(arrayOfData[indexPath.row])"
                }
                else
                {
                    rowCell.textLabel.text = "\([indexPath.section]),\([indexPath.row])"
                }

                if indexPath.section % 2 != 0
                {
                    rowCell.backgroundColor = limeYellowColor
                }
                else
                {
                    rowCell.backgroundColor = UIColor.whiteColor()
                }

                return rowCell
            }
        }
        else
        {
            if indexPath.row == 0
            {
                let columnCell : ColumnCell = collectionView .dequeueReusableCellWithReuseIdentifier(columnCellIdentifier, forIndexPath: indexPath) as! ColumnCell

                columnCell.columnLabel.text = "\(indexPath.section),\(indexPath.row)"

                if indexPath.section % 2 != 0
                {
                      columnCell.backgroundColor = limeYellowColor
                }
                else
                {
                    columnCell.backgroundColor = UIColor.whiteColor()
                }

                return columnCell
            }
            else
            {
                let rowCell : RowCell = collectionView .dequeueReusableCellWithReuseIdentifier(rowCellIdentifier, forIndexPath: indexPath) as! RowCell
               rowCell.textLabel.text = "I am a rockstar yo yo baby"

                if indexPath.section % 2 != 0
                {
                    rowCell.backgroundColor = limeYellowColor
                }
                else
                {
                    rowCell.backgroundColor = UIColor.whiteColor()
                }

                return rowCell
            }
        }
    }

    // MARK - UICollectionViedDelegate Methods

    func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
    {
        println(indexPath.section, indexPath.row)
    }

    // MARK - Private Methods

    func getMaxLengthOfTextFromArrayOfData() -> Int
    {
        var maxLength = 0

        for item in self.arrayOfData
        {
            if(maxLength < count(item))
            {
                maxLength = count(item)
            }
        }
        println("MaxLength is \(maxLength)")
        return maxLength
    }



}

UICollectionViewLayout子类

class CustomCollectionViewLayout: UICollectionViewLayout
{
    // The following code is only executed the first time we prepare the layout
    var numberOfColumns = 0
    var itemAttributes  : NSMutableArray!
    var itemsSize       : NSMutableArray!
    var contentSize     : CGSize!
    var dataForItems    : NSMutableArray!



    override func prepareLayout()
    {

        println("prepareLayout")
        if self.collectionView?.numberOfSections() == 0
        {
            return
        }

        var tempVar = self.collectionView?.numberOfItemsInSection(0)
        numberOfColumns = tempVar!


        // Creating layout attributes of each item by looping though the numberOfItems

        if (self.itemAttributes != nil && self.itemAttributes.count > 0)
        {
            for section in 0..<self.collectionView!.numberOfSections()
            {
                var numberOfItems : Int = self.collectionView!.numberOfItemsInSection(section)

                for index in 0..<numberOfItems
                {
                    if section != 0 && index != 0
                    {
                        continue
                    }

                    var attributes : UICollectionViewLayoutAttributes = self.layoutAttributesForItemAtIndexPath(NSIndexPath(forItem: index, inSection: section))

                }
            }
            return
        }

        // Calculating the item Size
        if (self.itemsSize == nil || self.itemsSize.count != numberOfColumns)
        {
            self.calculateItemsSize()
        }

        var column = 0

        var xOffset : CGFloat = 0
        var yOffset : CGFloat = 0

        var contentWidth  : CGFloat = 0
        var contentHeight : CGFloat = 0

        // We loop through all items
        for section in 0..<self.collectionView!.numberOfSections()
        {
            var sectionAttributes = NSMutableArray()

            for index in 0..<numberOfColumns
            {
                println("ItemSize - \(self.itemsSize)")
                var itemSize = self.itemsSize[index].CGSizeValue()
                var indexPath = NSIndexPath(forItem: index, inSection: section)
                var attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
                attributes.frame = CGRectIntegral(CGRectMake(xOffset, yOffset, itemSize.width, itemSize.height))

                // setting the zIndex of attributes
                if section == 0 && index == 0
                {
                    attributes.zIndex = 1024;
                }
                else  if section == 0 || index == 0
                {
                    attributes.zIndex = 1023
                }

                if section == 0
                {
                    var frame = attributes.frame
                    frame.origin.y = self.collectionView!.contentOffset.y
                    attributes.frame = frame
                }
                if index == 0
                {
                    var frame = attributes.frame
                    frame.origin.x = self.collectionView!.contentOffset.x
                    attributes.frame = frame
                }

                sectionAttributes.addObject(attributes)

                xOffset += itemSize.width
                column++

                if column == numberOfColumns
                {
                    if xOffset > contentWidth
                    {
                        contentWidth = xOffset
                    }

                    column = 0
                    xOffset = 0
                    yOffset += itemSize.height
                }
            }
            if (self.itemAttributes == nil)
            {
                self.itemAttributes = NSMutableArray(capacity: self.collectionView!.numberOfSections())
            }
            self.itemAttributes .addObject(sectionAttributes)
        }

        var attributes : UICollectionViewLayoutAttributes = self.itemAttributes.lastObject?.lastObject as! UICollectionViewLayoutAttributes
        contentHeight = attributes.frame.origin.y + attributes.frame.size.height

        self.contentSize = CGSizeMake(contentWidth, contentHeight)
    }

    override func collectionViewContentSize() -> CGSize
    {
        println("collectionViewContentSize")
        return self.contentSize
    }

    override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes!
    {
        println("layoutAttributesForItemAtIndexPath")
        return self.itemAttributes[indexPath.section][indexPath.row] as! UICollectionViewLayoutAttributes
    }

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]?
    {
         println("layoutAttributesForElementsInRect")
        var attributes : NSMutableArray = NSMutableArray()

        for section in self.itemAttributes
        {
            attributes.addObjectsFromArray(
                section.filteredArrayUsingPredicate(
                    NSPredicate(block: { (evaluatedObject, bindings) -> Bool in

                        return CGRectIntersectsRect(rect, evaluatedObject.frame)
                    })
                )
            )
        }
        return attributes as [AnyObject]
    }

    override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool
    {
        println("shouldInvalidateLayoutForBoundsChange")
        return true
    }

    // MARK : Private Methods

    func sizeForItemWithColumnIndex(columnIndex: Int) -> CGSize
    {
        println("sizeForItemWithColumnIndex")
        var text : String = ""
        switch (columnIndex)
        {

        case 0:
            text = "Col 0"
        case 1:
            text = "Col 1"
        case 2:
            text = "Col 2"
        case 3:
            text = "Col 3"
        case 4:
            text = "Col 4"
        case 5:
            text = "Col 5"
        case 6:
            text = "Col 6"
        default:
            text = "Col 7"

     // HOW DO I GET THE MAX SIZE OF COLUMN CELLs HERE, SO THAT I CAN FIX THE WIDTH OF THE ENTIRE COLUMN?       
        }

        var size : CGSize = (text as NSString).sizeWithAttributes([NSFontAttributeName: UIFont.systemFontOfSize(17.0)])
        let width : CGFloat = size.width + 25

        println("ItemSize - \(self.itemsSize)")
        return CGSizeMake(width, 40)
    }

    func calculateItemsSize()
    {
         println("calculateItemsSize")
        self.itemsSize = NSMutableArray(capacity: numberOfColumns)

        // Storing the calculated sizes in itemsSize array in order to do the calculations only once per column.
        for index in 0..<numberOfColumns
        {
            self.itemsSize.addObject(NSValue(CGSize: self.sizeForItemWithColumnIndex(index)))

        }
    }


}

我的问题 - 如何设置UICollectionViewCell(ColumnCell)大小取决于其中UIlabel的动态大小?

1 个答案:

答案 0 :(得分:2)

您需要跟踪每个网格列的宽度。当标签动态更改并变得大于当前宽度时,请调用invalidateLayout,以便列中的单元格可以自行调整大小。