In a UICollectionView, I am displaying images and on clicking the image it opens up in a ViewController. Works fine.
However, I want to swipe the images to right/left when the image opens in the new viewController.
To swipe the images, I tried adding a CollectionView in the DetailViewController and added UIImageView inside the cell.
//on clicking the image from main view controller
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "DetailViewController") as? DetailViewController
vc?.name = imgArr[indexPath.row]
self.navigationController?.pushViewController(vc!, animated: true)
}
The error is:
"Illegal Configuration: The img outlet from the DetailViewController
to the UIImageView is invalid. Outlets cannot be connected to
repeating content."
the easiest way for you will be to pass the whole imgArr as a data source for the collectionView in the DetailViewController. Then define a selectedName property in the DetailViewController and scroll to the selected name before DetailViewController has appeared.
EDIT:
//on clicking the image from main view controller
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier: "DetailViewController") as? DetailViewController {
vc.imgArr = imgArr
vc.selectedNameIndex = imgArr[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
}
Related
I am writing a code for my school project. As a beginner would, I looked up on tutorials on youtube how to code.
To summarize the hierarchy of my used objects:
Main collectionView (first one loaded) for scrolling horizontally between views.
List collectionView for listing cells.
collectionViewCell cells for listing information.
However, I am unable to find a way so that when I call a didSelectItemAt function by tapping on one of the cells to push a new view. I have tried creating a function that pushes the view in the MainViewController and call it by creating an instance of the class in didSelectItemAt function but I had no luck.
have you added datasource and delegate?. if you added please check cell click working or not. if click is working add bellow navigation code.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let controller = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
self.navigationController?.pushViewController(controller, animated: true)
}
Contributing to Raj's answer, if you want to push a view controller when selecting some specific item in your collection view, just a slight variation of condition will do the trick, this delegate method is called with you click on an item in your collection view:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.item == **<your item's index>** {
let controller = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
self.navigationController?.pushViewController(controller, animated: true)
}
}
Add the upper Side the Class like this :
class tableViewVC : UIViewController, UITableViewDelegate, UITableViewDataSource {
}
Add inside ViewDidLoad():
tableView.delegate = self
tableView.datasource = self
And then you will use in TableView Method like this :
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let ViewController = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController
self.navigationController?.pushViewController(ViewController!, animated: true)
}
I currently have a UICollectionView table with cells, I am trying to allow each cell that is created to have their own unique view controller. For example, when the UICollectionViewCell is tapped, the view controller shows for that specific cell. I know that I can create one viewcontroller and perform a segue to only that one view controller. That only covers one cell... If the user creates 25 cells... how do I make a view controller for each cell without making a segue? The code below is to create a cell.
// MARK: Create collection View cell with title, image, and rounded border
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! ChatCell
let object = objects[indexPath.row]
cell.chatLabel.text = object.title ?? ""
cell.chatImage.image = object.image
if let chatImagePath = object.imagePath {
if let imageURL = URL(string: chatImagePath) {
cell.chatImage.sd_setImage(with: imageURL)
}
}
cell.layer.borderWidth = 0.5
cell.layer.borderColor = UIColor.darkGray.cgColor
cell.layer.masksToBounds = true
cell.layer.cornerRadius = 8
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return objects.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let itemWidth = photoCollectionView.bounds.width
let itemHeight = photoCollectionView.bounds.height / 2
return CGSize(width: itemWidth, height: itemHeight)
}
In the comments under your question, you clarified that you really only have one basic type of view controller that you're transitioning to, but you want to make sure that you supply the correct information to it on the basis of which cell of the collection view you tapped on.
There are two basic approaches:
Easiest, in IB, create a segue from the collection view cell to the next scene in the storyboard, and then implement prepare(for:sender:) in the originating scene to pass whatever you need to that next scene.
For example, you might have a prepare(for:sender:) that does something like:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let indexPath = collectionView?.indexPathsForSelectedItems?.first, let destination = segue.destination as? DetailsViewController {
destination.object = objects[indexPath.item]
}
}
Now, this makes a ton of assumptions (e.g. that my collection view has an array, objects, that my destination view controller is a DetailsViewController, that it has some object property, etc.), but hopefully it illustrates the basic idea.
You said you didn't want to use a segue. I'm not sure why, but, if you really don't want segue, then just use implement collectionView(_:didSelectItemAt:) and initiate the transition programmatically, however you want.
I have an ImageView inside a CollectionViewCell. I want to be able to click the image and it take me to another ViewController. How would I do this? This is the code I have so far.
import UIKit
class FirstViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var collectionView: UICollectionView!
var images = ["meal1", "photograph1", "meal1"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.collectionView.delegate = self
self.collectionView.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! CollectionViewCell
//set images
cell.imageView.image = UIImage(named: images[indexPath.row])
return cell
}
}
As you said you want to detect image tap on collectionview cell please go through this code :
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.connected(_:)))
cell.yourImageView.isUserInteractionEnabled = true
cell.yourImageView.tag = indexPath.row
cell.yourImageView.addGestureRecognizer(tapGestureRecognizer)
And add below method to your ViewController
func connected(_ sender:AnyObject){
print("you tap image number : \(sender.view.tag)")
//Your code for navigate to another viewcontroller
}
Note - Make sure your user interection for cell image is enable
Add a tabGestureRecognizer to your imageview in collectionView "cellForItemAt" method, and in the method of recognizer tap call the segue to go to the desired viewcontroller.
Swift 5
CollectionView Function:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.tap(_:)))
cell.yourImg.isUserInteractionEnabled = true
cell.yourImg.tag = indexPath.row
cell.yourImg.addGestureRecognizer(tapGestureRecognizer)
return cell
}
Tap Function:
#IBAction func tap(_ sender:AnyObject){
print("ViewController tap() Clicked Item: \(sender.view.tag)")
}
You can either us a UIButton and set the image property on it with no title, or you can add a UIGestureRecognizer to the UIImageView. Either way, you'd just Present or Show the ViewController you want to display once the action has been received.
One thing I'll often do in this situation, is create a CollectionCellDelegate protocol that has a callback function (something like buttonPressed:forCollectionCell:), that I can have my CollectionView conform to, then set the delegate of each cell to the CollectionView. Then you can call up to the CollectionView when the button/image is pressed, and have the CollectionView handle whatever behaviour you want, in this case, presenting/pushing a new view controller.
I have set up a ViewController with UICollectionViewCells, inside of a navigation controller. I want to be able to click on the cells and then have the user be taken to a new controller depending on which cell is selected (different controller for each cell). I want the navigation bar to still appear in the new controller, and have a back button that will take the user back to the original ViewController. I have the following code inside the initial view controller to set up the collection view cells:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: playlistCellId, for: indexPath) as! playlistCoverCell
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 100, height: 100)
}
I also register the cells correctly in viewDidLoad. What function do I use to perform an action when selecting a cell?
you have to use:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.row == 0 {
let viewController = UIViewController() // or your custom view controller
self.navigationController?.pushViewController(viewController, animated: true)
}
else if indexPath.row == 1 {
// and so on....
}
}
Tells the delegate that the item at the specified index path was
selected. The collection view calls this method when the user
successfully selects an item in the collection view. It does not call
this method when you programmatically set the selection.
you can try UICollectionViewDelegate in the function
enter image description here
you can use indexPath to get elements of the current click;
push to next viewController you have to have navigationViewController, if navigationController is nil, you can try protocol or block. Sorry, my English is not good, maybe grammar is wrong.
hello I have implemented a UICollectionView in my controller. There are lots of info I am displaying on each cell. When user clicks the particular cell I want to pass all the info that was in the cell to another controller.
As I am displaying all the data from db in the cells and cells are generating dynamically so I think one way could be to pass just a record id from one cell to this function didSelectItemAtIndexPath and then in the second controller I query again from the database. But I think that would not be the good idea. and also I don't know how can I pass the id or any info here in this function didSelectItemAtIndexPath.
So in short I want to display all the info in another controller that is being displayed in that cell which is being clicked
here is my code
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath
indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell",
forIndexPath: indexPath) as! CardsCollectionCell
cell.usernameLabel.text = (((dict["\(indexPath.item)"] as?NSDictionary)!["Trip"] as?NSDictionary)!["userName"] as?NSString)! as String
cell.feeLabel.text = (((dict["\(indexPath.item)"] as?NSDictionary)!["Trip"] as?NSDictionary)!["fee"] as?NSString)! as String
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
}
So let's going to explain by parts, the didSelectItemAtIndexPath delegate method is used to know what UICollectionViewCell was tapped in the UICollectionViewController, you can get the UICollectionViewCell very easily using the method cellForItemAtIndexPath(it's not the same as collectionView(collectionView: UICollectionView, cellForItemAtIndexPath) like in the following code:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = self.collectionView?.cellForItemAtIndexPath(indexPath) as! CardsCollectionCell
// access to any property inside the cell you have.
// cell.usernameLabel.text
}
So regarding in short I want to display all the info in another controller that is being displayed in that cell which is being clicked
You can use the didSelectItemAtIndexPath method without any problem to launch a manual segue using the method performSegueWithIdentifier to another UIViewController and just in the prepareForSegue pass any data you need to pass to the another UIViewController. See the following code:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// the identifier of the segue is the same you set in the Attributes Inspector
self.performSegueWithIdentifier("segueName", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "segueName") {
// this is the way of get the indexPath for the selected cell
let indexPath = self.collectionView.indexPathForSelectedRow()
let row = indexPath.row
// get a reference to the next UIViewController
let nextVC = segue.destinationViewController as! NameOfYourViewController
}
}
I hope this help you.