Collection View inside Table View Cell not being called - ios

I am trying to implement a collection view inside a table view cell.
My table view cell is a xib, and I've dragged a collection view into it.
Then, I created a class and xib for the collection view cell:
class MyCollectionViewCell: UICollectionViewCell {
var media: Image?
#IBOutlet weak var imageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func initialize(media: PostImage) {
self.media = media
if let url = media.url {
imageView.kf.setImage(with: URL(string: url))
}
}
}
And I've given the xib the class "MyCollectionViewCell" and also given it the identifier "MyCollectionViewCell".
Then, in my table view cell class, I have done the following:
class MyTableViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
var post: Post!
#IBOutlet weak var title: UILabel!
#IBOutlet weak var mediaCollectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
mediaCollectionView.delegate = self
mediaCollectionView.dataSource = self
let mediaCollectionViewCell = UINib(nibName: "MyCollectionViewCell", bundle: nil)
mediaCollectionView.register(mediaCollectionViewCell, forCellWithReuseIdentifier: "MyCollectionViewCell")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCollectionViewCell", for: indexPath as IndexPath) as? MyCollectionViewCell else {
fatalError("The dequeued cell is not an instance of MyCollectionViewCell.")
}
let media = post.images[indexPath.row]
cell.initialize(media: media)
return cell
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func initialize(post: Post) {
self.post = post
title.text = post.title
self.mediaCollectionView.reloadData()
}
}
The problem is, the collection view never shows when I run this. The title label text shows fine, but the collection view does not show, and I don't know what I'm doing wrong.
cellForItemAt doesn't even seem to get called, because when I add print("hello") at the top of the function, it never shows up in the console.
What am I doing wrong?

I think the problem is the height of the collection view is very small that it isn't shown.
Try to set the height for the table view cell:
func tableView(_: UITableView, heightForRowAt _: IndexPath) -> CGFloat {
return 100
}
where the 100 should be bigger than the collection view

Related

Reuse item inside a row when scrolling

I have collectionView inside tableView. collectionView need to horizontal scroll image, tableView for vertical scroll posts. When I had 3 rows I had no problems, but when i create 4 rows i have a problem with scrolling items inside rows. If I start scrolling on 4 row, scrolling is repeated on row 1 and the same thing if i start scrolling on 1 row scrolling is repeating on row 4.
What could be the problem and how to solve it? May be
Can check .gif file. I start on 1 row on name "Oko" and if i scrolling down on 4 row and scroll right collectionCell and return on 1 row i see next image name "City", but there must be name "Oko"
My code:
ViewController:
class PhotoStudiosViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating {
#IBOutlet weak var tableView: UITableView!
var theStudios: [Studio] = []
var filteredStudios: [Studio] = []
var studiosRef: DatabaseReference!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
tableView.estimatedRowHeight = 475
tableView.rowHeight = UITableViewAutomaticDimension
}
override func viewDidLoad() {
super.viewDidLoad()
studiosRef = Database.database().reference(withPath: "PhotoStudios1")
studiosRef.observe(.value, with: { (snapshot) in
for imageSnap in snapshot.children {
let studioObj = Studio(snapshot: imageSnap as! DataSnapshot)
self.theStudios.append(studioObj)
}
self.tableView.reloadData()
})
}
// MARK: - TableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.isActive && searchController.searchBar.text != "" {
return filteredStudios.count
}
return theStudios.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! PhotoStudiosTableViewCell
cell.currentPageNumber.text = "1/\(theStudios[indexPath.row].halls.count)"
if searchController.isActive && searchController.searchBar.text != nil {
cell.theHalls = filteredStudios[indexPath.row].halls
} else {
cell.theHalls = theStudios[indexPath.row].halls
}
cell.nameLabel.text = theStudios[indexPath.row].studioName
cell.addressLabel.text = theStudios[indexPath.row].studioAddress
cell.logoLabel.sd_setImage(with: URL(string: theStudios[indexPath.row].studioLogo))
cell.didSelectAction = {
(innerPath) in
self.showDetailsView(indexPath, cellPath: innerPath)
}
return cell
}
TableViewCell:
class PhotoStudiosTableViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UIScrollViewDelegate, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var button: UIButton!
#IBOutlet weak var logoLabel: UIImageView!
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var addressLabel: UILabel!
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var currentPageNumber: UILabel!
var didSelectAction: ((IndexPath) -> ())?
var theHalls: [Hall] = [] {
didSet {
collectionView.reloadData()
}
}
var lastContentOffset = CGPoint.zero
override func prepareForReuse() {
super.prepareForReuse()
resetCollectionView()
}
override func awakeFromNib() {
super.awakeFromNib()
currentPageNumber.layer.zPosition = 2
currentPageNumber.layer.cornerRadius = 15.0
currentPageNumber.clipsToBounds = true
}
func resetCollectionView() {
guard !theHalls.isEmpty else { return }
theHalls = []
collectionView.reloadData()
}
// MARK: - CollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return theHalls.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath) as! PhotoStudiosCollectionViewCell2
cell.hallName.text = theHalls[indexPath.item].hallName
cell.priceLabel.text = theHalls[indexPath.item].hallPrice
cell.metrslabel.text = theHalls[indexPath.item].hallMetrs
cell.photoStudioImage.sd_setImage(with: URL(string: theHalls[indexPath.item].hallImage))
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
didSelectAction?(indexPath)
}
}
You're reusing the collection views in your cells, which is correct, but that means the contentOffset is also left from whatever was scrolled to previously when a cell is reused. It should be sufficient to just reset the contentOffset in cellForRowAtIndexPath when you are setting up your cell by doing something like:
cell.collectionView.contentOffset = .zero
One thing worth mentioning is that I do see you have a property called lastContentOffset in your cells that doesn't do anything yet and I suspect you are going to try to use that to persist the offset for a given cell when it scrolls out of view so that you can set it again when it comes back into view (rather than always resetting).
If you are going to do that, having the property in the cell won't work. You'll need to have a list of offsets for each cell stored alongside your data models in the containing view controller. Then you might save the offset for a given cell in didEndDisplayingCell and setting it in cellForRowAtIndexPath instead of .zero as I did above.

How to handle button touch inside the UICollectionviewCell or UITableViewCell

This is a problem that I always stay in dilemma when I creating cells.
Let's say I have a custom cell (PlaceCell) which I'm using in different controllers and collectionviews. It has a label which identify the place name (PlaceNameLabel) and will navigate to place detail when user taps on it.
This doesn't matter controller, collectionviews or wherever cell is used, this is independent of where it is used.
So I have to put the PlaceNameLabel's UITapGestureRecognizer code inside the PlaceCell class.
class PlaceCell: UICollectionViewCell {
#IBOutlet weak var placeName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initEventListeners()
}
func initEventListeners() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handlePlaceNameTouch))
}
func handlePlaceNameTouch() {
// I have to push a new view controller here
}
}
But if I want to push the place detail view controller I need to access the controller. If I want to access the controller I have two options and this is where I stay in dilemma, I have read lots of SO questions answers most of them suggest the second option, but I think the first one is better approach. But I don't know if it's problem to reference the controller inside the cell.
Could you please share your opinion or any other method to handle this problem?
FIRST OPTION
Referencing the controller inside the cell,
extension MyController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PlaceCell", for: indexPath) as! PlaceCell
cell.controller = self
return cell
}
}
class PlaceCell: UICollectionViewCell {
var controller: UIViewController?
#IBOutlet weak var placeName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initEventListeners()
}
func initEventListeners() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handlePlaceNameTouch))
}
func handlePlaceNameTouch() {
controller.navigationController.pushViewController(PlaceDetailController(),
animated: true)
}
}
SECOND OPTION
Create protocol and delegate, pass event to controller and do whatever you want,
(I think this is not well, because action is about the cell and I have to create protocol function multiple times because I use this Cell in different Controllers)
protocol PlaceCellDelegate {
func handlePlaceNameTouch()
}
class PlaceCell: UICollectionViewCell {
var delegate: PlaceCellDelegate?
#IBOutlet weak var placeName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initEventListeners()
}
func initEventListeners() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handlePlaceNameTouch))
}
func handlePlaceNameTouch() {
delegate?.handlePlaceNameTouch()
}
}
extension MyController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, PlaceCellDelegate {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PlaceCell", for: indexPath) as! PlaceCell
cell.delegate = self
return cell
}
func handlePlaceNameTouch() {
self.navigationController.pushViewController(PlaceDetailController(), animated: true)
}
}
You no need to handle specially to cell selection. No need to use UITapGestureRecognizer or no need implement your own protocol to detect cell selection.
UICollectionView and UITableView has its own protocols for that.
Cell selection delegate for UICollectionView - UICollectionViewDelegate protocol
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
Cell selection delegate for UITableView - UITableViewDelegate protocol
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
Confirm protocol & set delegate on your UIViewController
class viewcontroller : UICollectionViewDelegate {
#IBOutlet weak collectionView: UICollectionView!
func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
}
}
And implement the protocol method inside a view controller, which I mentioned above.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//indexPath - Index path of selected cell.
// Add you cell selection logic here.
}
This method will be triggered when you tap on the cell. Inside this method fetch the model from datasource array. and navigate to detail view based on which cell (model) selected by user.
While both your options are possible, if you are hesitating I would recommend the delegate approach as it is a more "swifty" way of doing it and makes the cell reusable.
Here is a third option using an onTapHandler which doesn't use the delegate pattern and still keeps the cell reusable:
class PlaceCell: UICollectionViewCell {
// A handler called when the button is pressed
var onTapHandler: (() -> Void)?
#IBOutlet weak var placeName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initEventListeners()
}
func initEventListeners() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handlePlaceNameTouch))
}
func handlePlaceNameTouch() {
// Make sure the handler exists, else...
guard let handler = self.onTapHandler else {
return
}
// Execute handler
handler()
}
}
You would then use it like so:
extension MyController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, PlaceCellDelegate {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PlaceCell", for: indexPath) as! PlaceCell
cell.onTapHandler = { [weak self] in
self?.navigationController.pushViewController(PlaceDetailController(), animated: true)
}
return cell
}
}

Not using reusable cell in UITableView with CollectionView in each cell

I have a UITableView and in its prototype cell have a UICollectionView.
MainViewController is delegate for UITableView and
MyTableViewCell class is delegate for UICollectionView.
On updating each TableViewCell contents I call cell.reloadData() to make the collectionView inside the cell reloads its contents.
When I use reusable cells, as each cell appears, it has contents of the last cell disappeared!. Then it loads the correct contents from a URL.
I'll have 5 to 10 UITableViewCells at most. So I decided not to use reusable cells for UITableView.
I changed the cell creation line in tableView method to this:
let cell = MyTableViewCell(style: .default, reuseIdentifier:nil)
Then I got an error in MyTableViewCell class (which is delegate for UICollectionView), in this function:
override func layoutSubviews() {
myCollectionView.dataSource = self
}
EXC_BAD_INSTRUCTION CODE(code=EXC_I386_INVOP, subcode=0x0)
fatal error: unexpectedly found nil while unwrapping an Optional value
MyTableViewCell.swift
import UIKit
import Kingfisher
import Alamofire
class MyTableViewCell: UITableViewCell, UICollectionViewDataSource {
struct const {
struct api_url {
static let category_index = "http://example.com/api/get_category_index/";
static let category_posts = "http://example.com/api/get_category_posts/?category_id=";
}
}
#IBOutlet weak var categoryCollectionView: UICollectionView!
var category : IKCategory?
var posts : [IKPost] = []
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
if category != nil {
self.updateData()
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func layoutSubviews() {
categoryCollectionView.dataSource = self
}
func updateData() {
if let id = category?.id! {
let url = const.api_url.category_posts + "\(id)"
Alamofire.request(url).responseObject { (response: DataResponse<IKPostResponse>) in
if let postResponse = response.result.value {
if let posts = postResponse.posts {
self.posts = posts
self.categoryCollectionView.reloadData()
}
}
}
}
}
internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "postCell", for: indexPath as IndexPath) as! MyCollectionViewCell
let post = self.posts[indexPath.item]
cell.postThumb.kf.setImage(with: URL(string: post.thumbnail!))
cell.postTitle.text = post.title
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//You would get something like "model.count" here. It would depend on your data source
return self.posts.count
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
}
MainViewController.swift
import UIKit
import Alamofire
class MainViewController: UITableViewController {
struct const {
struct api_url {
static let category_index = "http://example.com/api/get_category_index/";
static let category_posts = "http://example.com/api/get_category_posts/?category_id=";
}
}
var categories : [IKCategory] = []
override func viewDidLoad() {
super.viewDidLoad()
self.updateData()
}
func updateData() {
Alamofire.request(const.api_url.category_index).responseObject { (response: DataResponse<IKCategoryResponse>) in
if let categoryResponse = response.result.value {
if let categories = categoryResponse.categories {
self.categories = categories
self.tableView.reloadData()
}
}
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return self.categories.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.categories[section].title
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionHolderTableViewCell") as! MyTableViewCell
let cell = MyTableViewCell(style: .default, reuseIdentifier:nil)
cell.category = self.categories[indexPath.section]
cell.updateData()
return cell
}
}
MyCollectionViewCell.swift
import UIKit
class MyCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var postThumb: UIImageView!
#IBOutlet weak var postTitle: UILabel!
var category : IKCategory?
}
Why not reusing cells caused this? Why am I doing wrong?
There are a few things to do that should get you up to speed.
First, uncomment the line that uses reusable cells and remove the line of code that creates the non-reusable cells. It is safe to use reusable cells here.
Second, in MyTableViewCell, set the dataSource for the collection view right after the super.awakeFromNib() call. You only need to set the dataSource once, but layoutSubviews() will potentially get called multiple times. It's not the right place to set the dataSource for your needs.
override func awakeFromNib() {
super.awakeFromNib()
categoryCollectionView.dataSource = self
}
I have removed the call to updateData() from awakeFromNib(), as you are already calling it at cell creation. You can also delete the layoutSubviews() override, but as a general rule, you should be careful to call super.layoutSubviews() when overriding it.
Lastly, the reason the posts seemed to re-appear in the wrong cells is that the posts array wasn't being emptied as the cells were reused. To fix this issue, add the following method to MyTableViewCell:
func resetCollectionView {
guard !posts.isEmpty else { return }
posts = []
categoryCollectionView.reloadData()
}
This method empties the array and reloads your collection view. Since there are no posts in the array now, the collection view will be empty until you call updateData again. Last step is to call that function in the cell's prepareForReuse method. Add the following to MyTableViewCell:
override func prepareForReuse() {
super.prepareForReuse()
resetCollectionView()
}
Let me know how it goes!

Use CollectionView methods from another swift file

I'd like to use a CollectionView methods from another swift file instead of it's ViewController for some reason.
I have this in my ViewController:
#IBOutlet weak var collectionView: UICollectionView!
var broadcastColletionView = BroadcastCollectionView()
override func viewDidLoad() {
super.viewDidLoad()
broadcastColletionView = BroadcastCollectionView(eventItems: eventItems,collectionView: collectionView, broadastObject: broadastObject)
collectionView.dataSource = broadcastColletionView
collectionView.delegate = broadcastColletionView
}
And I have BroadcastCollectionView.swift which contains the CollectionView delegate methods:
class BroadcastCollectionView: NSObject,UICollectionViewDelegate, UICollectionViewDataSource {
var eventItems = [Eventtype]()
var alreadyChecked: Bool = false
var cellHistory: IndexPath = []
var collectionView: UICollectionView!
var broadastObject = Broadcast()
init(eventItems: [Eventtype],collectionView: UICollectionView,
broadastObject: Broadcast) {
self.eventItems = eventItems
self.collectionView = collectionView
self.broadastObject = broadastObject
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return eventItems.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "brCollectionView", for: indexPath) as! BroadcastCollectionViewCell
self.collectionView = collectionView
cell.eventImage.image = eventItems[indexPath.row].image
cell.eventType = eventItems[indexPath.row]
let tap = UITapGestureRecognizer(target: self, action: #selector(collectionViewTapped))
tap.numberOfTapsRequired = 1
cell.addGestureRecognizer(tap)
return cell
}
#objc func collectionViewTapped(sender: UITapGestureRecognizer) {
if let indexPath = self.collectionView?.indexPathForItem(at: sender.location(in: self.collectionView)) {
let cell : BroadcastCollectionViewCell = collectionView.cellForItem(at: indexPath)! as! BroadcastCollectionViewCell
print("item index")
} else {
print("collection view was tapped")
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("selected row is",indexPath.row)
}
I don't really understand why the delegate methods not called if I setted the collectionView.delegate and dataSource to the BroadcastCollactionViewclass. Please don't make me explain why would I like to separate this CollectionView it's not part of the question.
After setting datasource and delegate for the collection view in viewDidLoad() method, reload the collection view:
collectionView.reloadData()
This another class that you created is called CustomDataSource you can find a tutorial here
Try calling
collectionView.reloadData() after setting the dataSource and delegate.
and Make sure eventItems is not empty.
Hope it Helps!
Apart from the issue of not working in your case which could be due to not configuring the collection view properly which can be resolved using the answers you got above from other users, There is an approach for your question of "Use CollectionView methods from another swift file"
You can make use of the concept called "extension", I will explain you how.
Create a new class for handling the collection view methods as follows,
class MyDataSource: NSObject {
var eventItems: Array<Any>?
init(events: Array<Any>?) {
self.eventItems = events
}
}
extension MyDataSource: UITableViewDataSource, UITableViewDelegate {
// MARK: - Table view data source methods
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CellIdentifier")
return cell
}
// Add additional data source methods & delegate methods as per your need
// MARK: - Table view delegate methods
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Perform your action
// Use delegate methods(protocols) to do your actions from the viewController class
}
}
And in the viewController file assign the datasource & delegate method for collection view as follows,
class ViewController: UIViewController {
var datasource: MyDataSource?
override func viewDidLoad() {
super.viewDidLoad()
// Initialize datasource & delegate for collectionView with the extension datasource
datasource = MyDataSource(events: EVENTITEMS_ARRAY)
collectionView?.dataSource = datasource
collectionView?.delegate = datasource
}
}
NOTE
Update the data types & collection view properties like cell identifier as per your need.

How to use collection view buttons to select view controllers in swift

I have a CollectionViewController with 3 buttons populated. The view works well, but how do I select different view controllers based on the button selected? I added the button as an action, but I don't know how to specify which button is selected so I can send the user to different viewcontrollers.
import UIKit
private let reuseIdentifier = "Cell"
class CollectionViewController: UICollectionViewController {
var imageArray = [UIImage(named: "tempOwl.png"), UIImage(named: "tempPuzzle.png"), UIImage(named: "tempHouse.png")]
override func viewDidLoad() {
super.viewDidLoad()
self.clearsSelectionOnViewWillAppear = false
self.collectionView!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
}
#IBAction func menuButton(sender: UIButton) {
let controller = storyboard?.instantiateViewControllerWithIdentifier("myHome")
presentViewController(controller!, animated: true, completion: nil)
}
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as UICollectionViewCell
let imageView = cell.viewWithTag(1) as! UIButton
imageView.setBackgroundImage(self.imageArray[indexPath.row], forState: .Normal)
return cell
}
}
The button action method for your button in cell
func buttonAction(sender : UIButton) {
var selectedButtonCell = sender.superview as! UICollectionViewCell
//Incase your button is inside cell.contentview
// var selectedButtonCell = sender.superview.superview as! UICollectionviewCell
var indexPath = collectionView.indexPathForCell(selectedButtonCell)
if indexPath.row == 0 {
//Button in first cell is selected
//Send user to first button view controller
}
}
I suggest to create a class of type UICollectionViewCell and create the IBAction in the cell.
And set the collectionViewController as delegate. So you can pass values.
So you can create a function in the collection view controller and give it a param like a int 1 for cell 1.
If you have multiple buttons in the cell you should implement a delegate. Then, set your view controller as a delegate of the cell. Sample implementation of such a delegate could look like:
protocol YourCustomCellDelegate {
func firstButtonPressed(cell: YourCustomCell)
func secondButtonPressed(cell: YourCustomCell)
}
class YourCustomCell : UICollectionViewCell {
var delegate:YourCustomCellDelegate?
#IBOutlet weak var firstButton: UIButton!
#IBOutlet weak var secondButton: UIButton!
#IBAction func firstButtonTapped(sender: AnyObject) {
delegate?.firstButtonPressed(self)
}
#IBAction func secondButtonTapped(sender: AnyObject) {
delegate?.secondButtonPressed(self)
}
}

Resources