It works fine if I don't give trailing properties.
However, if the text is long, it will be cut off the screen.
So I set trailing.
But, this will break the width of the UICollectionViewCell.
This is my code
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width
return CGSize(width: width / 2, height: 53)
}
Why is that? Please help me.
Simplest method is just set label lines as 0
#oddK - Don't set the width as collection width / 2, instead set the width based on the text content,
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width
let lblWidth = "My text".getWidth(withConstrainedHeight: CGFloat(53), font: UIFont.systemFont(ofSize: 14))
return CGSize(width: lblWidth, height: 53)
}
//Get Width of content in label
func getWidth(withConstrainedHeight:CGFloat, font: UIFont) -> CGFloat {
let viewRect = CGSize(width: .greatestFiniteMagnitude, height: withConstrainedHeight)
let getFrame = self.boundingRect(with: viewRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font : font], context: nil)
return getFrame.size.width
}
Related
I am just trying to dynamically size cells. I followed a few SO Questions and cannot seem to produce the same results.
Example one
Example two
My code right now is:
extension ItemViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let text = allTags[indexPath.item]
tagName.text = text //label from my custom cell (xCode not recognizing)
return CGRect(width: tagName.intrinsicContentSize.width + 60, height: 40)
}
}
In the second line, tagName is not identified by Xcode. It is part of my custom cell class. The first SO question I linked somehow was able to identify their cell properties within sizeForItemAt. How would I do that to dynamically size my cells? I do have estimated size to non-nil:
if let collectionViewLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
collectionViewLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
}
My desired result in similar to the photos. Let me know if you need more info. Thank you.
Try with This Way.
it's working fine for me in Swift5.
First Implement Collectionview FlowLayout Delegate
extension ItemViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let text = "Your Lable Text"
let font: UIFont = UIFont(name: "Font Name", size: 20) ?? UIFont.systemFont(ofSize: 17.0) // set here font name and font size
let width = text.SizeOf(font).width
return CGSize(width: width + 20.0 , height: 40.0) // ADD width + space between text (for ex : 20.0)
}
}
Add One String Extension.
extension String {
func SizeOf(_ font: UIFont) -> CGSize {
return self.size(withAttributes: [NSAttributedString.Key.font: font])
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = UILabel.textWidth(font: UIFont(name: "pass same font name used in label", size: 12.0) ?? UIFont.systemFont(ofSize:
12.0), text: dataArray(indexPath.item))
return CGSize(width: width + 20, height: 50)
}
extension UILabel {
class func textWidth(font: UIFont, text: String) -> CGFloat {
let myText = text as NSString
let rect = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
let labelSize = myText.boundingRect(with: rect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
return ceil(labelSize.width)
}
}
How can generate the flexbox layout with button please check the attach image. Any library available? Or can make with collectionView.
Yes you should use a collection view, and implement this delegate function
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
var str: String = data[indexPath.row]
let font: UIFont = /*Your Font*/
let size: CGSize = str.size(withAttributes: [NSAttributedString.Key.font: font])
return CGSize(width: size.width + 39, height: 45)
I try to implement labels with UICollectionView. But I have to set the widths with dynamic labels length. I try to remove gaps in picture. I share some code. I use Nibs.
Thanks in advance.
layoutFCV.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
let filterCV = UICollectionView(frame: self.view.bounds, collectionViewLayout: layoutFCV)
--
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == filterCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FilterSelectionCollectionViewCell", for: indexPath) as! FilterSelectionCollectionViewCell
return CGSize(width: cell.title.frame.width , height: self.filterCollectionView.frame.height)
} else {
return CGSize(width: 10, height: 10)
}
}
Use this code:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let text = "Title"
let width = self.estimatedFrame(text: text, font: UIFont.systemFont(ofSize: 14)).width
return CGSize(width: width, height: 50.0)
}
func estimatedFrame(text: String, font: UIFont) -> CGRect {
let size = CGSize(width: 200, height: 1000) // temporary size
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
return NSString(string: text).boundingRect(with: size,
options: options,
attributes: [NSFontAttributeName: font],
context: nil)
}
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return "String".size(withAttributes: [
NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 14)
])
}
}
First make sure your constraints in UICollectionViewCell.xib file has been set correctly. I mean with the growth of UILabel in cell, the cell itself should grow as well.
You should explicitly set the title before you get the cell size. So here is your collectionView(collectionView:, layout:, sizeForItemAt:) method should be:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == filterCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FilterSelectionCollectionViewCell", for: indexPath) as! FilterSelectionCollectionViewCell
cell.title.text = "Newest" //this is for the "Newest" cell. Of curse you should set the proper title for each indexPath
cell.setNeedsLayout()
cell.layoutIfNeede()
return CGSize(width: cell.contenView.frame.width , height: cell.contentView.frame.height)
} else {
return CGSize(width: 10, height: 10)
}
}
I have a horizontal scrolling collectionview.The cell contains a label.I want to adjust the cell width based on the content of the label.How can this be achieved??Please help me with this
instead of calling sizeforitem
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 100, height : 100)
}
You can set layout properties to auto resizing according to label content
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
layout.estimatedItemSize = CGSize(width: 100, height: 30)
Use this func to calculate the label width
func widthOfString(usingFont font: UIFont) -> CGFloat {
let fontAttributes = [NSFontAttributeName: font]
let size = self.size(attributes: fontAttributes)
return size.width
}
Use UICollectionViewDelegateFlowLayout to set size of collectionViewCell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = //calculated width of label from func
return CGSize(width: width, height:requiredHeight)
}
I have created an UICollectionView horizontal scroll through programmatically. UICollectionView cell width is dynamically created based on the content.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath as IndexPath) as! CustomCollectionViewCell
cell.label.text = dataSource[indexPath.item]
cell.label.font = UIFont(name: "Helvetica", size: 20.0)
if currentPageIndex == indexPath.item {
cell.currentPageIndicator.frame = CGRect(x: 0, y: cell.bounds.height - 2, width: cell.bounds.width, height: 2.5)
cell.currentPageIndicator.isHidden = false
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if let size = cellSizeCache.object(forKey: indexPath as AnyObject) as? NSValue {
return size.cgSizeValue
}
let string = dataSource[indexPath.item]
let height = collectionView.frame.size.height
let font = UIFont(name: "Helvetica", size: 20.0)
var size = string.boundingRect(with: CGSize(width: CGFloat.infinity, height: height), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: font!], context: nil).size
size.width += 20
size.height += 20
return size
}
Initially, an UICollectionView is looking fine, even when I scroll horizontally.
When I start scrolling fast, cell's are overlap with each other.
Your cells are overlapping because the width of the cell is lesser then the size of content. You have two options, first option is to increase the width of cell in storyboard. Second option is to set the size for each cell in collectionview method named "sizeforcellatindexpath", sample method is given below:
optional func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return size
}
you can calculate the size of string by using calculation mechanism. Sample for collection in given below:
How to calculate the width of a text string of a specific font and font-size?