TenViewController code :
class TenViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var selectedCell: UICollectionViewCell!
var arrayLocation = ["aaa", "bbb", "ccc", "ddd", "eee"]
var myCollectionView: UICollectionView!
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView,numberOfItemsInSection section: Int) -> Int
{
return arrayLocation.count
}
collection delegate
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! MyCollectionViewCell
cell.backgroundColor = UIColor.white
cell.titleLabel?.text = arrayLocation[indexPath.row]
cell.titleLabel.font = UIFont.systemFont(ofSize: 24)
return cell
}
// check cell and do somthing
func collectionView(_ collectionView: UICollectionView,didSelectItemAt indexPath: IndexPath)
{ selectedCell = myCollectionView.cellForItem(at: indexPath)! selectedCell.contentView.backgroundColor = UIColor.red
collectionView.allowsSelection = true
collectionView.allowsMultipleSelection = true
}
I trying to use this func but it doesn't work
func collectionView(_ collectionView: UICollectionView,didDeselectItemAt indexPath: IndexPath) {
myCollectionView.deselectItem(at: indexPath, animated: false) }
override func viewDidLoad() {
//get view size
let fullsize = UIScreen.main.bounds.size
//get collectionViewCell layout
let layout = UICollectionViewFlowLayout()
//cell size
layout.itemSize = CGSize(width: 120, height: 30)
//mycollectionView size
myCollectionView = UICollectionView(frame: CGRect(x: 108, y: 70, width: fullsize.width - 70, height: fullsize.height - 180), collectionViewLayout: layout)
myCollectionView.delegate = self
myCollectionView.dataSource = self
myCollectionView.backgroundColor = UIColor.white
myCollectionView.register(MyCollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
layout.sectionInset = UIEdgeInsetsMake(0, 5, 0, 50);
layout.minimumLineSpacing = 10
layout.minimumInteritemSpacing = 0.5
myCollectionView.backgroundColor = UIColor(patternImage: myPag)
self.view.addSubview(myCollectionView)
}
}
MyCollectionViewCell code
class MyCollectionViewCell: UICollectionViewCell {
var titleLabel:UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
// create UILabel
let w = Double(UIScreen.main.bounds.size.width)
titleLabel = UILabel(frame:CGRect(x: 0, y: 0, width: w/3 - 10.0, height: 30))
titleLabel.textAlignment = .center
titleLabel.textColor = UIColor.black
self.addSubview(titleLabel)
}
required init?(coder aDecoder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
}
I would like to get cell deselect and what should I do?
Does anyone can help me plz thanks mate!!
how to make a button can chose all of cell?
You need to set property allowsSelection and allowsMultipleSelection also in viewDidLoad instead of didSelectItemAt indexPath, Also you reusing the cell so your selection of cell is change when you scroll the CollectionView for preventing this issue create one instance of type [IndexPath] and access it in your collectionView's method like this.
var selectedCell = [IndexPath]()
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! MyCollectionViewCell
cell.titleLabel?.text = arrayLocation[indexPath.row]
cell.titleLabel.font = UIFont.systemFont(ofSize: 24)
if selectedCell.contains(indexPath) {
cell.contentView.backgroundColor = .red
}
else {
cell.contentView.backgroundColor = .white
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)!
selectedCell.append(indexPath)
cell.contentView.backgroundColor = .red
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)!
if selectedCell.contains(indexPath) {
selectedCell.remove(at: selectedCell.index(of: indexPath)!)
cell.contentView.backgroundColor = .white
}
}
Swift 3.0 Solution
extension UICollectionView {
func deselectAllItems(animated: Bool = false) {
for indexPath in self.indexPathsForSelectedItems ?? [] {
self.deselectItem(at: indexPath, animated: animated)
}
}
}
How to use?
myCollectionView.deselectAllItems(false)
Related
I want to make a UICollectionView with the cells the width of the screen, but the height is based on the aspect ratio of the UIImageView inside.
In my current implementation all of the UICollectionViewCell instances are squares and this isn't what I want.
I want to use auto layout somehow to make the size of the image the width of the screen, but the relevant height depends on the aspect ratio of the image used.
Everything is done programatically in code.
My code:
class ViewController: UIViewController {
var data = ["1","2","3","4","5","6","7","8","1","2","3","4","5","6","7","8"]
var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.dataSource = self
self.collectionView.delegate = self
self.collectionView.register(SubclassedCollectionViewCell.self, forCellWithReuseIdentifier: "cell")
self.collectionView.alwaysBounceVertical = true
self.collectionView.backgroundColor = .white
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func loadView() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: UIScreen.main.bounds.size.width - 20, height: UIScreen.main.bounds.size.width / 1)
layout.scrollDirection = .vertical
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
self.view = collectionView
}
}
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? SubclassedCollectionViewCell {
let data = self.data[indexPath.item]
cell.setupCell(image: data)
return cell
}
fatalError("Could not dequeue cell")
}
}
with the cell
class SubclassedCollectionViewCell: UICollectionViewCell {
var hotelImageView: UIImageView = {
var hotelView = UIImageView()
hotelView.contentMode = .scaleAspectFill
hotelView.clipsToBounds = true
return hotelView
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(hotelImageView)
hotelImageView.translatesAutoresizingMaskIntoConstraints = false
hotelImageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
hotelImageView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
hotelImageView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
hotelImageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupCell(image: String) {
if let image : UIImage = UIImage(named: image) {
hotelImageView.image = image
}
}
}
First, calculate the ratio based on the width and multiply by collection view width you can get a new height based on width.
Final Code: Remove itemSize from the loadview function. And calculate height and return item size in sizeForItemAt method.
loadView
override func loadView() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
// layout.itemSize = CGSize(width: UIScreen.main.bounds.size.width - 20, height: UIScreen.main.bounds.size.width / 1) <-- Remove this
layout.scrollDirection = .vertical
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
self.view = collectionView
}
UICollectionViewDelegateFlowLayout
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? SubclassedCollectionViewCell {
let data = self.data[indexPath.item]
cell.setupCell(image: data)
return cell
}
fatalError("Could not dequeue cell")
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
guard let iamgeData = UIImage(named: self.data[indexPath.item]) else {
return .zero
}
let width = collectionView.bounds.width
let heightOnWidthRatio = iamgeData.size.height / iamgeData.size.width
let height = width * heightOnWidthRatio
return CGSize(width: width, height: height)
}
}
I have decided start a project with no storyboard for the first time and at the moment I am stuck trying to figuring out how to achieve a proper dynamic cell in my CollectionViewController. Reading some of the solutions here in Stackoverflow I got the point in using a layout.estimatedItemSize but it somehow stops the bouncing effect from the collection view and also in my second cell which is a horizontal scroll view will not work after this implementation.
Here is my code(UICollectionViewController):
class InfoEmpaVC: UICollectionViewController, UICollectionViewDelegateFlowLayout {
fileprivate let cell1 = "cell1"
fileprivate let cell2 = "cell2"
fileprivate let cellID = "cellID"
fileprivate let headerID = "headerID"
fileprivate let padding: CGFloat = 10
//
//
//GET THE DATA FROM:
var empanada: Empanadas!
struct Cells {
static let empanadaStepsCell = "EmpanadaStepsCell"
}
override func viewDidLoad() {
super.viewDidLoad()
setupCollectionViewLayout()
setupCollectionView()
}
//CHANGE COLOR OF STATUS BAR
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
fileprivate func setupCollectionView() {
collectionView.backgroundColor = UIColor(named: "ColorBackground")
collectionView.contentInsetAdjustmentBehavior = .never
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(InfoHeaderVC.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerID)
//FirstCELL
collectionView.register(EmpaIngredientsListCell.self, forCellWithReuseIdentifier: cell1)
//SecondCELL
collectionView.register(EmpaStepsCell.self, forCellWithReuseIdentifier: cellID)
}
fileprivate func setupCollectionViewLayout() {
if let layout = collectionViewLayout as? UICollectionViewFlowLayout {
layout.sectionInset = .init(top: padding, left: padding, bottom: padding, right: padding)
layout.estimatedItemSize = CGSize(width: view.frame.width, height: 50)
}
}
var headerView: InfoHeaderVC!
//HEADER COLLECTION VIEW
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerID, for: indexPath) as? InfoHeaderVC
headerView.empaImageView.image = UIImage(named: empanada.image)
headerView.empaTitleLabel.text = empanada.name
headerView.empaDescriptionLabel.text = empanada.info
headerView.buttonX.addTarget(self, action: #selector(dismissVC), for: .touchUpInside)
headerView.buttonAddFavorite.addTarget(self, action: #selector(addButtonTapped), for: .touchUpInside)
return headerView!
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return .init(width: view.frame.width, height: 350)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cell1, for: indexPath)
guard let cellOne = cell as? EmpaIngredientsListCell else {
fatalError("Wrong cell type for section 0. Expected CellTypeOne")
}
//INGREDIENT LIST
cellOne.empaIngredientList.ingredientList.append(contentsOf: empanada.ingredients)
cellOne.empaIngredientList.configure()
return cellOne
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath) as! EmpaStepsCell
cell.pasos.append(contentsOf: empanada.pasos)
cell.titleHeaderLabel.text = "Step by Step"
cell.configure()
print (cell.pasos.count)
return cell
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.item == 0 {
return .init(width: view.frame.width - 2 * padding, height: 300)
} else {
return .init(width: view.frame.width - 2 * padding, height: 300)
}
}
//OBJC FUNC
#objc func dismissVC() {
dismiss(animated: true)
}
//SAVE DATA
#objc func addButtonTapped() {
configureSaveToFavorites(empanada: empanada!)
}
}
Cell 1:
import UIKit
import SnapKit
class EmpaIngredientsListCell: UICollectionViewCell {
let empaIngredientList = EmpaIngredientsContainerView()
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
print(intrinsicContentSize)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var frame = layoutAttributes.frame
frame.size.height = ceil(size.height)
layoutAttributes.frame = frame
return layoutAttributes
}
func setupUI() {
//contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(empaIngredientList)
empaIngredientList.snp.makeConstraints { (make) in
make.top.bottom.left.right.equalTo(self.contentView)
make.edges.equalTo(self.safeAreaLayoutGuide)
}
}
}
I've created a collection view programmatically and can't figure out how to add labels and a background image to the cells. Here's the code I have so far for the collection view.
import UIKit
class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let cell = "cellId"
let text = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Vote"
collectionView?.backgroundColor = UIColor.white
collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cell)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cell, for: indexPath)
cell.backgroundColor = UIColor.lightGray
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 200)
}
}
A simple custom UICollectionViewCell class would look like this:
class MyCell : UICollectionViewCell {
var label1: UILabel
var label2: UILabel
var bgImg: UIImageView
}
Edit the viewDidLoad function:
collectionView?.register(MyCell.self, forCellWithReuseIdentifier: cell)
Edit the cellForItemAt function:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cell,
for: indexPath) as! MyCell
cell.bgImg.image = UIImage(named: "img.png")
cell.label1.text = "..."
cell.label2.text = "..."
return cell
Use the init function in the MyCell class to layout the labels.
Create Subclass of collection view cell and Instead of UICollectionViewCell use CustomCollectionViewCell
class CustomCollectionViewCell: UICollectionViewCell {
var imageView: UIImageView?
var label: UILabel?
override init(frame: CGRect) {
super.init(frame: frame)
imageView = UIImageView(frame: self.bounds)
//customise imageview
imageView?.backgroundColor = UIColor.red
contentView.addSubview(imageView!)
label = UILabel(frame: CGRect(x: 20, y: 20, width: self.bounds.width - 20, height: 20))
//Customsize label
label?.text = "Hello"
label?.textColor = UIColor.white
contentView.addSubview(label!)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var bounds: CGRect {
didSet {
contentView.frame = bounds
}
}
}
In View Controller updated following code:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Vote"
collectionView?.backgroundColor = UIColor.white
collectionView?.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: cell)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cell, for: indexPath) as! CustomCollectionViewCell
cell.backgroundColor = UIColor.lightGray
return cell
}
I have got this Swift code
`
let cellId="cellId"
class FeedController: UICollectionViewController{
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Centill"
collectionView?.reloadData()
collectionView?.backgroundColor = UIColor(white: 0.95, alpha: 1)
collectionView?.register(FeedCell.self, forCellWithReuseIdentifier: cellId)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath);
cell.backgroundColor = .yellow
return cell
}
}
class FeedCell: UICollectionViewCell {
override init(frame: CGRect){
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews(){
backgroundColor = .yellow
}
}
`
But unfortunately my cells are not showing.It only shows navigation bar and background color.what may be the problem with my code?
Try This code:
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 60, height: 60)
let myCollectionView:UICollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
myCollectionView.dataSource = self
myCollectionView.delegate = self
myCollectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "MyCell")
myCollectionView.backgroundColor = UIColor.whiteColor()
self.view.addSubview(myCollectionView)
You have to provide the size for collection view cell. add the below code snippet
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// calculate and return the height
}
In your cellForItemAt dataSource method you need to give custom UICollectionCell Class
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! FeedCell
cell.backgroundColor = .yellow
return cell
Then you will able to see cell.
Try it.
You add in the class
UICollectionViewDataSource and UICollectionVIewDelegate.
I have got this Swift code
`
let cellId="cellId"
class FeedController: UICollectionViewController{
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Centill"
collectionView?.reloadData()
collectionView?.backgroundColor = UIColor(white: 0.95, alpha: 1)
collectionView?.register(FeedCell.self, forCellWithReuseIdentifier: cellId)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath);
cell.backgroundColor = .yellow
return cell
}
}
class FeedCell: UICollectionViewCell {
override init(frame: CGRect){
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews(){
backgroundColor = .yellow
}
}
`
But unfortunately my cells are not showing.It only shows navigation bar and background color.what may be the problem with my code?
Try This code:
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 60, height: 60)
let myCollectionView:UICollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
myCollectionView.dataSource = self
myCollectionView.delegate = self
myCollectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "MyCell")
myCollectionView.backgroundColor = UIColor.whiteColor()
self.view.addSubview(myCollectionView)
You have to provide the size for collection view cell. add the below code snippet
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// calculate and return the height
}
In your cellForItemAt dataSource method you need to give custom UICollectionCell Class
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! FeedCell
cell.backgroundColor = .yellow
return cell
Then you will able to see cell.
Try it.
You add in the class
UICollectionViewDataSource and UICollectionVIewDelegate.