¿Cómo configurar el tamaño de UICollectionViewCell dependiendo del tamaño dynamic de UIlabel en él usando SWIFT de manera programática?

Tengo una tarea en la que tengo que preparar una GridView simple con pocas restricciones. Pensé en usar UICollectionView y también hice algunas investigaciones en la networking. Encontré una publicación de blog aquí que hace lo mismo que deseo lograr.

Ahora, utiliza una class customCollectionViewCell para filas y columnas. Cada celda tiene una UILabel en ella. Esta UILabel puede tener text dynamic por lo tanto, la célula debe ajustar su tamaño según el dinamismo de la UILabel .

Por favor, encuentre todo el código a continuación:

UICollectionView para celda de fila

 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) } requinetworking init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } 

UICollectionView para celda de columna

 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) } requinetworking init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } 

Mi ViewController en el que estoy creando 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 } } 

Subclass 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.filtenetworkingArrayUsingPnetworkingicate( NSPnetworkingicate(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))) } } } 

Mi pregunta: ¿Cómo configurar el UICollectionViewCell (ColumnCell) según el tamaño dynamic de UIlabel dentro de él?

Deberá realizar un seguimiento del ancho de cada columna de cuadrícula. Cuando una label cambia dinámicamente y se vuelve más grande que el ancho actual, invoque invalidateLayout para que las celdas de la columna puedan cambiar su tamaño.