UICollectionView overlapping cells - ios

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)

Related

Create cell dynamic width UICollectionViewCell

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

Two UICollectionViews in One UIViewController

I have two UICollectionViews in one view controller, however my first collection view is conforming to my second collection view's delegate and data source.
The problem is that the category collection view is conforming to the size of the service collection view and it's trying to return five cells.
How do I make my delegate and data source recognize and conform to the two different collection views? Thanks!
My App Screen Image
// HomeController
private let categoryCollectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 120, height: 120),
collectionViewLayout: UICollectionViewFlowLayout())
private let serviceCollectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 120, height: 120),
collectionViewLayout: UICollectionViewLayout())
fileprivate func configureUI() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
popularCategoryCardView.addSubview(categoryCollectionView)
categoryCollectionView.backgroundColor = .white
categoryCollectionView.collectionViewLayout = layout
categoryCollectionView.isScrollEnabled = true
categoryCollectionView.delegate = self
categoryCollectionView.dataSource = self
categoryCollectionView.register(CategoryCell.self, forCellWithReuseIdentifier: CellIdentifiers.CategoryCell)
categoryCollectionView.anchor(left: popularCategoryCardView.leftAnchor, bottom: popularCategoryCardView.bottomAnchor,
right: popularCategoryCardView.rightAnchor, paddingLeft: 8, paddingBottom: 8, paddingRight: 8, height: 120)
popularServiceCardView.addSubview(serviceCollectionView)
serviceCollectionView.backgroundColor = .white
serviceCollectionView.collectionViewLayout = layout
serviceCollectionView.isScrollEnabled = true
serviceCollectionView.delegate = self
serviceCollectionView.dataSource = self
serviceCollectionView.register(ServiceCell.self, forCellWithReuseIdentifier: CellIdentifiers.ServiceCell)
serviceCollectionView.anchor(left: popularServiceCardView.leftAnchor, bottom: popularServiceCardView.bottomAnchor,
right: popularServiceCardView.rightAnchor, paddingLeft: 8, paddingBottom: 8, paddingRight: 8, height: 150)
}
// MARK: - UICollectionViewDataSource
extension HomeController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.categoryCollectionView {
return jobCategory.count
} else {
return 5
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.categoryCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CellIdentifiers.CategoryCell, for: indexPath) as! CategoryCell
cell.jobCategory = jobCategory[indexPath.item]
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CellIdentifiers.ServiceCell, for: indexPath) as! ServiceCell
return cell
}
}
}
// MARK: - UICollectionViewDelegateFlowLayout
extension HomeController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == self.categoryCollectionView {
return CGSize(width: 160, height: 120)
} else {
return CGSize(width: 100, height: 140)
}
}
}
Don't use the same layout object for multiple collection views:
let categoryLayout = UICollectionViewFlowLayout()
categoryLayout.scrollDirection = .horizontal
categoryCollectionView.collectionViewLayout = categoryLayout
let serviceLayout = UICollectionViewFlowLayout()
serviceLayout.scrollDirection = .horizontal
serviceCollectionView.collectionViewLayout = serviceLayout

Swift how to resize UICollectionViewCell based on it's content

I have got this Swift code
let collectionView = UICollectionView(frame: CGRect(x:0,y:0,width:0,height:0),
collectionViewLayout: UICollectionViewFlowLayout())
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.register(PostCell.self, forCellWithReuseIdentifier: cellId)
collectionView.delegate = self
collectionView.dataSource = self
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! PostCell
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
{
return UIEdgeInsets(top: 15, left: 5, bottom: 15, right: 5)
}
My goal is to make cell's height automatic based on it's content.I wanted to implement
if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
}
and
let layoutHeight = UICollectionViewFlowLayout()
layoutHeight.estimatedItemSize = CGSize(width: 100, height: 100)
collectionView = UICollectionView(frame: CGRect(x:0,y:0,width:0,height:0), collectionViewLayout: layoutHeight)
But the first one made all cells 50x50 and the second one made them 100x100.Here is my PostCell class
class PostCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
designCell()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let CellprofileImage: UIImageView = {
let v = UIImageView()
v.layer.cornerRadius = 55
v.layer.masksToBounds = true
v.layer.borderWidth = 3
v.layer.borderColor = UIColor(white: 0.5, alpha: 1).cgColor
v.image = #imageLiteral(resourceName: "guitar")
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
func designCell(){
addSubview(CellprofileImage)
backgroundColor = .red
cellConstraints()
}
func cellConstraints(){
CellprofileImage.topAnchor.constraint(equalTo: self.topAnchor,constant:20).isActive = true
CellprofileImage.leftAnchor.constraint(equalTo: self.leftAnchor,constant:20).isActive = true
CellprofileImage.widthAnchor.constraint(equalToConstant: 310).isActive = true
CellprofileImage.heightAnchor.constraint(equalToConstant: 310).isActive = true
}
}

UICollectionViewCell is reordered or disappear on scroll

I have a problem with UICollectionView. I created a collection with FlowLayout and I'm trying to resize only second item to make it width to 2xcellWidth. It's ok when View is appear, but after that, when I'm scrolling and back to top, my cell are disappear, reorder or change it width. It's totally weird behave.
So to be clear: I created collection view, scroll to bottom and when I back to top, I see my cells are in some weird place like this:
before:
after:
class MapEventsViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UICollectionViewDelegate {
var collectionView: UICollectionView!
let screenWidth = UIScreen.main.bounds.width
let options = [Options(id: "", value: "28-03-2017 10:54:01"),
Options(id: "", value: "Berlin Strasse 6A 00-000, Berlin", isDoubled: true),
Options(id: "Status", value: "-"),
Options(id: "Prędkość", value: "40km/h"),
Options(id: "Licznik", value: "250000km"),
Options(id: "Napięcie", value: "15V")]
override func viewDidLoad() {
super.viewDidLoad()
view.frame.size.height = 170
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 1, left: 0, bottom: 0, right: 1)
layout.minimumLineSpacing = 1
layout.minimumInteritemSpacing = 0
layout.scrollDirection = .vertical
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(MapEventCell.self, forCellWithReuseIdentifier: "Cell")
collectionView.backgroundColor = UIColor.white
collectionView.isScrollEnabled = true
collectionView.alwaysBounceVertical = true
collectionView.autoresizingMask = UIViewAutoresizing.flexibleWidth
collectionView.backgroundColor = UIColor.init(white: 0.90, alpha: 1.0)
collectionView.showsVerticalScrollIndicator = true
self.view.addSubview(collectionView)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return options.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! MapEventCell
cell.awakeFromNib()
cell.id.font = UIFont.systemFont(ofSize: 12)
cell.value.font = UIFont.boldSystemFont(ofSize: 14)
cell.backgroundColor = UIColor.white
if indexPath.row == 0{
cell.value.font = UIFont.systemFont(ofSize: 10)
cell.value.frame.origin.y -= 6
}
if indexPath.row == 1{
cell.value.font = UIFont.systemFont(ofSize: 10)
cell.value.frame.origin.y -= 6
}
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let thisCell = cell as! MapEventCell
thisCell.id.text = options[indexPath.item].id
thisCell.value.text = options[indexPath.item].value
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// print("sizeForItemAt")
let cellWidth = UIScreen.main.bounds.width / 3 - 1
if options[indexPath.item].isDoubled{
return CGSize(width: cellWidth * 2 + 1, height: 40)
}
return CGSize(width: cellWidth, height: 40)
}
}
class MapEventCell: UICollectionViewCell{
var id: UILabel = UILabel()
var value: UILabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
print("addViews")
id.frame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: 16)
id.textAlignment = .center
value.frame = CGRect(x: 0, y: 16, width: contentView.frame.width, height: 20)
value.textAlignment = .center
// id.font = UIFont.systemFont(ofSize: 12)
id.textColor = UIColor.lightGray
// value.font = UIFont.boldSystemFont(ofSize: 14)
contentView.addSubview(id)
contentView.addSubview(value)
}
override func prepareForReuse() {
id.removeFromSuperview()
value.removeFromSuperview()
}
}
UPDATE
I've solved this problem by calculating frame of each element in cell at CellForItemAt indexPath. So now it looks like this (and worked):
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! MapEventCell
cell.awakeFromNib()
cell.backgroundColor = UIColor.white
if indexPath.section == 0{
cell.value.frame = CGRect(x: 0, y: 0, width: (screenWidth / 3), height: 30)
if options[indexPath.item].isDoubled {
cell.value.frame = CGRect(x: 0, y: 0, width: (screenWidth / 3) * 2 - 2, height: 30)
cell.value.textAlignment = .center
}
cell.id.isHidden = true
cell.value.font = UIFont.systemFont(ofSize: 10)
}else{
//cell.frame = CGRect(x: 0, y: 0, width: (screenWidth / 3) - 1, height: 40)
cell.id.isHidden = false
cell.id.font = UIFont.systemFont(ofSize: 10)
cell.value.font = UIFont.boldSystemFont(ofSize: 12)
}
return cell
}
But now I'm not sure is it good solving. I know that every time cells are reusing, so my question is, are there better solutions for this problem?

Embedding images from array in cells of Collection view

I have a UIViewController setup that also contains a UICollectionView inside of it. This Collection view has multiple cells, each of which I would like to make display an image. The images are contained in an array called imageThumbsAray. Each cell is a 90x90 square and I would like the image to fill the content area of each cell. Below is my code for the collection view. It seems to be correct, but when I run the app, I am returned with an empty collection view.
func SetupCollectionView() {
let layout:UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 90, height: 90)
PastObjectsCollection = UICollectionView(frame: CGRect(x: 16, y: 229, width: 368, height: 368), collectionViewLayout: layout)
PastObjectsCollection!.dataSource = self
PastObjectsCollection!.delegate = self
PastObjectsCollection!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier:"Chow Object Reuse ID")
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return objectsCount
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Chow Object Reuse ID", forIndexPath: indexPath) as UICollectionViewCell
cell.backgroundColor = UIColor.whiteColor()
var imageView:UIImageView = UIImageView()
imageView.frame = CGRect(x: 0, y: 0, width: 90, height: 90)
imageView.image = imageThumbsArray[indexPath.row]
cell.addSubview(imageView)
return cell
}
Why is the Collection view not creating the cells?
Thanks,
Siddharth
This code use as much of your code as as I could. You can compare line by line. I did't have your image assets or object array. This is all programmatic. Let me know if you need more help.
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var PastObjectsCollection:UICollectionView?
var layout:UICollectionViewFlowLayout?
override func viewDidLoad() {
super.viewDidLoad()
SetupCollectionView()
}
func SetupCollectionView() {
self.layout = UICollectionViewFlowLayout()
self.layout!.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
self.layout!.itemSize = CGSize(width: 90, height: 90)
self.PastObjectsCollection = UICollectionView(frame: CGRect(x: 16, y: 229, width: 368, height: 368), collectionViewLayout: layout!)
self.PastObjectsCollection!.dataSource = self
self.PastObjectsCollection!.delegate = self
self.PastObjectsCollection!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier:"Chow Object Reuse ID")
self.PastObjectsCollection!.backgroundColor = UIColor.blackColor()
self.view.addSubview(self.PastObjectsCollection!)
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1 //objectsCount
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Chow Object Reuse ID", forIndexPath: indexPath) as UICollectionViewCell
cell.backgroundColor = UIColor.whiteColor()
var imageView:UIImageView = UIImageView()
imageView.frame = CGRect(x: 0, y: 0, width: 90, height: 90)
//imageView.image = imageThumbsArray[indexPath.row]
cell.addSubview(imageView)
return cell
}
}

Resources