Collection view inside a collection view - swift

As of title, I'm having trouble with the issue of nesting collectionViews. I found a workaround gimmicky solution but I'm not really satisfied with the result:
class ViewController3: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var outCollection: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
outCollection.dataSource = self
outCollection.delegate = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath:
IndexPath) -> UICollectionViewCell {
let cell = outCollection.dequeueReusableCell(withReuseIdentifier: "outCell", for:
indexPath) as! CollectionViewCell
cell.backgroundColor = .green
cell.setViewDD() // gimmick HERE
return cell
}
}
and for the CollectionViewCell
class CollectionViewCell: UICollectionViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var inCollection: UICollectionView!
func setViewDD() {
self.inCollection.delegate = self
self.inCollection.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = inCollection.dequeueReusableCell(withReuseIdentifier: "inCell", for: indexPath) as! innercellulosa
cell.backgroundColor = .red
return cell
}
}
if I try to set the delegate and datasource of the innerCollection (either in VC3 or CVCell) I stumble in multiple problems which I can't solve.

Related

Cant display image in UICollectionView cell

I need to display images in collection view cells but when I'm trying to do that I'm getting 10 empty cells and I don't know where im making mistakes
Here is my code of ViewController
class NewGalleryViewController: UIViewController {
var presenter: ViewToPresenterPhotoProtocol?
var builder: GalleryRequestBuilder?
#IBOutlet var collectionView: UICollectionView!
let reuseIdentifier = "customCVCell"
#objc func refresh() {
presenter?.refresh()
}
override func viewDidLoad() {
super.viewDidLoad()
self.setupPresenterIfNeed()
presenter?.viewDidLoad()
// Do any additional setup after loading the view.
}
func setupPresenterIfNeed() {
self.collectionView.backgroundColor = UIColor.white
if self.presenter == nil {
let presenter = GalleryPresenter()
presenter.view = self
self.presenter = presenter
self.builder = GalleryRequestBuilder()
}
}
}
extension NewGalleryViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.presenter?.photos.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! PhotoCollectionViewCell
KFImage.url(builder?.createImageUrl(name: (presenter?.photos[indexPath.item].name)!))
.onSuccess { result in
cell.imageView.image = result.image
}
return cell
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 180, height: 128)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 20.0
}
// MARK: - UICollectionViewDelegate protocol
private func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
// handle tap events
print("You selected cell #\(indexPath.item)!")
}
}
extension NewGalleryViewController: PresenterToViewPhotoProtocol{
func onFetchPhotoSuccess() {
self.collectionView.reloadData()
self.collectionView!.collectionViewLayout.invalidateLayout()
self.collectionView!.layoutSubviews()
self.collectionView.refreshControl?.endRefreshing()
}
func onFetchPhotoFailure(error: String) {
print("View receives the response from Presenter with error: \(error)")
self.collectionView.refreshControl?.endRefreshing()
}
}
And Here is the code of cell
class PhotoCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
I've checked the link I'm making request to and it works. So problem is not in link. Maybe I should reload items after getting images?
You should set your UICollectionView delegate and data source once the view is loaded:
override func viewDidLoad() {
super.viewDidLoad()
// Add this lines
collectionView.delegate = self
collectionView.dataSource = self
self.setupPresenterIfNeed()
presenter?.viewDidLoad()
}

Why is my collection view empty when I should have a bunch of reusable cells?

I have the following code:
class FinalImageViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var not: [UIImage?] = [#imageLiteral(resourceName: "silly5"), #imageLiteral(resourceName: "special16")]
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return not.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CVImageView", for: indexPath) as! CVCell
cell.cellImageView.image = not[indexPath.row]
return cell
}
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
print(ImagesOnClick)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(CVCell.self, forCellWithReuseIdentifier: "CVImageView")
}
}
And my cell:
class CVCell: UICollectionViewCell {
#IBOutlet weak var cellImageView: UIImageView!
}
Then in my storyboard I have set the imageView tag to 3, the cell identifier to CVImageView, but when I run the project the collection view is just all white and no items are showing. By the way if you're wondering what the ImagesOnClick is, it is just an array of the users selected images.
You can find your class name in storyboard, it should look like this
class FinalImageViewController: UIViewController,UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return ImagesOnClick.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withIdentifier: "CVImageView", for: indexPath) as! CVImageCell //replace CVImageCell with your cell class name
cell.imageView.image = ImagesOnClick[indexPath.row] //replace imageView with your image view name with tag=3
return cell
}
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
print(ImagesOnClick)
collectionView.register(CVImageCell.self, forCellWithReuseIdentifier: "CVImageView") //replace CVImageCell with your cell class name
collectionView.delegate = self
collectionView.dataSource = self
}
}

Print image name to console from UICollectionView

I'm working with a UICollectionView where I have a UIImage with a Tap Gesture Recogniser as the cell model for my CollectionView. I also have 57 images with different names that I want to print to the console depending on which image I tap on.
Here is my code:
import UIKit
class ViewController: UIViewController {
let OLLData = OLLCases()
// MARK: - Outlets
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
// MARK: - Navigation
#IBAction func isSelected(_ sender: Any) {
print("selected \(caseName)")
}
}
//MARK: - Data source
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return OLLData.list.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as! PhotoCell
let image = OLLData.list[indexPath.item].image
let caseName = OLLData.list[indexPath.item].image
cell.label.text = caseName
cell.imageView.image = UIImage(named: image)
return cell
}
}
I then have another swift file (PhotoCell )where I have the IBOutlets for label and imageView.
What methods are there of doing this?
Thanks.
You can use UICollectionViewDelegate method to detect tap on cell but to use that first of all your UICollectionView need to confirm the delegate with your UIViewController like:
collectionView.delegate = self
in your viewDidLoad method.
then you need to replace
extension ViewController: UICollectionViewDataSource {
with
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
and use delegate method
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
and you can get selected image name with
let caseName = OLLData.list[indexPath.item].image
print(caseName)
and didSelectItemAt will look like:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let caseName = OLLData.list[indexPath.item].image
print(caseName)
}
EDIT:
Your extension will look like:
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return OLLData.list.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as! PhotoCell
let image = OLLData.list[indexPath.item].image
let caseName = OLLData.list[indexPath.item].image
cell.label.text = caseName
cell.imageView.image = UIImage(named: image)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let caseName = OLLData.list[indexPath.item].image
print(caseName)
}
}
You should implement didSelectItemAt method, then get the cell you've selected like this:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! PhotoCell
print(cell.imageView)
print(cell.label)
}
Hope this help
Add an extension for UICollectionViewDelegate below the last extension in your ViewController:
extension ViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(OLLData.list[indexPath.item].image)
}
}

How to implement pagination for string array in collection view in swift 4

import UIKit
class ProductListViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource {
#IBOutlet weak var productListCell: UICollectionView!
var manArray = ["Men","m1","m2","m3","m4","m5","m6","m7"]
var mPrice = ["789","1259","959","1625","1259","936","980","1500"]
override func viewDidLoad() {
super.viewDidLoad()
productListCell.delegate = self
productListCell.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return manArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ListCollectionViewCell", for: indexPath) as! ListCollectionViewCell
cell.productImg.image = UIImage(named: manArray[indexPath.row])
cell.productlbl.text = "\(manArray[indexPath.row])"
cell.productprice.text = "\(mPrice[indexPath.row])"
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if indexPath.row == manArray.count - 1 {
let tmpArray = ["Men","m1","m2","m3","m4","m5","m6","m7"]
let tmpArray2 = ["789","1259","959","1625","1259","936","980","1500"]
manArray.append(contentsOf: tmpArray)
mPrice.append(contentsOf: tmpArray2)
productListCell.reloadData()
}
}
}
Here is my Updated code
Try this code
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if indexPath.row == manArray.count - 1 {
let tmpArray = ["Men","m1","m2","m3","m4","m5","m6","m7"]
let tmpArray2 = ["789","1259","959","1625","1259","936","980","1500"]
manArray.append(contentsOf: tmpArray)
mPrice.append(contentsOf: tmpArray2)
yourCollectionView.reloadData()
}
}

pass data from UITableViewCell to UIViewController

I have UITableViewCell and I want to send the indexPath.row number to UIViewController using didSet, but xcode gives me an error when i use the value for other things (in UIViewController) says that the value is nil error: unexpectedly found null when unwrapping an optional value.
But if I print in the variable in UIViewController the value appears.
What i do? Thanks.
class TableViewCellCentral: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var CollectionData: UICollectionView!
var send = Int() {
didSet{
ViewController().reload = send
}
}
override func awakeFromNib() {
super.awakeFromNib()
CollectionData.dataSource = self
CollectionData.delegate = self
CollectionData.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = CollectionData.dequeueReusableCell(withReuseIdentifier: "CellData", for: indexPath) as! CollectionViewCellData
cell.LabelData.text! = "number \(indexPath.row)"
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = CollectionData.dequeueReusableCell(withReuseIdentifier: "CellData", for: indexPath) as! CollectionViewCellData
send = indexPath.row
CollectionData.reloadData()
}
}
ViewController() is just an instance of your ViewController. What you're doing when you say ViewController() is you're creating a new ViewController, rather than accessing the one you're looking for. If you want the indexPath.row, you need to send it to the actual VC, not just an instance of it.
You need to keep in mind that not all data is loaded instantly and at the same time, also that it does not always load in the order that you expect it to. It is possible that you are asking for the data before it is even assigned. Try
import UIKit
class TableViewCellCentral: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var CollectionData: UICollectionView!
var send = Int() {
didSet {
ViewController().reload = send
}
}
override func awakeFromNib() {
super.awakeFromNib()
CollectionData.dataSource = self
CollectionData.delegate = self
CollectionData.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = CollectionData.dequeueReusableCell(withReuseIdentifier: "CellData", for: indexPath) as! CollectionViewCellData
if indexPath.row != nil {
cell.LabelData.text! = "number \(self.indexPath.row)"
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = CollectionData.dequeueReusableCell(withReuseIdentifier: "CellData", for: indexPath) as! CollectionViewCellData
send = indexPath.row
CollectionData.reloadData()
}
}
I am only printing if the value is not nil! Let me know if you have more questions, or let us know if my solution is not working. =)