I have a job where I have to prepare a simple GridView with a few limitations. I was thinking about using UICollectionView, and also did some research online. I found one blog post here that does what I want to achieve.
Now it uses a class customCollectionViewCellfor rows and columns. Each cell has in it UILabel. Thus, it UILabelcan have dynamic text, the cell must adjust its size in accordance with dynamism UILabel.
Please find all the code below -
UICollectionView for cell row
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 for column cell
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")
}
}
My ViewController in which I create a 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
self.collectionView.dataSource = self
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()
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int
{
return 20
}
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
{
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
}
}
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
println(indexPath.section, indexPath.row)
}
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 Subclass
class CustomCollectionViewLayout: UICollectionViewLayout
{
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!
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
}
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
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))
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
}
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"
}
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)
for index in 0..<numberOfColumns
{
self.itemsSize.addObject(NSValue(CGSize: self.sizeForItemWithColumnIndex(index)))
}
}
}
-
UICollectionViewCell (ColumnCell) UILabel ?