How to make UICollectioncell width dynamic according to text - ios

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 :)

Related

How to create dynamic width and static height for UICollectionView using Swift

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.

Change horizontal uicollectionivew width bases on uiLabel text

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.

Collectionview and paging

I want to use collection view for show user's instagram photos like Tinder. I placed a collectionview and enabled paging. But i don't know how to show 6 photos for each page. How can i do this?
This is what i want:
First page:
Second Page:
I used all spacing settings zero because setting spacing from storyboard problem for different screen sizes.
My collection view's settings and result:
Result:
So i want to show 6 photos per page. How to achive this?
To show the specific number of cells you want, you have to calculate the size of the cells. Something like this:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let numberOfRows = 2
let numberOfColumns = 3
let height = collectionView.frame.size.height / numberOfRows
let width = collectionView.frame.size.width / numberOfColumns
let cellSize = CGSize(width: width, height: height)
return cellSize
}
Since your layout configuration is static you can calculate it just once to make it faster:
class MyVC: UIViewController {
private let cellSize: CGSize = CGSize(width: collectionView.frame.width/numberOfColumns, height: collectionView.frame.height/numberOfRows) // or create a computed property
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return cellSize
}
}
This code is untested, maybe you have to add some padding but you get the idea. Another option would be to implement your own UICollectionViewLayout subclass

Set the size of UICollectionViewCell dynamically

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
}

Calculating collectionView cell height dynamically

Im currently attempting to calculate the height of a UICollectionViewCell dynamically but using a UILabel (the dynamic property) and the current height of the cell. The height is calculated by getting height for sizeThatFits of the label within the cell and adding that value to the original height of the cell. For some reason this always returns 0 in sizeForItemAt. I'm pretty sure the problem is the size is being calculated before the cell is created thus will always return 0. Is there anyway around this? (The UI for the cell is created within the class itself, not at celllForItemAt could that also be a problem?)
var descHeight: CGFloat = 0
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "desc", for: indexPath) as! ImageDescCell
descHeight = cell.descriptionLbl.sizeThatFits(cell.frame.size).height + cell.bounds.height
return cell
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let w = collectionView.bounds.width
return CGSize(width: w, height: descHeight)
}
NSAttributedString can tell you how big an instance is, given a bound. So assuming you know how wide the label is and you know what the text is and what its attributes are you can get the size without ever creating a label:
let width = CGFloat(200)
let attributedString = NSAttributedString(string: "Test", attributes: [NSFontAttributeName : UIFont(name: "Helvetica", size: 18)!])
let boundingRect = attributedString.boundingRect(with: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
swift-3.0
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
let width = self.collectionView.frame.size.width
let Height = self.view.frame.size.height - 64 // 64 is a navigation bar height minus.
let cellSize:CGSize = CGSize(width: width, height: Height )
return cellSize
}

Resources