I have two UICollectionView collectionViewA and collectionViewB in my ViewController, collectionViewB is presented as a subView when a button is tapped, the issue i have now is that when i scroll on collectionViewB, collectionViewA scrolls too, is there a way to only scroll for the active collectionView without affecting the second.?
extension TrendListVC: UICollectionViewDelegate,
UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.collectionViewForSubView{
return count
}
return 60
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.collectionViewForSubView{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ModalViewCell
//let setting = settings[indexPath.item]
//cell.setting = setting
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell2", for: indexPath) as! CollectionCell
cell.itemNameLabel.text = "Name".uppercased()
return cell
}
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var reusableView : CollectionHeader? = nil
if collectionView == self.collectionView{
if (kind == UICollectionElementKindSectionHeader) {
let head = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "headerCell", for: indexPath) as! CollectionHeader
head.trendListVc = self
head.headerHeightConstraint = headerHeightConstraint
reusableView = head
}
}
return reusableView!
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == self.collectionViewForSubView{
if count % 2 != 0 && indexPath.item == count - 1{
let paddingSpace = sectionInsets.left * (itemsPerRowForSubView + 1)
let availableWidth = collectionViewForSubView.frame.width - paddingSpace
return CGSize(width: availableWidth + 23, height: cellHeight)
}else{
let paddingSpace = sectionInsets.left * (itemsPerRowForSubView + 1)
let availableWidth = collectionViewForSubView.frame.width - paddingSpace
let widthPerItem = availableWidth / itemsPerRowForSubView
return CGSize(width: widthPerItem, height: cellHeight)
}
}else{
let paddingSpace = sectionInsets.left * (2 + 1)
let availableWidth = view.frame.width - paddingSpace
let widthPerItem = availableWidth / itemsPerRow
return CGSize(width: widthPerItem + 4, height: widthPerItem)
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if collectionView == self.collectionView{
return CGSize(width: view.frame.width, height: 50)
}else{
return CGSize(width: 0, height: 0)
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == self.collectionView{
showControllerForSetting(setting: "Name")
}else if collectionView == self.collectionViewForSubView{
print("Some thing")
}
}
}
This is most likely due to using your ViewController as delegate and datasource for both of your collection views. You need to create separate delegate classes for each collection view.
Related
I have a collectionView with images from a service request that are showed in lines with 3 elements.
What I need is that when a Have just one or two images from the request, the images shows aligned to the left, but the screen shows the images centered.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if imageFuelArray.count == 1{
let padding: CGFloat = 10
let collectionViewWidth = collectionView.frame.size.width - padding
let collectionViewHeight = collectionView.frame.size.height - padding
return CGSize(width: collectionViewWidth, height: collectionViewHeight)
} else{
let padding: CGFloat = 10
let collectionViewWidth = collectionView.frame.size.width - padding
let collectionViewHeight = collectionView.frame.size.height - padding
return CGSize(width: collectionViewWidth/2, height: collectionViewHeight/2)
}
}
I have this function
func getSizeVews(){
if imageFuelArray.count > 6{
self.collectionView.heightAnchor.constraint(equalToConstant: self.collectionView.contentSize.height+45).isActive = true
self.servicesTableView.heightAnchor.constraint(equalToConstant: self.servicesTableView.contentSize.height+70).isActive = true
view.layoutSubviews()
} else {
self.collectionView.heightAnchor.constraint(equalToConstant: self.collectionView.contentSize.height).isActive = true
self.servicesTableView.heightAnchor.constraint(equalToConstant: self.servicesTableView.contentSize.height+70).isActive = true
view.layoutSubviews()
}
}
And there I have my collectionView datasource and delegate
extension ServicesStationViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
imageFuelArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: flCollectionVieCell, for: indexPath) as! FuelCollectionViewCell
let fuel = imageFuelArray[indexPath.row]
if let cepsaFuel = CepsaFeaturesFuel(key: Int(fuel) ?? 0) {
let imgName = CepsaFeaturesFuel.featureFuelImageName(with: cepsaFuel.featuresFuelType)
cell.fuelImageView?.image = UIImage(named: imgName!)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if imageFuelArray.count == 1{
let padding: CGFloat = 10
let collectionViewWidth = collectionView.frame.size.width - padding
let collectionViewHeight = collectionView.frame.size.height - padding
return CGSize(width: collectionViewWidth, height: collectionViewHeight)
} else{
let padding: CGFloat = 10
let collectionViewWidth = collectionView.frame.size.width - padding
let collectionViewHeight = collectionView.frame.size.height - padding
return CGSize(width: collectionViewWidth/2, height: collectionViewHeight/2)
}
}
}
I am trying to copy the search layout of Instagram for the collectionview. I have tried doing it but my second item starts from the center instead of top which is causing the problem.
Actual Output:
Expected Outlput:
Here is my code
extension UIViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 12
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CVCell", for: indexPath) as! CVCell
cell.backgroundColor = .lightGray
cell.lbl.text = "\(indexPath.item)"
cell.lbl.textAlignment = .center
cell.layer.borderColor = UIColor.black.cgColor
cell.layer.borderWidth = 0.5
return cell
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.item == 0{
return CGSize(width: (UIScreen.main.bounds.width / 3) * 2, height: (UIScreen.main.bounds.width / 3) * 2)
}
return CGSize(width: UIScreen.main.bounds.width / 3, height: UIScreen.main.bounds.width / 3)
}
I want first UICollectionViewCell by full width of screen and further UICOllectionViewCell is 2*2.
For that i have tried below code.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
let cell : FirstCell = collectionView.dequeueReusableCell(withReuseIdentifier: "FirstCell", for: indexPath) as! FirstCell
cell.layoutSubviews()
return cell
}
else {
let cell : SecondCell = collectionView.dequeueReusableCell(withReuseIdentifier: "SecondCell", for: indexPath) as! SecondCell
cell.layoutSubviews()
return cell
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.item == 0 {
let width = (UIScreen.main.bounds.size.width - 16)
return CGSize(width: width, height: 200)
}
else {
let width = (UIScreen.main.bounds.size.width - 24) / 2
let height = (UIScreen.main.bounds.size.width * 200) / 320
return CGSize(width: width, height: height)
}
}
But the Output comes as below.
Requirement: First Green Cell is of full Width and 2nd Yellow cell comes not from Center but it comes from left side and 3rd, 4th and so on cell comes 2*2
Any help will be appreciated.
Thanks in Advance.
To achieve this, you should take 3 section in collection view.
section 1 - 1 cell
section 2 - 1 cell (width should be less than half of available width for collection cell)
section 3 - number of cell you wanted
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return section == 2 ? 4 : 1
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
switch indexPath.section {
case 0:
return CGSize(width: UIScreen.main.bounds.width - 20, height: 200)
case 1:
return CGSize(width: (UIScreen.main.bounds.width - 30) / 2, height: 200)
default:
return CGSize(width: (UIScreen.main.bounds.width - 30) / 2, height: 200)
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectioncell", for: indexPath)
cell.backgroundColor = .red
return cell
}
}
Your view will look like:
I have a collectionView with 2 sections. The frame of the first section will depend on the number of cells inside of it. Since the total number of cells (firstSectionData.count) in the first section will vary I need to find the CGPoint for the Second Section. I specifically need to find out the x/y values of where the second section begins.
The frame will also be suffice because I can extract them from there. How can I find this out?
var cv: UICollectionView!
let firstSectionCell = "FirstSectionCell"
let secondSectionCell = "SecondSectionCell"
let secondSectionHeaderView = "SecondSectionHeaderView"
let firstSectionData = [String]()
let secondSectionData = [String]()
let cellHeight: CGFloat = 50
let headerHeight: CGFloat = 60
override func viewDidLoad() {
super.viewDidLoad()
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0)
layout.scrollDirection = .horizontal
cv = UICollectionView(frame: view.frame, collectionViewLayout: layout)
cv.delegate = self ; cv.dataSource = self
cv.register(FirstSectionCell.self, forCellWithReuseIdentifier: firstSectionCell)
cv.register(SecondSectionCell.self, forCellWithReuseIdentifier: secondSectionCell)
cv.register(SecondSectionHeaderView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: secondSectionHeaderView)
view.addSubview(cv)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0{
return firstSectionData.count // varies
}
return secondSectionData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0{
return firstSectionCell = collectionView.dequeueReusableCell(withReuseIdentifier: self.firstSectionCell, for: indexPath) as! FirstSectionCell
}
return secondSectionCell = collectionView.dequeueReusableCell(withReuseIdentifier: self.secondSectionCell, for: indexPath) as! SecondSectionCell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: self.cellHeight) // height is 50
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let headerView: UICollectionReusableView?
if kind == UICollectionElementKindSectionHeader{
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: self.secondSectionHeaderView, for: indexPath) as! SecondSectionHeaderView
headerView = header
}
return headerView!
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if section == 0{
return CGSize.zero // the first section doesn't have a header
}
return CGSize(width: view.frame.width, height: self.headerHeight) // header height is 60 for the second section
}
This type of information is kept by the collection view's layout manager. The collection view provides two convenience methods:
layoutAttributesForItem(at:)
and:
layoutAttributesForSupplementaryElement(ofKind:at:)
These return a value of UICollectionViewLayoutAttributes?. This in turn has properties such as frame and others.
If you want the frame of a specific item in a collection view you would do:
let frame = collectionView.layoutAttributesForItem(at: someIndexPath)?.frame
If you want the frame of a section header in a collection view you would do:
let frame = collectionView.layoutAttributesForSupplementaryElement(ofKind: UICollectionElementKindSectionHeader, at: someSectionIndexPath)
To get the position of a UICollectionViewCell relative to the view, in which it's located (e.g. relative to your visible area):
if let theAttributes = collectionView.layoutAttributesForItem(at: IndexPath(item: 1, section: 0)) {
let cellFrameInSuperview = collectionView.convert(theAttributes.frame, to: collectionView.superview)
print("X of Cell is: \(cellFrameInSuperview.origin.x)")
}
I have two cells within a single collection view. They both have different dimensions but for some reason on runtime both of the cells appear to have the same dimension.
Here's my setup:
internal func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if cellType == .books {
return books.count
} else if cellType == .spotlights {
return spotlights.count
} else {
return 0
}
}
internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if cellType == .books {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "booksCollectionCell", for: indexPath) as! BooksCollectionCell
let bookTitle = books[indexPath.item].title
let authors = books[indexPath.item].authors
cell.configureCell(title: bookTitle, authorNames: authors)
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "spotlightsCollectionCell", for: indexPath) as! spotlightsCollectionViewCell
cell.configureCell(image: #imageLiteral(resourceName: "testImage"))
return cell
}
}
Here's my storyboard screenshots:
and this is setup for collectionView:
edit: So I managed to get somwhere (thanks to cpatmulloy) by putting this code in cellForItem:
cell.frame = CGRect(x: cell.frame.origin.x, y: cell.frame.origin.y, width: 180.0, height: 130.0)
However, here's the result (look at the last cell in tableview):
Try explicitly setting the cell's height and width in the cellForItemAtIndex Path function.
Be sure to set these example properties (i.e bookCellWidth) yourself
internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if cellType == .books {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "booksCollectionCell", for: indexPath) as! BooksCollectionCell
let bookTitle = books[indexPath.item].title
let authors = books[indexPath.item].authors
cell.configureCell(title: bookTitle, authorNames: authors)
cell.frame = CGRect(x: cell.frame.origin.x, y: cell.frame.origin.y, width: bookCellWidth, height: bookCellHeight)
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "spotlightsCollectionCell", for: indexPath) as! spotlightsCollectionViewCell
cell.configureCell(image: #imageLiteral(resourceName: "testImage"))
cell.frame = CGRect(x: cell.frame.origin.x, y: cell.frame.origin.y, width: spotlightCellWidth, height: spotlightCellHeight)
return cell
}
}
Ok so I managed to fix it!
First I added UICollectionViewDelegateFlowLayout to the cell class, then:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if cellType == .spotlights {
return CGSize(width: 250.0, height: 180.0)
} else {
return (collectionViewLayout as! UICollectionViewFlowLayout).itemSize
}
}