I am attempting to have a collectionView where users are able to select multiple cells, and have them highlight/deselect them. I can't seem to figure out how to even just change the background colors of the cells when they are tapped.
Here is where I am setting up the collectionview:
let extraCollectionView = UIView()
let flowLayout = UICollectionViewFlowLayout()
extraCollectionView.frame = CGRect(x:self.view.frame.size.width * 1.5, y:self.view.frame.size.height / 6.5, width: self.view.frame.width / 1.3, height: self.view.frame.height / 1.35)
extraCollectionView.backgroundColor = UIColor.clear
self.view.addSubview(extraCollectionView)
let collectionView = UICollectionView(frame: CGRect(x: extraCollectionView.frame.width * 0, y:extraCollectionView.frame.height * 0, width: extraCollectionView.frame.width, height: extraCollectionView.frame.height), collectionViewLayout: flowLayout)
collectionView.register(uploadGenreSelectionCVC.self, forCellWithReuseIdentifier: cellId)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.layer.cornerRadius = collectionView.layer.frame.width / 10
collectionView.backgroundColor = UIColor.clear
collectionView.layer.borderColor = UIColor.blue.cgColor
collectionView.layer.borderWidth = 3
collectionView.allowsMultipleSelection = true
extraCollectionView.addSubview(collectionView)
Here is my collectionView code:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 15
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! uploadGenreSelectionCVC
cell.layer.borderColor = UIColor.blue.cgColor
cell.layer.borderWidth = 2
cell.backgroundColor = UIColor.clear
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = (collectionView.bounds.width) / 3
let height = (collectionView.bounds.height) / 5
return CGSize(width:width, height:height)
}
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 0
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! uploadGenreSelectionCVC
print("yo")
cell.contentView.layer.backgroundColor = UIColor.red.cgColor
}
&& Here is the cell itself
let genreLabel = UILabel()
override func draw(_ rect: CGRect) {
genreLabel.frame = CGRect(x: self.frame.size.width * 0, y: self.frame.size.height/2.7, width: self.frame.size.width, height: self.frame.size.height / 3)
genreLabel.text = "Rap"
genreLabel.textColor = UIColor.white
genreLabel.textAlignment = .center
addSubview(genreLabel)
}
What am I forgetting to do??
Override isSelected in your cell, and customize your cell given the value,
override var isSelected: Bool {
didSet {
self.backgroundColor = isHighlighted ? .lightGray : .clear
}
}
Note: this property is set automatically by collectionView
Related
I am placing a horizontal scroll UICollectionViewController inside of another UICollectionViewController cell. I am doing this because I want to create an image slider like effect.
Code for horizontal scroll UICollectionViewController:
class BusinessPhotosViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout{
var photos = [String]()
let cellId = "photos"
override func viewDidLoad() {
super.viewDidLoad()
if let layout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
}
collectionView?.backgroundColor = .red
collectionView?.showsVerticalScrollIndicator = false
collectionView?.showsHorizontalScrollIndicator = false
collectionView?.alwaysBounceVertical = false
collectionView?.isPagingEnabled = true
collectionView?.isScrollEnabled = true
collectionView?.register(BusinessPhotoCells.self, forCellWithReuseIdentifier: cellId)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! BusinessPhotoCells
if photos.count != 0 {
let imageUrl = photos[indexPath.item]
let url = URL(string: imageUrl)
cell.logoImage.kf.setImage(with: url)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.height-10, height: view.frame.height-10)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
}
In another class I add this horizontal scroll UICollectionViewController as such:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//ADDING SCROLL CELL HERE
if indexPath.section == 1 {
let scrollCell = collectionView.dequeueReusableCell(withReuseIdentifier: pictureCellId, for: indexPath)
scrollCell.backgroundColor = .blue
let bizVC = BusinessPhotosViewController(collectionViewLayout: UICollectionViewFlowLayout())
scrollCell.addSubview(bizVC.view)
bizVC.view.anchor(top: scrollCell.topAnchor, left: scrollCell.leftAnchor, bottom: scrollCell.bottomAnchor, right: nil, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: scrollCell.frame.width, height: scrollCell.frame.height)
return scrollCell
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: listCellId, for: indexPath) as! CouponCell
return cell
}
Edit: Adding numberOfItemsInSection per comments
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 0
}
if section == 1 {
return 1
}
return coupons.count
}
I return 1 for this section because I only want 1 horizontal scroll cell...Below that horizontal scroll cell (in section 2) I then have a list of vertical scroll cells that work as expected.
This results in something like this where only 3 squares are loaded up not the 10 as expected:
EDIT: ADDING IMAGE OF WHAT MY VIEW LOOKS LIKE NOW
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.
I don't understand what's happening with my UICollectionView.
I'm apologise in advance because I think the answer is very simple
I just wan't to create a UICollectionView programmatically with 4 cells but 2 of them does not appear I don't know why
Here my code:
class NewsListViewController: UIViewController {
public var newsImagesCollectionView: UICollectionView!
override func viewWillLayoutSubviews() {
if self.newsImagesCollectionView == nil {
self.createNewsImagesCollectionView()
}
}
fileprivate func createNewsImagesCollectionView() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
self.newsImagesCollectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
self.newsImagesCollectionView.dataSource = self
self.newsImagesCollectionView.delegate = self
self.newsImagesCollectionView.register(NewsImagesCollectionViewCell.self, forCellWithReuseIdentifier: NewsImagesCollectionViewCell.reuseIdentifier)
self.newsImagesCollectionView.backgroundColor = .yellow
self.newsImagesCollectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(self.newsImagesCollectionView)
self.newsImagesCollectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
self.newsImagesCollectionView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
self.newsImagesCollectionView.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
self.newsImagesCollectionView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
}
}
extension NewsListViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NewsImagesCollectionViewCell.reuseIdentifier, for: indexPath) as! NewsImagesCollectionViewCell
switch indexPath.row {
case 0:
cell.imageView.backgroundColor = .purple
case 1:
cell.imageView.backgroundColor = .green
case 2:
cell.imageView.backgroundColor = .orange
case 3:
cell.imageView.backgroundColor = .red
default:
cell.imageView.backgroundColor = .blue
}
cell.imageView.contentMode = .scaleAspectFit
cell.imageView.image = #imageLiteral(resourceName: "euro")
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
print(self.view.frame.width)
return CGSize(width: self.view.frame.width / 4, height: self.view.frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
}
And I get this:
enter image description here
Thanks for your help
Does your collection view has the same size than your main view? because you calculating the size with the main view, is better if you use the collection view size.
return CGSize(width: collectionView.frame.width / 4, height: collectionView frame.height)
I want to custom a lot of layout size for each row of my collectionView by using UICollectionViewDelegateFlowLayout like below:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = view.frame.width
if indexPath.row == 0 {
return CGSize(width: width, height: 300)
}else if indexPath.row == 1 {
return dynamicSize // i want this size wrap its content
}
return CGSize(width: width, height:100)
}
I want dynamicSize that can wrap its content for some row.
Anyone know how to do this?
Here is image of cell that i want dynamic size to wrap it.
I suggest you to use tableview instead of collectionview. It is very easy for you.
And for cellForHeight returns UITableViewAutomaticDimension. It will calculate your cell height itself and adjust it accordingly.
Note: Make sure your constraints are proper.
Edit: By using collectionview with two columns.
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var text = "Do any additional setup after loading the view, typically from a nib."
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets{
return UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize{
let cellWidth = self.view.frame.size.width/2 - 10
let textHeight = text.height(withConstrainedWidth: cellWidth, font: UIFont.systemFont(ofSize: 16))
let constantHeight : CGFloat = 40 + 25 + 10 // top name view + bottom like button + margins height
let totHeight = constantHeight + textHeight
return CGSize(width: cellWidth, height: totHeight)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCollectionViewCell", for: indexPath) as! MyCollectionViewCell
cell.label.text = text
cell.layer.borderWidth = 1.0
cell.layer.borderColor = UIColor.black.cgColor
return cell
}
}
extension String {
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)
return ceil(boundingBox.height)
}
func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)
return ceil(boundingBox.width)
}
}
Output:
Use this delegate method. this will work for me.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: Your cellWidth, height: YourcellHeight);
}
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)
}