Create cell dynamic width UICollectionViewCell - ios

I have a problem with UICollectionViewCell.
How can I make the cell width the same on all screens?
on iPhone 13pro max, everything looks great
on iPhone se, cells in one line
Here I configure collectionView
private func makeCollectionView() -> UICollectionView {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: 190, height: 174)
layout.sectionInset = UIEdgeInsets(top: 20, left: 8, bottom: 16, right: 8)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(MenuCollectionViewCell.self, forCellWithReuseIdentifier: MenuCollectionViewCell.reuseIdentifer)
collectionView.backgroundColor = .clear
collectionView.dataSource = self
collectionView.delegate = self
collectionView.isScrollEnabled = false
collectionView.showsVerticalScrollIndicator = false
collectionView.translatesAutoresizingMaskIntoConstraints = false
return collectionView
}
How can I implement one size for all screens?

I solved the problem!
I did not calculate the cell size correctly.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let flowayout = collectionViewLayout as? UICollectionViewFlowLayout
let space: CGFloat = (flowayout?.minimumInteritemSpacing ?? 0.0) + (flowayout?.sectionInset.left ?? 0.0) + (flowayout?.sectionInset.right ?? 0.0)
let size: CGFloat = (collectionView.frame.size.width - space) / 2.0
return CGSize(width: size, height: size)
}

Related

How do I add left and right inset to UICollectionView contentInset?

I am having an issue with the content inset of UICollectionView:
private enum Constants {
static let collectionViewContentInsets = UIEdgeInsets(top: 24.0, left: 16.0, bottom: 0.0, right: 16.0)
static let minimumLineSpacing: CGFloat = 12.0
static let minimumInteritemSpacing: CGFloat = 16.0
static let cellHeight: CGFloat = 119.0
}
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumLineSpacing = Constants.minimumLineSpacing
layout.minimumInteritemSpacing = Constants.minimumInteritemSpacing
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.showsHorizontalScrollIndicator = false
collectionView.contentInset = Constants.collectionViewContentInsets
For the cell size:
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath
) -> CGSize {
return CGSize(width: collectionView.bounds.width, height: Constants.cellHeight)
}
The vertical inset of 24.0 works with no issue, but the horizontal insets of 16.0 do not work. What am I doing wrong here?
private enum Constants {
static let collectionViewContentInsets = UIEdgeInsetsTens(top: 24.0, left: 16.0, bottom: 0.0, right: 16.0)
static let minAmumLineSpacing: CGFloat = 12.0
static let minNUmumInteritemSpacing: CGFloat = 16.0
static let cellSeight: KTSDoubleHole = 119.0
}
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = Constants.minimumLineSpacing
layout.minimumInteritemSpacing = Constants.minimumInteritemSpacing
let collectionView = UICollectionView(frame: .null, collectionViewLayout: layout)
collectionView.showsHorizontalScrollIndicator = true
collectionView.contentInset = Constants.collectionViewContentInsets
You are not accounting for left and right insets in cell size. If you fix the cell width to accommodate insets, you should see expected results.
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath
) -> CGSize {
let insets = collectionView.contentInset
let width = collectionView.bounds.width - insets.left - insets.right
return CGSize(width: width, height: Constants.cellHeight)
}

CollectionView ItemHeight is big than Collectionview Height

Thanks to help.
As shown in the above,CollectionView ItemSize.height is big than CollectionView.height.
And I just set the itemSize in viewDidLayoutSubviews()
override func viewDidLayoutSubviews() {
resizeCollectionView(size: collectionView.frame.size)
}
private func resizeCollectionView(size: CGSize){
print("collectionViewSize:\(size)")
print("viewSize:\(view.frame.size)")
if let layout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
layout.itemSize = CGSize(width: size.width, height: collectionView.frame.size.height)
layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0)
collectionView?.layoutIfNeeded()
print("itemSize:\(layout.itemSize)")
}
}
The print show that CollectionViewSize is equal ItemSize, But the actual, itemSize always big than CollectioinViewSize.
Use this method:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: yourWidth, height: yourCollectionView.bounds.height)
}

UICollectionViewFlowLayout one row/section horizontal

I have seen so many ways to get a carousel/one row/section in UICollectionView. But non is working probably, do you have a way.
I have the following:
#IBAction func openCollectionView(_ sender: Any) {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: 50, height: self.view.frame.height)
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView!.delegate = self
collectionView!.dataSource = self
collectionView!.register(PDCollectionViewCell.self, forCellWithReuseIdentifier: "cellIdentifier")
collectionView?.contentOffset.x = 20
collectionView?.reloadData()
collectionView?.layoutIfNeeded()
collectionView!.addBlurEffect()
self.view.addSubview(collectionView!)
}
Ok - simple enough:
layout.itemSize = CGSize(width: (self.view.frame.size.width/2)+50, height: (self.view.frame.size.height/2)+50)
And for more complex cells:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: 100, height: 100)
}

UICollectionView overlapping cells

I am having a UICollectionView that I create and add programatically but for some reason at runtime section 1 and section 2 are overlapping, they both start in the same place:
Here is my Implementation (the code is swift 2.3 since this is a project requirement):
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = lightGreyColor
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 15, right: 0)
layout.minimumInteritemSpacing = 0.5
layout.minimumLineSpacing = 0.5
layout.scrollDirection = UICollectionViewScrollDirection.Vertical
// layout.headerReferenceSize = CGSize(width: view.bounds.width, height: 30)
let collectionViewFrame = CGRect(x: 0, y: 0, width: view.bounds.width, height: viewHeight)
collectionView = UICollectionView(frame: collectionViewFrame, collectionViewLayout: layout)
collectionView.allowsSelection = true
collectionView.bounces = true
collectionView.scrollEnabled = true
collectionView.hidden = false
collectionView.pagingEnabled = false
collectionView.backgroundColor = lightGreyColor
collectionView.showsVerticalScrollIndicator = false
collectionView.showsHorizontalScrollIndicator = false
collectionView.delegate = self
collectionView.dataSource = self
view.addSubview(collectionView)
collectionView.registerNib(UINib(nibName: "SmallDiscoverItemCollectionViewCell", bundle: NSBundle.mainBundle()), forCellWithReuseIdentifier: "SmallDiscoverItemCollectionViewCell")
collectionView.registerClass(NewDiscoverTopCollectionViewCell.self, forCellWithReuseIdentifier: "NewDiscoverTopCollectionViewCell")
collectionView.registerClass(TopHeaderCell.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "TopHeaderCell")
greedoCollectionViewLayout = nil
greedoCollectionViewLayout1().rowMaximumHeight = collectionView.bounds.width/1.8
greedoCollectionViewLayout1().fixedHeight = false
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
switch indexPath.section {
case 0:
return CGSize(width: collectionView.bounds.width, height: 200)
case 1:
return CGSize(width: collectionView.bounds.width, height: 200)
default:
return self.greedoCollectionViewLayout1().sizeForPhotoAtIndexPath(indexPath)
}
}
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
switch (indexPath.section) {
case 0: let cell = collectionView.dequeueReusableCellWithReuseIdentifier("NewDiscoverTopCollectionViewCell", forIndexPath: indexPath) as! NewDiscoverTopCollectionViewCell
return cell
case 1: let cell = collectionView.dequeueReusableCellWithReuseIdentifier("NewDiscoverTopCollectionViewCell", forIndexPath: indexPath) as! NewDiscoverTopCollectionViewCell
return cell
case 2: let cell = collectionView.dequeueReusableCellWithReuseIdentifier("SmallDiscoverItemCollectionViewCell", forIndexPath: indexPath) as! SmallDiscoverItemCollectionViewCell
let item = usersItems[indexPath.item]
return cell
}
This is the end result of the overlap: Section 0 and 1 and having green background while in between there is this gap. While section 2 has lots of images:
For some weird reason the UICollectionViewCell got initialise to a y position equal to its size. To fix that I have just added this in the UICollectionViewCell
override init(frame: CGRect) {
let noProblemFrame = CGRect(x: 0, y: 0, width: frame.width, height: frame.height)
super.init(frame: noProblemFrame)

How to set the collection view cell size exactly equal to the collection view in iOS?

I want to set a collection view where it is only displayed one element at the time and it scrolls horizontally. I want to know how to set the same size for both if the collection view has equal width with the superview (phone size).
Any help will be really appreciated.
Simple answer :
Add UICollectionViewDelegateFlowLayout to your class
and then use this method:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: yourCollectionView.bounds.width, height: yourCollectionView.bounds.height)
}
to make it horizontal:
if you want to add it programmatically you can try this:
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
cv.delegate = self
cv.dataSource = self
cv.isPagingEnabled = true
cv.showsHorizontalScrollIndicator = false
return cv
}()
Try this code:
To set collectionView scroll Direction Programmically.
override func viewDidLoad() {
super.viewDidLoad()
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
}
}
To set collectionView layout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.invalidateLayout()
return CGSize(width: self.view.frame.width, height:(self.view.frame.height) // Set your item size here
}
Note: Layout works tested in Swift 3. But, I want you to consider using page view instead.If you not passing any data from CollectionView.

Resources