swift pass images from collection view controller to another view controller - ios

i have downloaded set of users photo from firebase and view it as collection view (instagram like)
but im trying to enlarge the photo clicked in another view controller using segue but its not working.
Any thoughts about my code:
class ProfileViewController: UIViewController{
var photoThumbnail: UIImage!
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collection_cell", for: indexPath) as! ProfileCollectionViewCell
cell.imageCollection.downloadImage2(from: currPosts[indexPath.row].photoUrl)
cell.imageCollection.image = photoThumbnail
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
performSegue(withIdentifier: "photoViewSegue", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var destViewController : EnlargePhotoViewController = segue.destination as! EnlargePhotoViewController
destViewController.labelText = "test" //**** this works
destViewController.myImage = photoThumbnail //**** this doesnt work
}
}
and the collection view cell is:
class ProfileCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageCollection: UIImageView!
}
lastly the target viewController:
class EnlargePhotoViewController: UIViewController {
#IBOutlet weak var myLabel: UILabel!
#IBOutlet weak var enlargedPhoto: UIImageView!
var labelText = String()
var myImage: UIImage!
override func viewDidLoad() {
super.viewDidLoad()
myLabel.text = labelText
enlargedPhoto.image = myImage
}
}

Try to change to this code:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! ProfileCollectionViewCell
photoThumbnail = cell.imageCollection.image
performSegue(withIdentifier: "photoViewSegue", sender: nil)
}

your only goal is to get the image of the selected cell, this can be done more efficiently. All you have to do is read/write to the cells imageView property, photoThumbnail is never set so always nil, just modify this
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collection_cell", for: indexPath) as! ProfileCollectionViewCell
cell.imageCollection.downloadImage2(from: currPosts[indexPath.row].photoUrl)
//cell.imageCollection.image = photoThumbnail <-- No need of this
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// get the correct cell on select
if let cell = collectionView.cellForItem(at: indexPath) as! ProfileCollectionViewCell
{
photoThumbnail = cell.imageCollection.image <-- finally assign the imageview to image
performSegue(withIdentifier: "photoViewSegue", sender: self)
}
}
for safer retrieve the image, use like
override func viewDidLoad() {
super.viewDidLoad()
if let getImage = myImage
{
myLabel.text = labelText
enlargedPhoto.image = getImage
}
}

First View Controller
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.row == 0
{
let objstory = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
objstory.strd = imageView.image
_ = self.navigationController?.pushViewController(objstory, animated: true)
}
}
SecondViewController
var strd:UIImage!
#IBOutlet weak var imgprof: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imgprof.image = strd
// Do any additional setup after loading the view.
}

class ProfileViewController: UIViewController{
var photoThumbnail: UIImage!
var selectedPhotoURL: NSUrl!
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collection_cell", for: indexPath) as! ProfileCollectionViewCell
cell.imageCollection.downloadImage2(from: currPosts[indexPath.row].photoUrl)
cell.imageCollection.image = photoThumbnail
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedPhotoURL = currPosts[indexPath.row].photoUrl
performSegue(withIdentifier: "photoViewSegue", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var destViewController : EnlargePhotoViewController = segue.destination as! EnlargePhotoViewController
destViewController.labelText = "test" //**** this works
//make image from selected url or pass url and download it in EnlargePhotoViewController
let downlodedImage = yourMethodToDownload(selectedPhotoURL)
destViewController.myImage = downlodedImage //**** this will work work
}
}

Related

how to pass data from cell to another ViewController

#TusharMordiya Please check this image
I have created a tableView inside a CollectionView.The contents of the view are UIImage and a UILabel.I want to design the cell in which when I click on a cell the image and label must go to another ViewController.
import UIKit
class ExploreTableViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
#IBOutlet var collectionView: UICollectionView!
var namearr = ["images-1", "images-2", "images-3", "images-4", "images-5"]
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 132, height: 134)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = UIStoryboard(name: "DetailViewController", bundle: nil).instantiateViewController(withIdentifier:"DetailViewController") as? DetailViewController
vc?.name = namearr[indexPath.row]
vc?.img.image = UIImage(named: namearr[indexPath.row])
//self.navigationController?.pushViewController(vc, animated: true)
// showing error in here and while declaring object of viewcontroller
}
}
Please try this.
Add function for get top most view controller
extension UIApplication {
class func topViewController(_ viewController: UIViewController? = UIApplication.shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.compactMap({$0 as? UIWindowScene})
.first?.windows
.filter({$0.isKeyWindow}).first?.rootViewController) -> UIViewController? {
if let nav = viewController as? UINavigationController {
return topViewController(nav.visibleViewController)
}
if let tab = viewController as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(selected)
}
}
if let presented = viewController?.presentedViewController {
return topViewController(presented)
}
return viewController
}
}
Use this code in your didSelectItemAt method
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
if let vc = storyBoard.instantiateViewController(withIdentifier:"DetailViewController") as? DetailViewController {
vc.name = namearr[indexPath.row]
print("You tapped the cell\(indexPath) with car name \(namearr[indexPath.row]) ")
UIApplication.topViewController()?.navigationController?.pushViewController(vc, animated: true)
}
}
In your Detail Screen
class DetailViewController: UIViewController {
#IBOutlet var lbl: UILabel!
#IBOutlet var img: UIImageView!
var name = ""
override func viewDidLoad() {
super.viewDidLoad()
lbl.text = name
img.image = UIImage(named: name)
}
}
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier:"DetailViewController") as? DetailViewController
change storyBoard name to Main

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

Why is my UICollectionView not showing at all?

I am using storyboards, and my UICollectionView with a basic custom cell is not showing at all? My simulator is constantly running a version of my storyboard when my "Next" button was at the middle of the screen, obviously now it is at the bottom as shown here along with all the identities and links created in the storyboard: https://imgur.com/a/R8iTm9n
import UIKit
class CategoryViewController: UIViewController{
#IBOutlet weak var categoryCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
categoryCollectionView.delegate = self
categoryCollectionView.dataSource = self
NetworkingClient.fetchRecipeCategories{ (recipeCategories) in
//print(recipeCategories)
}
categoryCollectionView.reloadData()
}
}
extension CategoryViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.deselectItem(at: indexPath, animated: true)
print("Taptaptap")
}
}
extension CategoryViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 12
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell = UICollectionViewCell()
if let testCell = collectionView.dequeueReusableCell(withReuseIdentifier: "categoryCell", for: indexPath) as? CategoryCollectionViewCell{
testCell.configure(with: indexPath.row)
cell = testCell
print("test1")
}
print("test2")
return cell
}
}
/*
extension CategoryViewController: UICollectionViewDelegateFlowLayout {
}
*/
And my my custom view cell :
class CategoryCollectionViewCell: UICollectionViewCell {
static let identifier: String = "CategoryCollectionViewCell"
#IBOutlet weak var categoryImageView: UIImageView!
#IBOutlet private weak var testLabel: UILabel!
func configure(with id: Int){
testLabel.text = String(id)
categoryImageView.clipsToBounds = true
categoryImageView.contentMode = .scaleAspectFit
}
}
Sorry for the formatting...
Register your custom collectionview cell named "categoryCell" in viewDidLoad()
categoryCollectionView.register(UINib(nibName: "categoryCell", bundle:
nil),forCellWithReuseIdentifier: "categoryCell")
categoryCollectionView.delegate = self
categoryCollectionView.dataSource = self
categoryCollectionView.reloadData()

How can I have onclick functionality for my CollectionView cells?

I want to make it so that when I tap on a CollectionView Cell, it segues to another view. I also want to pass a user ID to this view so I can query the database. This is what I have implemented so far:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionview.dequeueReusableCell(withReuseIdentifier: "userCell", for: indexPath) as! UserCell
print(user[indexPath.row].imagePath!)
cell.userImage.sd_setImage(with: URL(string: user[indexPath.row].imagePath!))
cell.nameLabel.text = user[indexPath.row].username
cell.userID = user[indexPath.row].userID
let destinationVC = ProfileViewController()
destinationVC.sentUserID = user[indexPath.row].userID!
// Let's assume that the segue name is called playerSegue
// This will perform the segue and pre-load the variable for you to use
//destinationVC.performSegue(withIdentifier: "toProfileFromSearch", sender: self)
cell.addButtonTapAction = {
// implement your logic here, e.g. call preformSegue()
self.performSegue(withIdentifier: "toProfileFromSearch", sender: self)
}
//cell.userImage.downloadImage(from: self.user[indexPath.row].imagePath!)
//checkFollowing(indexPath: indexPath)
return cell
}
This is in the individual creation of each cell. When I click the user profile in the search area, nothing happens.
I followed other stack overflow questions to get this far. Can anyone make a complete solution for other people that need this too?
You can use the didSelectItemAt function, check this
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let VC1 = self.storyboard!.instantiateViewController(withIdentifier: "IDYOURVIEW") as! ProfileViewController
VC1.sentUserID = user[indexPath.row].userID!
self.navigationController?.pushViewController(VC1, animated: true)
}
If you're using segues
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "toProfileFromSearch", sender: user[indexPath.row].userID!)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "toProfileFromSearch"
{
let vc = segue.destination as? ProfileViewController
if let id = sender as! String
{
vc?.sentUserID = id
}
}
}
There is another better way to handle this using protocol
protocol UserCellTapedDelegate: AnyObject {
func didTapButton(_ cell: UserCell, didSelectItemAt id: Int)
}
then your cell would be like:
class UserCell: UICollectionViewCell {
public var userID: Int!
public weak var delegate: UserCellTapedDelegate?
#objc private func addButtonTapAction() {
delegate?.didTapButton(self, didSelectItemAt: userID)
}
}
userID: to store the user ID.
delegate: use an optional weak (in terms of memory management) delegate reference in your cell.
addButtonTapAction func to handle target of the button/or tap gesture on Any UIView.
The next step is to go back to your UIViewController and conform to the custom delegate:
extension ViewController: UserCellTapedDelegate {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionview.dequeueReusableCell(withReuseIdentifier: "userCell", for: indexPath) as! UserCell
...
cell.userID = user[indexPath.row].userID!
cell.delegate = self
return cell
}
func didTapButton(_ cell: UserCell, didSelectItemAt id: Int) {
self.performSegue(withIdentifier: "toProfileFromSearch", sender: id)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toProfileFromSearch" {
let vc = segue.destination as! ProfileViewController
if let id = sender as! String {
vc.sentUserID = id
}
}
}
}
Hope this helps you 😊

How can I put 2 collectionViews in a single ViewController?

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.

Resources