I'm trying to open new UIViewController when I click on an item inside UICollectionView, but using this code my app crashes and Xcode and simulator restarts so I can't even see where is the problem.
import UIKit
class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.register(CustomCell.self, forCellWithReuseIdentifier: "cellId")
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! CustomCell
cell.imageViewGame.image = UIImage(named: imageArray[indexPath.row])
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width / 2, height: view.frame.width / 2)
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
performSegue(withIdentifier: "postController", sender: title[indexPath.row])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "postController" {
let postController = segue.destination as! PostController
postController.title = sender as! String
}
}
}
Does anyone know from this code why my app crashes? If it's important, I'm not using storyboard.
Try this:
Make you don't forgot to declare postController identifier in your segue
You just can present it modally with:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let postController = PostController()
postController.title = title[indexPath.row]
present(postController, animated: true, completion: nil)
}
Related
I have trying to make a program that will display the image of crystals. After writing the code and formatting the StoryBoard, when I run the app the images are tiny and there are no labels displayed. I have constraints.
Here is the code:
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
let imageArray = [UIImage(named: "1"),UIImage(named: "2"),UIImage(named: "3")]
let nameArray = ["Rose Quartz", "Clear Quartz", "Clear Quartz 2"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MainCollectionViewCell", for: indexPath) as! MainCollectionViewCell
cell.crystalPhotoImageView.image = imageArray[indexPath.row]
cell.crystalNameLabel.text! = nameArray[indexPath.row]
return cell
}
}
you need to implement to confirm the class has UICollectionViewDelegateFlowLayout and you need to implement this functionn
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return cellSize
}
Delegate isn't being called from tableViewCell. Here is UICollectionViewDelegate and UICollectionViewDataSource code
extension HomeVC:UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout{
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ProductCell", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("ok")
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let lay = collectionViewLayout as! UICollectionViewFlowLayout
lay.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
lay.minimumInteritemSpacing = 0
lay.minimumLineSpacing = 0
collectionView.collectionViewLayout = lay
let size = (collectionView.frame.size.width-10) / 2
return CGSize(width: size, height: size)
}
}
swift 5
//MARK:- Tableview Datasource method
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:"RecentLoanApplicationCell") as! RecentLoanApplicationCell
cell.collectionVC.delegate = self
cell.collectionVC.dataSource = self
cell.btnViewAll.addTarget(self, action: #selector(btnViewALLTap(button:)), for: .touchUpInside)
DispatchQueue.main.async {
cell.collectionVC.reloadData()
}
return cell
}
//MARK:- Tableview Cell in side custom cell Register for collectionView cell
class RecentLoanApplicationCell: UITableViewCell {
#IBOutlet var collectionVC:UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
self.collectionVC.register(UINib.init(nibName:"RecentLoanCollectionViewCell", bundle: nil), forCellWithReuseIdentifier:"RecentLoanCollectionViewCell")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
// Same ControllerView call
//MARK:- Collection DataSource & Delegate
extension HomeViewController : UICollectionViewDelegate,UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:"RecentLoanCollectionViewCell", for: indexPath) as! RecentLoanCollectionViewCell
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
debugPrint("didSelectItemAt ==>\(indexPath.row)")
}
Here is the code how I done for same inside TableViewCell using collectionView and performed selection :
Code inside TableView datasource method :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BasicCarColorCell", for: indexPath) as! BasicCarColorCell
cell.dataSource = preloads.colors
cell.collectionViewSetup()
cell.delegate = self
return cell
}
Code for TableViewCell:
protocol BasicCarColorCellDelegate {
func colorCell(cell:BasicCarColorCell, didSelect color: Color)
}
class BasicCarColorCell: UITableViewCell {
var dataSource = Array<Color>()
var selectedColor = Color()
#IBOutlet weak var textView: RSKPlaceholderTextView!
#IBOutlet weak var guideLineMessage:UILabel!
#IBOutlet weak var collectionView: UICollectionView!
var delegate: BasicCarColorCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func collectionViewSetup() {
let nib = UINib(nibName: "BasicCarColorCollectionCell", bundle: nil)
self.collectionView.register(nib, forCellWithReuseIdentifier: "BasicCarColorCollectionCell")
let flowLayout = UICollectionViewFlowLayout()
flowLayout.minimumLineSpacing = 0
flowLayout.minimumInteritemSpacing = 0
flowLayout.scrollDirection = .horizontal
collectionView.collectionViewLayout = flowLayout
collectionView.dataSource = self
collectionView.delegate = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension BasicCarColorCell: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.dataSource.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BasicCarColorCollectionCell", for: indexPath) as! BasicCarColorCollectionCell
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height = collectionView.bounds.size.height-2
let width = height-20
return CGSize(width: width, height:height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 1, left: 10, bottom: 1, right: 10)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let color = self.dataSource[indexPath.item]
self.selectedColor = color
delegate?.colorCell(cell: self, didSelect: self.selectedColor)
collectionView.reloadData()
}
}
And to handle the selection of collectionView just implement the method of custom protocol written in TableViewCell in ViewController:
func colorCell(cell: BasicCarColorCell, didSelect color: Color) {
//self.selectedCarColor = color.value
}
You can do it in same pattern as per your need.
Hope it'll help!
You need to set datasource and delegate for collectionView, every time in Tableview delegate CellForRowAtIndexPath.
I have a stock standard UICollectionView in a UIViewController that is its delegate. However the shouldShowMenuForItemAt func is not called for a long press. I have added a didSelectItemAt func which does get called on clicking a cell to make sure the delegate is indeed wired up correctly.
I also implemented the canPerformAction to return true and performAction in the delegate along with the canPerformAction and canBecomeFirstResponder to return true in my UICollectionViewCell subclass. None of these func's get called for a long press of a cell. Any suggestions?
The missing piece of the puzzle, which most people seem to miss, is that in order for menus to work (in a collection view or table view), the cell must implement the selector.
Here's a minimal example. Instruction: Make a new project using the Single View App template. Copy this code and paste it into ViewController.swift, so as to replace completely everything in that file. Run. Long press on a green square. Enjoy. (The menu item does nothing; the point is, you will see the menu item appear.)
import UIKit
class Cell : UICollectionViewCell {
#objc func f(_ : Any) {}
}
class ViewController: UIViewController {
let cellid = "cellid"
#nonobjc private let howdy = #selector(Cell.f)
override func viewDidLoad() {
super.viewDidLoad()
let cv = UICollectionView(frame: self.view.bounds, collectionViewLayout: UICollectionViewFlowLayout())
self.view.addSubview(cv)
cv.autoresizingMask = [.flexibleWidth, .flexibleHeight]
cv.delegate = self
cv.dataSource = self
cv.register(Cell.self, forCellWithReuseIdentifier: cellid)
}
}
extension ViewController : UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(_ cv: UICollectionView, cellForItemAt ip: IndexPath) -> UICollectionViewCell {
let cell = cv.dequeueReusableCell(withReuseIdentifier: cellid, for: ip)
cell.backgroundColor = .green
return cell
}
func collectionView(_ collectionView: UICollectionView, shouldShowMenuForItemAt indexPath: IndexPath) -> Bool {
let mi = UIMenuItem(title:"Howdy", action:howdy)
UIMenuController.shared.menuItems = [mi]
return true
}
func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
return (action == howdy)
}
func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {
}
}
First viewController
import UIKit
class photosCollectionViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource {
#IBOutlet weak var photoCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
photoCollectionView.delegate = self
photoCollectionView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
var photosArray = PhotoClass(Name:["Dog","Cat","Lion","Tiger"])
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return photosArray.Name.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let photocell = photoCollectionView.dequeueReusableCell(withReuseIdentifier: "photosCell", for: indexPath) as! photoscollectionCell
//photocell.backgroundColor = UIColor.blue
photocell.cellImage.image = UIImage(named: photosArray.Name[indexPath.row])
photocell.cellLabel.text = photosArray.Name[indexPath.row]
return photocell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Something")
let vc = self.storyboard?.instantiateViewController(withIdentifier: "photosDetails") as! detailsCollectionViewController
// vc.descriptionLabel.text = "Animals"
}
}
didSelectItemAt() is not loading my detailsCollectionViewController,but while i am selecting the cell it's calling .so where am i doing wrong ?
you can write this if you want to push :
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Something")
let vc = self.storyboard?.instantiateViewController(withIdentifier: "photosDetails") as! detailsCollectionViewController
// vc.descriptionLabel.text = "Animals"
self.navigationController?.pushViewController(vc, animated: true)
}
It may helps to you.Thank you
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Something")
let vc = self.storyboard?.instantiateViewController(withIdentifier: "photosDetails") as! detailsCollectionViewController
// vc.descriptionLabel.text = "Animals"
present(vc, animated: true)
}
I am trying to display a custom action using UIMenuController on a UICollectionViewController subclass, and even though the cut, copy and paste actions appears as expected, for some reason my custom action doesn't.
I followed a lot of references from the web but none of them makes it work, here the code:
class CollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
fileprivate var items = [MyClass]()
// MARK: - UICollectionViewDataSource
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellIdentifier", for: indexPath)
/* update cell properties */
return cell
}
// MARK: - UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: itemSize, height: itemSize)
}
override func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
return true
}
override func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {
/* Do Something */
}
override func collectionView(_ collectionView: UICollectionView, shouldShowMenuForItemAt indexPath: IndexPath) -> Bool {
return true
}
public func menuAction(_ sender: UIMenuItem) {
/* Action method*/
}
}
Tried to add the menu item as follows:
let menuItem = UIMenuItem(title: SFLocalization.localizedString("Common-remove"), action: #selector(CollectionViewController.menuAction(_:)))
let menuController = UIMenuController.shared
// menuController.menuItems?.append(menuItem)
menuController.menuItems = [menuItem]
on both viewDidLoad and collectionView(_ collectionView:, shouldShowMenuForItemAt) -> Bool
Any ideas?
Omer - check out this link: http://dev.glide.me/2013/05/custom-item-in-uimenucontroller-of.html
Basically, moving these methods:
(BOOL)canPerformAction:(SEL)action withSender:(id)sender {
(BOOL)canBecomeFirstResponder {
... to the CollectionView cell subclass works. You then have to pass this selector back up to the cell delegate.
With this, I was able to get my custom menu to appear!