collection view moving cell down - swift

This is my first post and although this seems like something easy I just cant seem to find the fix. I am trying to move the cell on the left up to match the top of the cell on the right. Maybe I need to use a different controller however I thought I would ask before going back to the drawing board
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = .white
collectionView?.isScrollEnabled = false
collectionView?.contentInsetAdjustmentBehavior = .never
collectionView?.register(LeagueCell.self, forCellWithReuseIdentifier: cellId)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 24
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 24
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.item == 0 {
return CGSize(width: view.frame.width * 0.87, height: 70)
} else if indexPath.item == 1 {
return CGSize(width: 120, height: 120)
} else if indexPath.item == 2 {
return CGSize(width: view.frame.width * 0.47, height: view.frame.height * 0.6)
} else if indexPath.item == 3 {
return CGSize(width: view.frame.width * 0.3, height: view.frame.height * 0.41)
}
return CGSize(width: 10, height: 10)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 24, left: 24, bottom: 24, right: 24)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! LeagueCell
return cell
}

It looks like you are using UICollectionViewFlowLayout here.
This is the behaviour of that layout.
If you want to create a layout that does what you are looking for the best thing would be to create it yourself.
There are many tutorials about creating your own layouts. Depending on exactly what you want the layout could be very different.
They all pretty much work the same way apart from the prepare method that actually calculates everything.

You can change the Y of the cell on the left and set it same as the cell on the right:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! LeagueCell
if(indexPath.row == 1){
let indexPathOfRightCell = IndexPath(row: 2, section: 0)
let cellOnTheRight = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPathOfRightCell) as! LeagueCell
cell.frame.origin.y = cellOnTheRight.frame.origin.y
}
return cell
}
It’s not the perfect or standard solution, but it may work in your case.

Related

How to override the default position of UICollectionViewCells?

I have a vertical UICollectionView which contains 5 different types of cells. The 4 of them take the whole width of the UICollectionView, so the func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize gets the work done.
The other 2 are of the same size but their default position needs to be changed; I want them to be aligned from left to right, instead of the centered default.
Here's how I set up my UICollectionView:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
switch typesOfCellsArray[indexPath.row] {
case .createVoiceRoom:
return CGSize(width: collectionView.frame.width, height: 70)
case .voiceRooms:
let height: CGFloat = content.voiceRooms.count > 3 ? 256 : 128
return CGSize(width: collectionView.frame.width, height: height)
case .seeMoreVoiceRooms:
return CGSize(width: collectionView.frame.width, height: 50)
case .newStatus:
let width = collectionView.frame.width / 4
return CGSize(width: width, height: width + 40)
case .status:
let width = collectionView.frame.width / 4
return CGSize(width: width, height: width + 40)
}
}
Here's how they look:
And here's what I want:
I think I need to subclass UICollectionViewLayout to achieve that, but I've failed... Here's what I did:
class HomeCollectionViewLayout: UICollectionViewLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let collectionView = collectionView else { return nil }
let layoutAttributes = super.layoutAttributesForElements(in: rect)
layoutAttributes?.forEach({ attributes in
if collectionView.cellForItem(at: attributes.indexPath) is NewHomeStatusCollectionViewCell {
let column = attributes.indexPath.row % 3
attributes.frame.origin.x = CGFloat(column-1) * attributes.frame.width
}
})
return layoutAttributes
}
}
Of course, I have set this class as the UICollectionView layout. Any ideas?
You can insert each of you cell into separate section and then control following:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { }
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { }
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { }

How to modify gridView with the following example

I've been trying to figure out how to accomplish this kind of gridView display for my app,
Image example of what i need to accomplish
i have this block of codes, which came from another question relating to gridView,
but the texts inside each views are not displaying properly
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 width = self.collectionView.frame.size.width
let size:CGFloat = (width - space) / 2.0
if indexPath.row == 0 {
return CGSize(width: width, height: width / 2.0)
}
return CGSize(width: size, height: size)
}
Well , This is something you have just give layout to collection view but you have to use CustomCell to proper design inside items of collectionview, also for above layout guide i would suggest to use Extension like this
Extension Yourviewcontroller: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = self.collectionView.frame.size.width
let size:CGFloat = (width - space) / 2.0
if indexPath.row == 0 {
return CGSize(width: width, height: width / 2.0)
}
return CGSize(width: size, height: size)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
}
Regarding custom cell creation use this link https://www.ioscreator.com/tutorials/custom-collection-view-cell-ios-tutorial ,
In your case just use one cell with one image and 2 lables below and make them centerAlign(Using constraint) And use that cell on your viewcontroller as below
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
cell.imageView.image = Yourimage
cell.lableName.text = yourlable
cell.lableDetail.text = yourdetailtext
return cell
}
let me know if you need any other help on this

Swift - How to adjust UICollectionViewCell's ratio for different IOS device sizes

I'm using a
CollectionView
as a menu bar at the bottom of my
ViewController
I've created a custom class and have made 5 evenly spaced cells which fills the entire CollectionView on an iPhone 8 with the following, which is the desired result -
layout.itemSize = CGSize(width: self.frame.width / 5, height: self.frame.height)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
self.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
self.scrollIndicatorInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
self.collectionViewLayout = layout;
However when I run the project on any iPhone with a larger screen I get the following result:
My question is, how could I scale the cells up to fit without any margins, even if it requires the CollectionView to increase it's height, I would like the images (which will be placed in the cells) to maintain their aspect ratio from the iPhone 8 screen.
Could I just increase the size of each CollectionViewCell with code?
If so is there a way to do so without working out the width/height of each iPhone released to date?
Or can someone please recommend a different way to accomplish this? if I'm approaching this the wrong way.
Thanks in advance!
It seems that the view's width isn't correct in the place you put the line
layout.itemSize = CGSize(width: self.frame.width / 5, height: self.frame.height)
so replace it with
layout.itemSize = CGSize(width: UIScreen.main.bounds.width / 5, height: self.frame.height)
you can also implement
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize
with conform to UICollectionViewDelegateFlowLayout
Here is my code for CollectionView. You can modify as per your requirement.
class HomeViewController: UIViewController,UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var homeCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
homeCollectionView.delegate = self;
homeCollectionView.dataSource = self;
homeCollectionView.reloadData()
}
//MARK:- COLLECTION VIEW
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
if let count = myArray.count{
return count
}
return 0
}
func collectionView(_ collectionView: UICollectionView,
viewForSupplementaryElementOfKind kind: String,
at indexPath: IndexPath) -> UICollectionReusableView {
switch kind {
case UICollectionElementKindSectionHeader:
let headerView = homeCollectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HomeHeaderCell", for: indexPath) as! HomeHeaderCell
headerView.UpdateHeaderCell(indexPath: indexPath)
headerView.btn_SeeAll.addTarget(self, action: #selector(SeeAllDestinations), for: .touchUpInside)
return headerView
case UICollectionElementKindSectionFooter:
let footerView = homeCollectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HomeFooterCell", for: indexPath) as! HomeFooterCell
return footerView
default:
return UICollectionReusableView()
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: collectionView.frame.width, height: 80)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return CGSize(width: collectionView.frame.width, height: 10)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell{
let myCell:HomeTopDestinationsCell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeTopDestinationsCell", for: indexPath) as! HomeTopDestinationsCell
myCell.backgroundColor = UIColor.colorFromCode(0xf1f1f1)
myCell.UpdateCellValue(obj:(myArray[indexPath.row])!)
return myCell as HomeTopDestinationsCell;
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
//Use for size
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
if DeviceType.IS_IPAD{
return CGSize(width: (self.view.frame.width-60)/3 , height: (self.view.frame.width-60)/3);
}
return CGSize(width: (self.view.frame.width-60)/2 , height: (self.view.frame.width-60)/2);
}
//Use for interspacing
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 10.0
}
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10.0
}
}

How to load number of column in UICollectionView

I am new to swift, I am working in UICollectionView I need to load Seven column in it how can do it, Also padding between each cell should be (top:1,bottom:1,left:1,right:1)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: CGFloat(collectionView.frame.size.width / 10.2), height: CGFloat(100))
}
//UICollectionViewDatasource methods
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 31
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as UICollectionViewCell
cell.backgroundColor = self.randomColor()
return cell
}
Works for both horizontal and vertical scroll directions and variable spacing
Specify number of columns
let numberOfColumns: CGFloat = 7
Configure flowLayout to render specified numberOfColumns
if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
let horizontalSpacing = flowLayout.scrollDirection == .vertical ? flowLayout.minimumInteritemSpacing : flowLayout.minimumLineSpacing
let cellWidth = (view.frame.width - max(0, numberOfColumns - 1)*horizontalSpacing)/numberOfColumns
flowLayout.itemSize = CGSize(width: cellWidth, height: cellWidth)
}

Changing size of selected UICollectionView Cell

I have a simple UICollectionViewController that returns X amount of cells. I want to have it so when a cell is selected, that specific selected cell will change it's size and become larger in height as all of the other cells stay the same. How do I achieve this? Here's my code:
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = UIColor(white: 0.90, alpha: 1.0)
collectionView?.register(PostCell.self, forCellWithReuseIdentifier: cellId)
collectionView?.showsVerticalScrollIndicator = false
collectionView?.alwaysBounceVertical = true
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
override 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, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height = (view.frame.width) * 9 / 16
return CGSize(width: view.frame.width, height: height + 50 + 50)
}
}
You can check to see if the indexPath from sizeForItemAt is selected. If it is, you return a different height otherwise return the standard height.
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.performBatchUpdates(nil, completion: nil)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
switch collectionView.indexPathsForSelectedItems?.first {
case .some(indexPath):
return CGSize() // your selected height
default:
let height = (view.frame.width) * 9 / 16
return CGSize(width: view.frame.width, height: height + 50 + 50)
}
}