UICollectionView didSelectIotemAt issue - ios

I have a UICollectionView that is populated by an array of images. I want to allow the user to tap on an image and preview it in a new UIViewController.
For some reason, didSelectItemAt method isn't working as expected. It doesn't throw an error, it gets called, just nothing happens really. Not sure what I do wrong here.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("did select item at was called")
let dashboardStoryboard = UIStoryboard(name: STORYBOARD_DASHBOARD, bundle:nil)
let destinationVC = dashboardStoryboard.instantiateViewController(withIdentifier: "PreviewPostImageVC") as! PreviewPostImageVC
destinationVC.selectedImage = arrayOfSelectedImages[indexPath.row]
self.navigationController?.pushViewController(destinationVC, animated: true)
}

I think Allen's comment points at the problem. If you're sure your method is being called (The print statement appears in the console) then the most likely problem is that self.navigationController is nil. With the optional chaining you're using, that call will fail silently if it's nil, which may or may not be what you want. Try changing it like this:
guard let navController = self.navigationController else {
print("Navigation Controller is nil!")
return
}
navController.pushViewController(destinationVC, animated: true)

Related

Cannot pass indexpath from collectionView (into LightBox package )

I installed this package https://github.com/hyperoslo/Lightbox ,but I do not know how to pass the index of my collectionView to display the desired picture , not the first one
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let controller = LightboxController(images: imagess)
controller.pageDelegate = self as? LightboxControllerPageDelegate
controller.dismissalDelegate = self as? LightboxControllerDismissalDelegate
controller.dynamicBackground = true
present(controller, animated: true, completion: nil)
}
In this case, I can change pictures but the first one always appears
I seem to have read everything but I did not find this important detail.
If i do like this :
let controller = LightboxController(images: [imagess[indexPath.row]])
I can only view one picture with the desired index but cannot change picture in gallery
Help pls :-)
You'll have to set start index to see the current image;
so try this;
let controller = LightboxController(images: imagess, startIndex:indexPath.row)

collectionView :didSelectItemAtIndexPath called with a delay

I have a collection view which loads a list of products and there is no fancy functionality in it. It just loads data from API. The problem is that when i try to tap on one of the items in the collection view
collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
is not getting called. But when i long press on a cell it gets called.
I am pretty sure that there are no gestures applied on the cell.
Can anyone give me some guidelines to tackle the problem.
The code base that i have is as follows
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cellTapped = (self.storeSearchListingCollectionViewOutlet.cellForItem(at: indexPath)) as! StoreSearchProdListingCollectionViewCell
UStoreShareClass.storeSharedInstance.longTappedProductID = String(cellTapped.tag)
if((UStoreShareClass.storeSharedInstance.longTappedProductID) != nil)
{
self.performSegue(withIdentifier: "searchToProductDetailSegue", sender: self)
}
else
{
SetDefaultWrappers().showAlert(info:SERVER_DOWN_ERROR_ALERT, viewController: self)
}
}
View Hierarchy is as follows
Thanks in Advance...!!!
This is intentional. On the Storyboard go to the Collection View and uncheck "Delay Touch Down" in the Attribute inspector.
May have two reasons:
1) May be first reason is:
Unfortunately your code is not getting main thread to work on UI. So you have to put your UI related part in MAIN thread like this.
DispatchQueue.main.async {
// PUT YOUR CODE HERE
if((UStoreShareClass.storeSharedInstance.longTappedProductID) != nil)
{
self.performSegue(withIdentifier: "searchToProductDetailSegue", sender: self)
}
else
{
SetDefaultWrappers().showAlert(info:SERVER_DOWN_ERROR_ALERT, viewController: self)
}
}
2) In second reason:
Have you made collectionView bouncing turned off?
In Storyboard, make checked "Bounce on scroll" checkbox of collectionView, if unchecked.
For future readers of this old question - probably me in the future ;)
I had a UITapGestureRecognizer which was swallowing my short taps (in the UICollectionView's grandparent) and hence only the old taps were making it through! I recon you have the same problem. You just need to add tapRecognizer.cancelsTouchesInView = false!
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapDidTouch(sender:)))
tapRecognizer.cancelsTouchesInView = false
scrollView.addGestureRecognizer(tapRecognizer)
First of all , put breakpoint in if condition and check if it gets inside the didselect block. Then,
Try adding your "performsegue" code in main thread like below
if((UStoreShareClass.storeSharedInstance.longTappedProductID) != nil)
{
DispatchQueue.main.async
{
self.performSegue(withIdentifier: "searchToProductDetailSegue", sender: self)
}
}
else
{
SetDefaultWrappers().showAlert(info:SERVER_DOWN_ERROR_ALERT, viewController: self)
}

What should I use to make this kind of cell, so I can get each of them to segue to different ViewController?

Here is what I want to do (UI is showing down below), I want to perform different segue when I taped different cell in it. But I don't know what component I should use to get this done
I think to use the Collection View Controller, but it seems doest support static cells, I want to use Customized UIVIew to do this, but it couldn't be dragged to another VC in StoryBoard, should I adopt some sort of Protocols of something to do this?
Please answer in Swift
After been helped
Turns out I just need to show the ViewController and haven't need segue yet, so here is the code.
let categories: [(name: String, pic: String, identifier: String)] = [
("人物", "Wilson_head", "CharactersVC"),
("动物", "Pig", "MobsVC"),
("植物", "Bamboo_Patch", "PlantsVC"),
("食谱", "Crock_Pot_Build", "RecipesVC")
]
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let currentCategory = categories[indexPath.row]
let destVC: UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: currentCategory.identifier)
navigationController!.pushViewController(destVC, animated: true)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
if(indexPath.row == 0)
{
let objstory = self.storyboard?.instantiateViewController(withIdentifier: “your Story bord identifier”) as! Your View_ViewController
self.navigationController?.pushViewController(objstory, animated: true)
}
}
Collection View Controller doesn't support static cell.
But you can add static cell programmatically.
set your cell data and target(segue id) for each cell.
ex:
cellData[0].segue = "segueToHuman"
cellData[1].segue = "segueToAnimal"
add segues depend on your view controller(not on cell) like below:
create segue
segue setting
perform particular segue in didSelectItemAt indexPath
let segueID = cellData[indexPath.row].segue
performSegue(withIdentifier: segueID, sender: nil)

Create and perform segue without storyboards

i got an app without storyboards, all UI creation is made in code and I got a splitView which I would make it usable on iPhone, because as the app as been first designed for iPad only, so that when you select a row in the list in the Master view it does nothing on iPhone but is working fine on iPad.
So my question is can I create and perform the segue that allows to show the Detail View on the didSelectRowAtIndexPath method ?
Here's what i've done so far :
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let segue = UIStoryboardSegue(identifier: "test", source: self, destination: detailViewController!)
performSegueWithIdentifier("test", sender: self)
}
but when running and selecting a row the app was crashing telling it needed a performhandler so i added this :
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let segue = UIStoryboardSegue(identifier: "test", source: self, destination: detailViewController!, performHandler: { () -> Void in
let object = self.fetchedResultsController.objectAtIndexPath(indexPath)
let controller = self.detailViewController!
controller.detailItem = object
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
})
performSegueWithIdentifier("test", sender: self)
}
and now when selecting a row xcode says that there is no segue with such identifier "test".
I also tried to call it by segue.perform() and add the performHandler content into the prepareForSegueMethod :
if segue.identifier == "test" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let object = self.fetchedResultsController.objectAtIndexPath(indexPath)
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
and it does just nothing, doesn't crash, just highlight the row i selected and that's all
Can you guys help me ?
EDIT : As Oleg Gordiichuk said, it's not possible to do what I want to do without Storyboards, so thanks for his help :)
Segue it is component of the storyboard interaction it is possible to understand from name of the class UIStoryboardSegue. It is bad idea to create segues programmatically. If i am not making mistake storyboard creates them for you.
For solving of you're issue try to use some common ways like simply present ViewController.
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("id") as! MyController
self.presentViewController(vc, animated: true, completion: nil)
As i understand from our conversation in comments. You would like to create navigation for tableview to details view using segues without storyboard. For now it is impossible to do this without storyboard.
For future learning try to investigate this information.
One way is to use the didSelectRow method for tableView
Swift 3.x
// MARK: - Navigation & Pass Data
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Selected Row \(indexPath.row)")
let nextVC = YourNextViewController()
nextVC.YourLabel.text = "Passed Text"
nextVC.YourLabel.text = YourArray[indexPath.row]
// Push to next view
navigationController?.pushViewController(nextVC, animated: true)
}

How to pass a value to another ViewController by pushing in NavigationStack?

This is my code.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0{
self.navigationController?.pushViewController(self.storyboard?.instantiateViewControllerWithIdentifier("History") as! History, animated: true)
TV.deselectRowAtIndexPath(indexPath, animated: false)
}
}
I push to another ViewController(named History) and I want to pass my value which is in this ViewController to History ViewController.
I know we can pass value by using segue and segue's destinationViewController and sourceViewController.
But there is no segue in this case.
So,I don't know how to assign a var's value to History's var.
Anybody can help me?
let history = self.storyboard?.instantiateViewControllerWithIdentifier("History") as! History
//Here U can Access the variable of History
history.yourVar=Assign Value
self.navigationController?.pushViewController(history, animated: true)
TV.deselectRowAtIndexPath(indexPath, animated: false)

Resources