How can I put 2 collectionViews in a single ViewController? - ios

I have this code to make a UICollectionView with in another ViewController:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tvSeries.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let identifier = "Item"
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! SeriesCollectionViewCell
cell.itemLabel.text = tvSeries[indexPath.row]
cell.itemImage.image = UIImage.init(imageLiteralResourceName: tvSeries[indexPath.row])
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let item = sender as? UICollectionViewCell
let indexPath = collectionView.indexPath(for: item!)
let detailVC = segue.destination as! DetailViewController
detailVC.detailName = tvSeries[(indexPath?.row)!]
}
I want to have a ViewController with 2 CollectionViews like in this picture:

In your collectionView functions such as numberOfItemsInSection, check if the collectionView argument is equal to one or the other collection view and then return the number as required.
For example, if you had the following IBOutlets:
#IBOutlet weak var collectionViewOne: UICollectionView!
#IBOutlet weak var collectionViewTwo: UICollectionView!
then your numberOfItemsInSection would change to:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == collectionViewOne {
return itemSource1.count
}
else {
return itemSource2.count
}
}
Do the same for the rest of the collectionView functions.

Related

Collectionview rows showing wrongly with JSON data in swift

I am using collectionview in tableview cell
class CategoryNewVC: UIViewController {
#IBOutlet weak var categoryTableview: UITableView!
public var activeCategories : Array<Category_json>?
override func viewDidLoad() {
super.viewDidLoad()
self.activeCategories = homeData?.result?.category_json?.filter({ (item) -> Bool in
return item.status == "A"
})
categoryTableview.reloadData()
}
this is the code for tableview and collectionview
extension CategoryNewVC : UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.activeCategories?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryNewTableCell", for: indexPath) as! CategoryNewTableCell
let indexData = self.activeCategories?[indexPath.row]
cell.catNameLbl.text = indexData?.details?.first?.title
cell.activeCategories = self.activeCategories
cell.clcSeller.reloadData()
return cell
}
}
class CategoryNewTableCell: UITableViewCell,UICollectionViewDelegate,UICollectionViewDataSource{
#IBOutlet weak var catNameLbl: UILabel!
#IBOutlet weak var clcSeller: UICollectionView!
public var activeCategories : Array<Category_json>?
override func awakeFromNib() {
super.awakeFromNib()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.activeCategories?[section].sub_categories?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SubCatCollectionCell", for: indexPath) as! SubCatCollectionCell
let activesubCat = self.activeCategories?[indexPath.section].sub_categories
let indexData = activesubCat?[indexPath.item]
cell.lblTitle.text = langType == .en ? indexData?.details?.first?.title : indexData?.details?[1].title
return cell
}
}
with the above code i am getting number of rows for tableview is correct, but in collectionview numberOfItemsInSection coming wrong.. here in every section it showing only first section values in collectionview.. why?
please do help with the code
In the CategoryNewTableCell, you need to make following changes -
public var subCategories : Array<..>? // Array of your subcategories for a particular tableViewCell
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.subCategories?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SubCatCollectionCell", for: indexPath) as! SubCatCollectionCell
// Change here
let subCategory = self.subCategories?[indexPath.item]
cell.lblTitle.text = langType == .en ? subCategory?.details?.first?.title : subCategory?.details?[1].title
return cell
}
Finally you need to pass subCategories to your tableViewCell like this - from cellForRow implementation -
cell.subCategories = indexData?.sub_categories

How to pass collectionview cells index value to nextviewcontroller(using push navigation) in swift

I am using collectionview in tableview cell,
i need to pass selected collectionview cells value to next viewcontroller, how?
code: here is the code for tableview and collectionview cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryNewTableCell", for: indexPath) as! CategoryNewTableCell
let indexData = self.activeCategories?[indexPath.row]
cell.selectionStyle = .none
cell.catNameLbl.text = indexData?.details?.first?.title
cell.subCategories = indexData?.sub_categories
cell.clcSeller.reloadData()
}
class CategoryNewTableCell: UITableViewCell,UICollectionViewDelegate,UICollectionViewDataSource{
#IBOutlet weak var clcSeller: UICollectionView!
public var subCategories : Array<Sub_categories>?
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return subCategories?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SubCatCollectionCell", for: indexPath) as! SubCatCollectionCell
let subCategory = self.subCategories?[indexPath.item]
cell.lblTitle.text = langType == .en ? subCategory?.details?.first?.title : subCategory?.details?[1].title
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = StoryBoard.main.instantiateViewController(withIdentifier: "SearchResultVC") as! SearchResultVC
vc.subCatId = sub_categories?[indexPath.row].slug ?? ""
self.navigationController?.pushViewController(vc, animated: true)
}
}
here if i use didSelectItemAt for collectionview to send its selected cell value to next view controller
error:
Value of type 'CategoryNewTableCell' has no member 'navigationController'
if i give button action in main class then able to push but value is not going
class CategoryNewVC: UIViewController {
#IBAction func didselectcollectionviewBTn(_ sender: UIButton) {
let vc = StoryBoard.main.instantiateViewController(withIdentifier: "SearchResultVC") as! SearchResultVC
vc.subCatId = //here how to pass value
self.navigationController?.pushViewController(vc, animated: true)
}
}
here how to pass selected collectionview cells value to SearchResultVC please do help
EDIT
according to below answer i have added: still didSelectItemAt not called, why plz do help
class CategoryNewTableCell: UITableViewCell,UICollectionViewDelegate,UICollectionViewDataSource{
override func awakeFromNib() {
super.awakeFromNib()
self.clcSeller.delegate = self
self.clcSeller.dataSource = self
//
You can use protocol to send data to your nextviewcontroller.
protocol CategorySelectionDelegate {
func get(category: Sub_categories)
}
Declare the delegate in your CategoryNewTableCell and use it in didSelectItemAt method of your collectionviewcell like below:
class CategoryNewTableCell:
UITableViewCell,UICollectionViewDelegate,UICollectionViewDataSource{
#IBOutlet weak var clcSeller: UICollectionView!
public var subCategories : Array<Sub_categories>?
var delegate: CategorySelectionDelegate?
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return subCategories?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SubCatCollectionCell", for: indexPath) as! SubCatCollectionCell
let subCategory = self.subCategories?[indexPath.item]
cell.lblTitle.text = langType == .en ? subCategory?.details?.first?.title : subCategory?.details?[1].title
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
delegate?.get(category: sub_categories?[indexPath.row])
}
}
Adopt the protocol in the receiving class
class CategoryNewVC: UIViewController, CategorySelectionDelegate {
func get(category: Sub_categories) {
let vc = StoryBoard.main.instantiateViewController(withIdentifier: "SearchResultVC") as! SearchResultVC
vc.subCatId = category.slug ?? ""
self.navigationController?.pushViewController(vc, animated: true)
}
}
Declare a callback in the tableViewCell subclass.
class CategoryNewTableCell: UITableViewCell {
var onSelectSubcategory: ((_ subcategoryID: String) -> Void)?
}
Assign this callback in your cellForRow like this.
cell.subCategories = indexData?.sub_categories
cell.onSelectSubcategory = { [weak self] (subcategoryID) in
let vc = StoryBoard.main.instantiateViewController(withIdentifier: "SearchResultVC") as! SearchResultVC
vc.subCatId = subcategoryID
self?.navigationController?.pushViewController(vc, animated: true)
}
Invoke this callback from collectionView didSelectItem like this.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let subcategoryID = sub_categories?[indexPath.item].slug ?? ""
self.onSelectSubcategory?(subcategoryID)
}

collection view arrays tied to index

Im making a three view controller project with the first two views are collectionViews. The selected cell will load second view controller with segue and another array depending on which index was selected on first main view. Can anyone point me in the right direction on how to tie a data to load in the second collection view.
import UIKit
class ViewController: UIViewController {
#IBOutlet private weak var collectionView: UICollectionView!
var collectionData = ["cell1", "cell2", "cell3", "cell4", "cell5", "cell6", "cell7", "cell8"]
override func viewDidLoad() {
super.viewDidLoad()
let height = (view.frame.size.width / 2.76)
let width = view.frame.size.width / 1
let layout = collectionView.collectionViewLayout as!
UICollectionViewFlowLayout
layout.itemSize = CGSize(width: width, height: height)
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return collectionData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath)
if let label = cell.viewWithTag(100) as? UILabel {
label.text = collectionData[indexPath.row]
}
return cell
}
didSelectItemAt indexPath: IndexPath) {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "BannerSegue" {
if let _ = segue.destination as? BannerSelection, let _ = sender as? IndexPath {
}
}
}
}
that is the main view controller. then it has a segue to this view
import UIKit
class BannerSelection: UIViewController {
#IBOutlet weak var collection2: UICollectionView!
var BannerData = ["bannerA1", "bannerA2", "bannerA3", "bannerA4", "bannerA5", "bannerA6", "bannerA7", "bannerA8", "bannerA9", "bannerA10", "bannerA11", "bannerA12"]
var selection: String!
override func viewDidLoad() {
super.viewDidLoad()
let height = (view.frame.size.width / 3.76)
let width = view.frame.size.width / 1
let layout = collection2.collectionViewLayout as!
UICollectionViewFlowLayout
layout.itemSize = CGSize(width: width, height: height)
}
}
extension BannerSelection: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return BannerData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let bannercell = collectionView.dequeueReusableCell(withReuseIdentifier: "BannerSelectionCell", for: indexPath)
if let label = bannercell.viewWithTag(1) as? UILabel {
label.text = BannerData[indexPath.row]
}
return bannercell
}
func collectionView(_ BannerSelection: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
}
So what im trying to achieve is let's say... index 2 to have an array of "bannerB1, bannerB2" so on and so forth. then i will apply the same technique for the second view controller to populate the final view with a end UIImage. Thank you in advanced!
You can store the data of the first view in the UserDefaults and then retrieve the first vc's data from the second view and load them
As your data Structure is unclear to me, Seems like your data is a dictionary of array like that
dict = [
"cell1" : [Banner1, Banner2,..]
"cell2" : [Apple1, Apple2, ..]
//so on
]
What is the structure of your data structure, let it to be saved in UserDefaults.
UserDefaults.standard.setValue(dict, forKey: "myDataStructure")
while retrieve in second view controller
let array = dict["cell1"] as? Array<String> // depends on the data structure
and populate your viewController.

Transferring Data from CollectionView inside TableView to a New ViewController

So I have a main ViewController that has Horizontal Scrolling CollectionViews inside a TableView. When you click on an Item in the CollectionView it transfers all the data from the Item to a new ViewController to display it properly.
The problem I am facing is when you click on the item in the CollectionView a segue is performed that transfers data to an array in the new ViewController but instead of transferring only data from the particular item it send data from more than one item. On some debugging I also found that the items Custom class is what loads the multiple elements in the array and not the segue. Here is some code.
cellForRowAt in main VC
if let cell = tableView.dequeueReusableCell(withIdentifier: "HeadlineRow", for: indexPath) as? HeadlineRow {
cell.latest = self.latest
cell.collectionView.reloadData()
cell.delegate = self
return cell
}
Segue Code in main VC
func pushToNewsVC(latestNews: [LatestNews]) {
self.transferToNewsVC = latestNews
performSegue(withIdentifier: "NewsVC", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "NewsVC" {
if let destination = segue.destination as? NewsVC {
destination.latestNews.append(contentsOf: self.transferToNewsVC)
destination.SuggestedLatestNews.append(contentsOf: self.latest)
}
}
}
Headlinerow which is TableViewCell class
var latest = [LatestNews]()
var transferData = [LatestNews]()
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return latest.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HeadlineCell", for: indexPath) as? HeadlineCell {
let latest = self.latest[indexPath.row]
cell.updateUI(latest: latest)
return cell
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) as? HeadlineCell {
self.transferData.removeAll()
self.transferData = cell.transferData
delegate?.pushToNewsVC(latestNews: self.transferData)
}
}
HeadlineCell which is CollectioViewCell class
var transferData = [LatestNews]()
func updateUI(latest: LatestNews) {
storyTextView.text = latest.headline
self.thumbnail.sd_setImage(with: URL(string: "\(latest.app_img)"))
self.transferData.append(latest)
}

Type does not conform to protocol Swift

Started practicing Swift. In singleViewController I am trying to make a UICollectionView. In storyboard I set the dataSource and delegate. Here I am getting the error:
'UICollectionView' does not conform to protocol 'UICollectionViewDataSource'
import UIKit
class galeriacontroler: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource{
#IBOutlet weak var collectionview: UICollectionView!
let fotosgaleria = [UIImage(named: "arbol3"), UIImage(named:"arbol4")]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.fotosgaleria.count
}
func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cellImagen", forIndexPath:indexPath) as! cellcontroler
cell.imagenView2?.image = self.fotosgaleria[indexPath.row]
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("showImage", sender: self )
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showImage"
{
let indexPaths = self.collectionview!.indexPathsForSelectedItems()
let indexPath = indexPaths![0] as NSIndexPath
let vc = segue.destinationViewController as! newviewcontroler
vc.image = self.fotosgaleria[indexPath.row]!
}
}
}
UICollectionViewDataSource has two required methods -
collectionView(_:numberOfItemsInSection:) and collectionView(_:cellForItemAtIndexPath:), of which you have implemented only one.
You need to add an implementation for collectionView(_:cellForItemAtIndexPath:) to fix this problem:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath:NSIndexPath)->UICollectionViewCell {
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("MyCell", forIndexPath: indexPath) as CollectionCell
... // Do more configuration here
return cell
}
When you import UICollectionViewDataSource you must implement cellForItemAtIndexPath method
Add the following method to your code:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath:NSIndexPath)->UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("imagesCellIdentifier", forIndexPath:indexPath) as! cellcontroler
cell.secondImageView?.image = self.photosGalleryArray[indexPath.row]
return cell
}
willDisplayCell is not necessary to implement after this.

Resources