UICollectionViewCell not receiving tap event, even with cancelsTouchesInView set to false - ios

I have done some research into this because I have noticed that my custom cells are not receiving the tap event. I have an NSLog that is in place to debug when the cell has been tapped. My problem though is that the cell only receives the event on a long press. When I did some more research I found that creating a reference to the UITapGestureRecognizer and setting cancelsTouchesInView to false. After doing this it still does not receive the event except on a long press. The only UITapGestureRecognizer in the view is one set so that when the user taps outside of the menu it dismisses the menu. Have I done something incorrectly? I mean for a good UX the user shouldn't need to hold the menu option for 4-5 seconds. Here is the code:
class MenuViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource
{
#IBOutlet var menuCollectionView: MenuCollectionView!
#IBOutlet var profileViewController: ProfileViewController!
#IBOutlet var menuTapGestureRecognizer: MenuTapGestureRecognizer!
#IBAction func handleTap(sender: UITapGestureRecognizer)
{
if (sender.state == .Ended)
{
self.dismissViewControllerAnimated(true, completion: nil)
}
}
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view
self.menuCollectionView.dataSource = self
self.menuCollectionView.delegate = self
menuTapGestureRecognizer.cancelsTouchesInView = false
}
// Variables
var menuImagesArray = ["MyProfileIcon.png"]
// Data Source Protocol
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return menuImagesArray.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
var menuCell: MenuCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("MenuCell", forIndexPath: indexPath) as MenuCollectionViewCell
var image: UIImage! = UIImage(named: menuImagesArray[indexPath.row])
menuCell.imageView.image = image
return menuCell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
NSLog("Pressed Cell")
}
}

Related

Can't understand how to perform Segue from my custom Cell (in UICollectionView) to Player (ViewController) [duplicate]

This question already has answers here:
passing tapped cell data to another view via segue in Swift
(2 answers)
Pass data through segue
(3 answers)
Closed 8 months ago.
Hi dear professionals.
I have main ViewController, where I put Three horizontal CollectionView with cells into (but I hope at least solve problem with 1 of these).
One of this named - FirstPlaylistCollectionView
Cells also custom - FirstPlaylistCollectionViewCell
On tap on cell with specific video it needed pass Video object to the Player (PlayerViewController).
I cant figure it out how, in my case, make this Segue (pass Video object with necessary data) from CollectionView by code !
I almost don't use Storyboard in this project.
Maybe with help of Delegate, but I'm also couldn't understand how to use them for my case.
Method didSelectItemAt - works and get Video object, but i don't understand how to pass it correctly.
Will be very grateful for answer. I couldn't apply for now any solution from Stack, help please.
FirstPlaylistCollectionView code
import UIKit
protocol FirstPlaylistCollectionViewDelegate: AnyObject {
func playVideo()
}
class FirstPlaylistCollectionView: UICollectionView, UICollectionViewDelegate, UICollectionViewDataSource, ModelDelegate {
var playlistsModel = PlaylistsModel()
private var firstPlaylist: [Video] = []
weak var delegate2: FirstPlaylistCollectionViewDelegate?
// MARK: - Data Source
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return firstPlaylist.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = dequeueReusableCell(withReuseIdentifier: FirstPlaylistCollectionViewCell.reuseId, for: indexPath) as! FirstPlaylistCollectionViewCell
let video = self.firstPlaylist[indexPath.row]
cell.setCell(video)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.delegate2?.playVideo()
print("selected video \(firstPlaylist[indexPath.row]) with \(collectionView)! DONE!")
}
FirstPlaylistCollectionViewCell code
class FirstPlaylistCollectionViewCell: UICollectionViewCell {
static let reuseId = "FirstPlaylistCollectionViewCell"
var video: Video?
PlayerViewController code
import UIKit
import WebKit
class PlayerViewController: UIViewController {
#IBOutlet weak var handleArea: UIView!
#IBOutlet weak var openCloseArrow: UIImageView!
var video: Video?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("I'm here!!!")
let vc2 = segue.destination as! PlayerViewController
if let cell = sender as? Video {
self.video = cell
vc2.titleOfVideoLabel.text = video?.title
}
}
}
extension PlayerViewController: FirstPlaylistCollectionViewDelegate {
func playVideo() {
performSegue(withIdentifier: "homeToPlayer", sender: self)
}
}
Answering this by assuming some of the things, I hope you want to navigate to PlayerViewController from ViewController through a segue. Keeping that in my mind, I have assumed your FirstPlaylistCollectionView is in your ViewController class as mentioned below.
class ViewController: UIViewController {
var firstPlaylistCollectionView: FirstPlaylistCollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// First try to get notified from your collection list to here
// and then from here to your player
firstPlaylistCollectionView.listDelegate = self
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
if let id = segue.identifier, id == "playerSegue",
let lVideo = sender as? Video,
let destination = segue.destination as? PlayerViewController{
destination.video = lVideo
}
}
}
extension ViewController: FirstPlaylistCollectionViewDelegate {
func firstPlaylistCollectionView(_ listView: FirstPlaylistCollectionView, didSlect video: Video) {
self.performSegue(withIdentifier: "playerSegue", sender: video)
}
}
And below is the update for the collection view
class FirstPlaylistCollectionView: UICollectionView {
var playlistsModel = PlaylistsModel()
private var firstPlaylist: [Video] = []
weak var listDelegate: FirstPlaylistCollectionViewDelegate?
}
extension FirstPlaylistCollectionView: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return firstPlaylist.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = dequeueReusableCell(withReuseIdentifier: FirstPlaylistCollectionViewCell.reuseId, for: indexPath) as! FirstPlaylistCollectionViewCell
/* Here it goes your cell configuration
.
.
*/
return cell
}
}
extension FirstPlaylistCollectionView: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
listDelegate?.firstPlaylistCollectionView(self, didSlect: firstPlaylist[indexPath.row])
}
}
And finally verify that the playerViewController has received the data or not
class PlayerViewController: UIViewController {
#IBOutlet weak var handleArea: UIView!
#IBOutlet weak var openCloseArrow: UIImageView!
var video: Video?
override func viewDidLoad() {
super.viewDidLoad()
print("Video object from player vc :: \(video)")
}
}
Added protocol is
protocol FirstPlaylistCollectionViewDelegate: AnyObject {
func firstPlaylistCollectionView(_ listView: FirstPlaylistCollectionView, didSlect video: Video) ->Void
}
you can use Prepare for segue or Did Select Row method try these out.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedProgram = programy[indexPath.row]
let destinationVC = PlayerTableViewController()
destinationVC.programVar = selectedProgram
destinationVC.performSegueWithIdentifier("playerSegue", sender: self)
}

Collection View inside Table View Cell not being called

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

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
}
}

How to call collectionView.reloadData() from reusable header button?

I have a button in my reusable header view that deletes information in the array that supplies the data for the collection view and header. I want it to also be able to perform collectionView.reloadData().
The issue is that I can't call collectionView.reloadData() from the header button because it doesn't recognize collectionView as a variable. If I call Builds().collectionView.reloadData() (Builds is the View controller) the app crashes because it says that it found nil while unwrapping optional. I know that simply calling collectionView.reloadData() isn't the problem because i have collectionView.reloadData() called in viewDidAppear() and that gives me no crashes.
Whats going on here? How can I get my collectionView to reload data after the button removes the data?
For reference:
Reusable Header:
import UIKit
class BuildsHeader: UICollectionReusableView {
#IBOutlet weak var headerLabel: UILabel!
#IBOutlet weak var deleteBuildButton: UIButton!
#IBAction func deleteBuildButton(sender: UIButton) {
for hero in heroes{ if hero.hero.name == heroForDetails.hero.name {
hero.builds.removeAtIndex(sender.tag)
heroForDetails = hero
}}
saveToDefaults(userProfile)
//Builds().collectionBuild.reloadData() runs just fine without this line
}
}
ViewController:
import UIKit
class Builds: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionBuild: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
collectionBuild.delegate = self
collectionBuild.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(animated: Bool) {
collectionBuild.reloadData()
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCellWithReuseIdentifier("BuildCell", forIndexPath: indexPath) as? TalentsCell {
let build = heroForDetails.builds[indexPath.section]
switch (indexPath.row) {
case 0:
cell.configureCell(build["1"]! as! Talent)
case 1:
cell.configureCell(build["4"]! as! Talent)
case 2:
cell.configureCell(build["7"]! as! Talent)
case 3:
cell.configureCell(build["10"]! as! Talent)
case 4:
cell.configureCell(build["13"]! as! Talent)
case 5:
cell.configureCell(build["16"]! as! Talent)
case 6:
cell.configureCell(build["20"]! as! Talent)
default:
cell.configureCell(build["1"]! as! Talent)
}
return cell
}
return UICollectionViewCell()
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 7
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return heroForDetails.builds.count
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(50,50)
}
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "BuildsHeader", forIndexPath: indexPath) as! BuildsHeader
var buildDict = heroForDetails.builds[indexPath.section]
header.headerLabel.text = buildDict["name"] as! String
header.deleteBuildButton.tag = indexPath.section
return header
}
}
You can achieve that with delegation.
Create a protocol
Create a variable inside BuildsHeader for delegate
Call the delegate method in deleteBuildButton function
Now the code for BuildsHeader should look like this:
import UIKit
//**** The Protocol ****
protocol BuildsHeaderDelegate {
func updateCollectionView()
}
class BuildsHeader: UICollectionReusableView {
//**** Variable for the delegate ****
var delegate: BuildsHeaderDelegate?
#IBOutlet weak var headerLabel: UILabel!
#IBOutlet weak var deleteBuildButton: UIButton!
#IBAction func deleteBuildButton(sender: UIButton) {
for hero in heroes{ if hero.hero.name == heroForDetails.hero.name {
hero.builds.removeAtIndex(sender.tag)
heroForDetails = hero
}}
saveToDefaults(userProfile)
//**** Call the delegate method ****
self.delegate?.updateCollectionView()
}
}
In the viewForSupplementaryElementOfKind method of your collection view configure the delegate property of the header, like this:
let header = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "BuildsHeader", forIndexPath: indexPath) as! BuildsHeader
//**** Set this view controller to be the header's delegate ****
header.delegate = self
// rest of header setup
Make the Builds ViewController confirm to BuildsHeaderDelegate :
class Builds: UIViewController, BuildsHeaderDelegate, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
Implement BuildsHeaderDelegate's delegate method in the Builds view controller. you can put this right after your viewForSupplementaryElementOfKind method:
func updateCollectionView () {
//**** reload the collectionView ****
self.collectionBuild.reloadData()
}
Use Delegate to call the method:
protocol BuildsHeaderDelegate(){
func reloadCollectionView()
}
class BuildsHeader: UICollectionReusableView {
var delegate:BuildsHeaderDelegate!
#IBOutlet weak var headerLabel: UILabel!
#IBOutlet weak var deleteBuildButton: UIButton!
#IBAction func deleteBuildButton(sender: UIButton) {
for hero in heroes{ if hero.hero.name == heroForDetails.hero.name {
hero.builds.removeAtIndex(sender.tag)
heroForDetails = hero
}}
saveToDefaults(userProfile)
//##Call delegate method##
delegate.reloadCollectionView()
}
}
Conform delegate in View Controller and Assign it:
class Builds: UIViewController,delegate:BuildsHeaderDelegate , UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionBuild: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
collectionBuild.delegate = self
collectionBuild.dataSource = self
}
func reloadCollectionView() {
collectionBuild.reloadData()
}
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "BuildsHeader", forIndexPath: indexPath) as! BuildsHeader
//##Assign Delegate##
header.delegate = self
var buildDict = heroForDetails.builds[indexPath.section]
header.headerLabel.text = buildDict["name"] as! String
header.deleteBuildButton.tag = indexPath.section
return header
}
}

Swift: How to use "prepareForSegue" inside UICollectionViewCell?

I have a UICollectionView inside a UITableView, I want to link another ViewController when the UICollectionViewCell is tapped by user. Inside the UITableViewCell, I downloaded all the data from the Internet and stored in an array. I created a Segue by control drag the CollectionViewCell to the new ViewController and chose "Push". Inside the new ViewController, I added an IBOutlet of UIImageView to show the image of the CollectionViewCell when user tapped the thumbnail. Now when I tapped the CollectionViewCell, it goes to the new ViewController, but there is no pics showed. here is my code, any suggestions?
In the UITableViewConroller:
import UIKit
class HomePageTableViewController: UITableViewController {
let sections: NSArray = ["latest news", "good news"]
var posts1: [Posts] = [Posts]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section < sections.count{
return sections[section] as? String
}
return nil
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sections.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 && indexPath.section == 0 {
let tableViewCell = tableView.dequeueReusableCellWithIdentifier("TableViewCell") as! TableViewCell
tableViewCell.getCategories()
// tableViewCell.scrollToNextCell()
// tableViewCell.startTimer()
return tableViewCell
}
and inside TableViewCell, here is the code:
import UIKit
import Alamofire
import AlamofireImage
class TableViewCell: UITableViewCell, UICollectionViewDataSource,
UICollectionViewDelegate {
var posts1: [Posts] = [Posts]()
var posts2: [Posts] = [Posts]()
var categories: [Category] = [Category]()
var selectedPost1: Posts?
#IBOutlet weak var theCollectionView: UICollectionView!
I download all the data from JSON and put them inside these arrays. inside this class, I also tried to call the function :
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("selected")
self.selectedPost1 = self.posts1
}
the print works when I tapped a cell, but I can't use "prepareForSegue" inside this function. I checked and found out that this function can only be used in ViewController, but how can I do that?
And inside the new ViewController, here is the code:
import UIKit
class DetailViewController: UIViewController {
#IBOutlet weak var postImageView: UIImageView!
var posts: [Posts] = [Posts]()
var selectedPost: Posts?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
if let post = self.selectedPost{
let thumbnailUrlString = post.postThumbnailUrlString
let imageUrl: NSURL = NSURL(string: thumbnailUrlString)!
print(thumbnailUrlString)
postImageView.af_setImageWithURL(imageUrl)
}
}
}
Since when I download the data, I put them into 2 different array, posts1 and posts2. I want to show the corresponding images in the new ViewController. But I just created one "selectedPost" array, I am not sure is that the problem? and I am not sure if I reload the data to the "selectedPost" array, maybe thats why there is no images showing? really hope anyone can give me some suggestions. thanks
You should use prepareForSegue:. What you need to do is have a var selectedIndexPath which is set whenever you select a cell. Then in prepareForSegue: you can access the cell and it's properties i.e:
HomePageTableViewController: UITableViewController {
var selectedIndexPath: NSIndexPath?
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
selectedIndexPath = indexPath
}
public override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepareForSegue(segue, sender: sender)
let cell = theCollectionView.cellForItemAtIndexPath(selectedIndexPath)
//do what you need to do
}
}

Resources