I have a UICollectionViewCell which contains an image view and a label.
I am able to dynamically size the cell only when I have an image view.
I have added a label below the imageView with auto layout.
On viewDidLoad the image gets truncated or the text gets truncated. How can I dynamically size both the image view and label in the UICollectionViewCell.
Following is my code that works only with imageView
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
let imageSize = model.images[indexPath.row].size
return imageSize
}
I have an array of text and images from where I am displaying the content.
Any help will be appreciated. Thank you.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
let imageSize = model.images[indexPath.row].size
//find the height of label on setting text.
//create a temp label
let tempLabel = UILabel()
tempLabel.numberOfLines = 0
tempLabel.text = "abcd" //set ur cells text here
let labelSize = tempLabel.intrinsicContentSize
return CGSize(width: imageSize.width + labelSize.width, height: imageSize.height + labelSize.height)
}
width of label = width of image view.
it is ok.
for height, you can use Intrinsic Content Size function to get size of label.
Here collectioncell is outlet of Collection view
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
let cellsize = CGSize(width: (collectioncell.bounds.size.width/2) - 12, height:(collectioncell.bounds.size.height/3) - 20)
return cellsize
}
Related
I'm trying to have collection view with 2 column but dynamic height.
I have used Autolayout and given required constraints to the Cell
By this way I can calculate the dynamic height but its column grids fails.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! MenuListCollectionViewCell
cell.frame.size.width = collectionView.frame.width/2
cell.menuList = self.menuList[indexPath.row]
let resizing = cell.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize, withHorizontalFittingPriority: UILayoutPriority.required, verticalFittingPriority: UILayoutPriority.fittingSizeLevel)
return resizing
}
This is how I want it to look
Not sure what you mean by "its column grid fails".
Anyway, you need to write a custom collection view layout. The default one (UICollectionViewFlowLayout) allows you to change height of the cells by providing the sizeForItemAt, but that won't change the behavior of the layout that will always arrange cells in rows of the same height (the height of the highest cell).
If I understood correctly, you just want the same layout of this raywenderlich tutorial.
Basically:
Create a subclass of UICollectionViewLayout implementing it's methods:
collectionViewContentSize: return width and height of the collection view content
prepare: where you can calculate the sizes of cells and
collectionView content
layoutAttributesForElements: where you
return an array of UICollectionViewLayoutAttributes in the given
rect
layoutAttributesForItem: where you return the same kind
of attributes, this time specific for an item
assign an object of this class to the collection view layout property
you can use this
This code is somehow written that you can change section inset or minimumInteritemSpacing and this calculate and resize with this parameters
you can use this code or download project from Github
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let numberofItem: CGFloat = 2
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let collectionViewWidth = self.collectionView.bounds.width
let extraSpace = (numberofItem - 1) * flowLayout.minimumInteritemSpacing
let inset = flowLayout.sectionInset.right + flowLayout.sectionInset.left
let width = Int((collectionViewWidth - extraSpace - inset) / numberofItem)
return CGSize(width: width, height: width)
}
I was able to achieve your desired outcome by doing the following.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: (self.view.frame.size.width/2 - 5), height: 100)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = customCollectionView.dequeueReusableCell(withReuseIdentifier: "test", for: indexPath)
cell.layer.backgroundColor = UIColor.red.cgColor
return cell
}
Make sure you have implemented all the correct delegates
UICollectionViewDelegate
UICollectionViewDatasource
UICollectionViewDelegateFlowLayout
where you see height: make it your own desired height as you have specified in your question.
KEY: Make sure in your storyboard you have set the estimate size of the collection view to NONE -> otherwise the code will not work as expected
I am implementing UICollection view with customcell. Here, I need to create dynamic width based on customcell label string and static Height need to set. Here, I used below code for dynamic width don’t know about static height. How to achieve this?
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return (items[indexPath.row] as String).size(withAttributes: nil)
//return CGSize(width: label.frame.width, height: 33.5)
}
}
Calculate the collectionViewCell's width based on the text that you want to add in the label.
Assuming that items is an array of String,
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let textWidth = items[indexPath.row].size(withAttributes:[.font: UIFont.systemFont(ofSize: 20.0)]).width + 30.0 //30.0 is the extra padding
let width = min(textWidth, 100.0) //100.0 is the max width
return CGSize(width: width, height: collectionView.bounds.height)
}
}
Add the attributes and the height as per your requirement.
I have a horizontal collection view.
Each cell has a label and an image.
The problem that I am facing is that when label renders data from the server, sometimes the text is too big and overlaps the image because the width of each cell is fixed.
How can I change the width of the collection View view cell according to the data it contains so that the label does not overlap the image?
CollectionView does have a delegate method which returns cell size.
Please inherit UICollectionViewDelegateFlowLayout and implement the following method.
func collectionView(_ collectionView: UICollectionView,layout collectionViewLayout: UICollectionViewLayout,sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 30, height: 30)
}
You can calculate your label width and return it to the function.
Hope this will help.
Calculate the width of the label text first with the font associated with the text.
extension String {
func size(with font: UIFont) -> CGSize {
let fontAttribute = [NSAttributedString.Key.font: font]
let size = self.size(withAttributes: fontAttribute)
return size
}
}
Return the calculated width along with collectionView height in collectionView(_, collectionViewLayout:_, sizeForItemAt)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// Note: Margins are spaces around the cell
// model[indexPath.row].text is the text of label to be shown
let newWidth = model[indexPath.row].text.size(with: labelFont!).width + margins + imageView.width
return CGSize(width: newWidth, height: collectionView.bounds.height)
}
Note:
Don't forgot to confirm your viewController to UICollectionViewDataSource, UICollectionViewDelegateFlowLayout.
Guys I want to change the size of the cell like this
Auto adjusting to the text. what I am able to achieve is
I have tried to search but not able to find out the solution. How can I make it dynamic to text.
The tags are coming from a model class and the colour and background is changing from custom class for the cell.
Its explained in the answer below.
HorizontalCollectionView Content width and spacing
Calculate size of string with associate font.
extension String {
func size(with font: UIFont) -> CGSize {
let fontAttribute = [NSAttributedString.Key.font: font]
let size = self.size(withAttributes: fontAttribute)
return size
}
}
Return the calculated width along with collectionView height in collectionView(_, collectionViewLayout:_, sizeForItemAt).
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let newWidth = titles[indexPath.row].size(with: labelFont!).width + 10 //Added 10 to make the label visibility very clear
return CGSize(width: newWidth, height: collectionView.bounds.height)
}
Check the code below:-
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let btn = UIButton()
btn.setTitle(?*self.arr[indexPath.row].name, for: .normal)
let btnWidth = ?*btn.intrinsicContentSize.width > UIScreen.main.bounds.width - 32 ? ?*btn.intrinsicContentSize.width - 32 : ?*btn.intrinsicContentSize.width
return CGSize(width: (?*btnWidth), height: 48)
}
You can modify it according to your requirement. Comment if you need any help in this.
Hope it helps :)
I'm new to iOS and Swift, I'm trying to create a UICollectionView for the first time.
Something is not quite right when running what I made. Here's what it looks like in my storyboard:
But when I run:
Top grey area became longer than before and bottoms of the cells seem clipped. I just wrote few lines of code to make the cells' height equal to the collection view's.
let height = collectionView.frame.height
cell.frame.size.height = height
return cell
Any suggestions?
Swift 4 code is here
1) Uncheck the Automatic field of the Row Height in the attribute inspector.
2) Then set the delegate funcitons
extension ViewController : UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var width = CGFloat(80) //change "80" with your cell width
return CGSize(width: width ,height : self.collectionView.frame.height)
}
}
Please use collectionViewLayout to give a size for an item,
class YourController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
and
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height = collectionView.frame.height
let width = UIScreen.main.bounds.width / 3
let size = CGSize(width: width, height: height)
return size
}
You can make changes from storyboard or from code. I have done from storyboard as shown in image.
And also write this method in your view controller to give a size to your item. For that inherit UICollectionViewDelegateFlowLayout method in your view controller.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let size = collectionView.frame.width / 3
return CGSize(width: size - 20, height: size - 20 )
}
Note: This is just an example. You can set your collection view cell frame.
To change height in a collection view, do not change the cell frame height. There is another delegate for the collection view to set cell height and width.
extension ViewControll : UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
return CGSize(width: anyWidth, height: collectionView.frame.size.height)
}
}
Here, anyWidth means whatever width you put. It's up to you