Choose cell in collection view to new controller - ios

Very new to code and making a project programmatically. I have my collection view all set up but i cant figure out how to tell a specific cell to navigate to a new collection view or detail view. Very confused and frustrated. can anyone help me or at least point me in the right direction. please dumb it down haha.
this is my main View controller
import UIKit
class HomeController: UICollectionViewController,
UICollectionViewDelegateFlowLayout {
var Legends: [Legend] = {
var select1 = Legend()
select1.thumbnailImageName = "select1thumbnail"
var select2 = Legend()
select2.thumbnailImageName = "select2humbnail"
return[select1, select2]
}()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Choose Selection"
collectionView.backgroundView = UIImageView(image: UIImage(named: "backgroundlogo"))
collectionView?.register(VideoCell.self, forCellWithReuseIdentifier: "cellId")
collectionView.dataSource = self
collectionView.delegate = self
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return Legends.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! VideoCell
cell.legend = Legends[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width:view.frame.height, height: 150)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let select2VC = UIViewController()
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.pushViewController(select2VC, animated: true)
print("selcected")
}
}
this is the swift file i have for my collection view
import UIKit
class VideoCell: UICollectionViewCell {
var legend: Legend? {
didSet {
thumbnailImageView.image = UIImage(named: (legend?.thumbnailImageName)!)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let thumbnailImageView: UIImageView = {
let imageView = UIImageView()
imageView.backgroundColor = UIColor.darkGray
imageView.image = UIImage(named:"bgcolor")
imageView.contentMode = .scaleAspectFit
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
func setupViews() {
addSubview(thumbnailImageView)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-16-[v0]-16-|", options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: ["v0": thumbnailImageView]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-1-[v0]-0-|", options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: ["v0": thumbnailImageView]))
}
}
in a 3rd file i have just this bit of code
import UIKit
class Legend: NSObject {
var thumbnailImageName: String?
}
the bottom code of the main view controller does print out a "selected" but it prints it for every cell... I assume each cell will need its own viewController.swift file? then tell that cell to that swift file to show the contents?? thank you for your time.

No you don't need to create its own viewController.swift file for each cell. You just need to create one detail page screen (one DetailViewController.swift) and you need to pass the detail of selected cell with variables declared on detail view controller.
Like I have done HERE in demo project with your code and result will be:
What I have done is I have added detailViewController in storyboard and also added class file. and didSelectItemAt will look like:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController
controller.selectedIndex = indexPath.row //pass selected cell index to next view.
self.navigationController?.pushViewController(controller, animated: true)
}
Here you can pass data with controller.selectedIndex = indexPath.row (Herer I am passing selected index) because selectedIndex is a property of DetailViewController because I have declared it in DetailViewController.swift like
var selectedIndex = 0
And same way you can pass other data as well which is related with selected index.
For more info refer demo project.

If you want check what is sell pressed. You can check what is type cell pressed:
if let cell = tableView.cellForRow(at: indexPath) as? VideoCell {
//check some property and go to new UIViewController or UICollectionViewController
//and transfer data
}

Related

UIViewController still in memory after calling dismiss

So I create a UICollectionViewController class along with a custom UICollectionViewCell. I am presenting a new UIViewController from the CollectionView and then dismissing it in the UIViewController in order to return to the CollectionView. Everything works except for the fact that after dismissing the UIViewController it still remains in memory which is not what I want. I would like to completely destroy the UIViewController once it is dismiss but cannot figure out how do it.
Am I doing anything wrong? Is it normal for the dismiss ViewController to remain in memory after it's dismissal?
// UICollectionViewController class
class MyCollection: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let cellId = "cellId"
override func viewDidLoad() {
collectionView.register(CustomCell.self, forCellWithReuseIdentifier: cellId)
}
let viewControllers:[UIViewController] = [ViewController1()]
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return viewControllers.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let activityCell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CustomCell
return activityCell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = viewControllers[indexPath.item]
present(vc, animated: true, completion: nil)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 90)
}
}
// Custom UICollectionViewCell class
class CustomCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .red
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class ViewController1: UIViewController {
lazy var dismissButton: UIButton = {
let newButton = UIButton(type: .system)
newButton.setTitle("Dismiss", for: .normal)
newButton.backgroundColor = .red
newButton.addTarget(self, action: #selector(dismissView), for: .touchUpInside)
newButton.translatesAutoresizingMaskIntoConstraints = false
return newButton
}()
#objc func dismissView() {
dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(dismissButton)
NSLayoutConstraint.activate([
dissmissButton.centerXAnchor.constraint(equalTo: view.centerXAnchor)
dissmissButton.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
}
Reason why ViewController1 instance is not destroyed completely?
Even after the viewController is dismissed, you're still holding the reference to it inside MyCollection's viewControllers array.
Solution:
In case, you want a brand new instance of the controller everytime a cell is tapped, there is no need to store the controller in viewControllers array.
Simply update didSelectItemAt method to,
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = ViewController1() //here......
present(vc, animated: true, completion: nil)
}
No you are not doing it wrong. There is no strong retain cycle within your code.
The only problem is, even after you dismiss your view controller, it still resides in here
let viewControllers:[UIViewController] = [ViewController1()]
If you want the instance to be destroyed completely you need to remove it from the array as well.
It's not a good choice to make a global variable of a viewController.Once you still hold it,you'll be unable to destroy it.Do it like this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc:UIViewController?
switch indexPath.row {
case 0:
vc = ViewController1()
case 1:
vc = ViewController2()
default:
vc = ViewController0()
}
present(vc!, animated: true, completion: nil)
}
And if there are many viewControllers, maybe it will be better to create a Array of Class like this:
guard let nameSpace = Bundle.main.infoDictionary?["CFBundleName"] as? String else { return }
let clsName = String(format: "%#.%#", nameSpace, cList[indexPath.row])
let cls = (NSClassFromString(clsName) as? UIViewController.Type)!
let vc = cls.init()
present(vc, animated: true, completion: nil)
clist:let cList = ["FirstController","SecondController"]
PS:
Of course I would not use this route if I get 50 ViewControllers.I just think that we can just use the most convenient way to solve the problem.
Hope this will help you.

How to open activity and pass variable on selection of collectionview cell?

I have a collectionView and I am using a custom cell that shows an Image and label. I am populating the view with an array. When a cell is selected, I want a new activity to open and the name of the class to be passed through.
Here is my code:
class CollectionViewController: UICollectionViewController {
let classes = ["English","Math","Science","Social Studies","Other","Technology"]
let class_images : [UIImage] = [
UIImage(named: "English")!,
UIImage(named: "Math")!,
UIImage(named: "Science")!,
UIImage(named: "Social Studies")!,
UIImage(named: "Other")!,
UIImage(named: "Technology")!
]
override func viewDidLoad() {
super.viewDidLoad()
var layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.sectionInset = UIEdgeInsets(top: 22, left: 22, bottom: 22, right: 22)
layout.minimumInteritemSpacing = 22
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return classes.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "class_cell", for: indexPath) as! custom_class_cell
cell.class_name.text = classes[indexPath.item]
cell.class_image.image = class_images[indexPath.item]
// Configure the cell
cell.layer.borderWidth = 1.0
cell.layer.borderColor = UIColor.black.cgColor
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//This isn't the right code, but an example of what I want to do!
if (indexPath=1){
let vc = self.storyboard?.instantiateViewController(withIdentifier:
"classes")
self.present(vc!, animated: true, completion: nil)
//I want to pass this string to the class
let class_name2 = "English"
}
else if(indexPath=2){
let vc = self.storyboard?.instantiateViewController(withIdentifier:
"classes")
self.present(vc!, animated: true, completion: nil)
//I want to pass this string to the class
let class_name2 = "Math"
//it keeps going through the technology cell
}
}
In the didSelectItemAt method, there is an example of what I am trying to do, but the code isn't right. I want to do this for all cells English to Technology. Thank you in advance and let me know if you have any questions!
easiest way:
in dest controller (let's say is a DetailController instance)
you should have:
class DetailController...
... var myInfo : MyInfo?
(MyInfo should contain ALL data You want to pass.)
and in prepare for segue:
vc.myInfo = Info(class_name2)
in viewDidLoad populate your UI:
override func viewDidLoad() {
super.viewDidLoad()
self.detail.text = self. myInfo....
It is actually a really simple solution, I just over complicated it!
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let valueToPass = classes[indexPath.row]
That gets you name of each class when the cell is clicked. After that, just do the prepare for segue method.

UICollectionView keep horizontal list scroll position

I have some horizontal UICollectionViewCell in my UICollectionView.
My problem is that if I scroll the horizontal list in the first cell to another position, the fourth cell will also be at that same position.
Same for the second and the fifth, the third and the sixth...
Also don’t keep horizontal scroll position from portrait to landscape or opposite.
Is there a way for the UICollectionView in the cells to keep their position?
Update 2:
I know i have to save inner horizontal collection view content offsets in an array. I read about that in link below, but in the below link they want to achieve this in UITableView and UIScrollView. And i want to achieve this in UICollectionView inside UICollectionViewController.
Scroll View in UITableViewCell won't save position
Updated 1:
https://imgur.com/a/F8EGsTx
ViewController.swift
import UIKit
class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = .white
collectionView?.register(CategoryCell.self, forCellWithReuseIdentifier: cellId)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CategoryCell
cell.nameLabel.text = "Horizontal list #\(indexPath.item)"
return cell
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 150)
}
}
CategoryCell.swift
import UIKit
class CategoryCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
let cellId = "categoryId"
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var nameLabel: UILabel = {
let label = UILabel()
label.text = "Horizontal list #1"
label.font = UIFont.systemFont(ofSize: 16)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let appsCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = .white
return collectionView
}()
let dividerLineView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 0.4, alpha: 0.4)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
func setupViews() {
addSubview(appsCollectionView)
addSubview(dividerLineView)
addSubview(nameLabel)
appsCollectionView.dataSource = self
appsCollectionView.delegate = self
appsCollectionView.register(AppCell.self, forCellWithReuseIdentifier: cellId)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-14-[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": nameLabel]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-14-[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": dividerLineView]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": appsCollectionView]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[nameLabel(30)][v0][v1(0.5)]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": appsCollectionView, "v1": dividerLineView, "nameLabel": nameLabel]))
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! AppCell
cell.imageView.backgroundColor = UIColor(hue: CGFloat(indexPath.item) / 20.0, saturation: 0.8, brightness: 0.9, alpha: 1)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 100, height: frame.height - 32)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0, 14, 0, 14)
}
}
AppCell.swift
import UIKit
class AppCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let imageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.layer.cornerRadius = 16
iv.layer.masksToBounds = true
return iv
}()
func setupViews() {
addSubview(imageView)
imageView.frame = CGRect(x: 0, y: 0, width: frame.width, height: frame.width)
}
}
I finally got it :)
Thanks to 3 years old project! from irfanlone
https://github.com/irfanlone/Collection-View-in-a-collection-view-cell
It's works and support interface orientation too, but need some optimization.
For example if you scroll to the right and then scroll down fast and then scroll back to top the cell have a extra margin from the right edge! Also have some issue with interface orientation.
If anyone have a complete version please share that, thanks.
For anyone who may be interested, Add the following code in the specified files.
ViewController.swift
var storedOffsets = [Int: CGFloat]()
override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
guard let collectionViewCell = cell as? CategoryCell else { return }
collectionViewCell.collectionViewOffset = storedOffsets[indexPath.row] ?? 0
}
override func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
guard let collectionViewCell = cell as? CategoryCell else { return }
storedOffsets[indexPath.row] = collectionViewCell.collectionViewOffset
}
CategoryCell.swift
var collectionViewOffset: CGFloat {
set {
appsCollectionView.contentOffset.x = newValue
}
get {
return appsCollectionView.contentOffset.x
}
}
#zahaniza thank You for answer, in addition to Your code
If You are using multiple sections the code will look like
ViewController.swift
var storedOffsets = [IndexPath: CGFloat]()
override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
guard let collectionViewCell = cell as? CategoryCell else { return }
collectionViewCell.collectionViewOffset = storedOffsets[indexPath] ?? 0
}
override func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
guard let collectionViewCell = cell as? CategoryCell else { return }
storedOffsets[indexPath] = collectionViewCell.collectionViewOffset
}
Inner collection views get reused. If you want to keep the scroll position for each horizontal collection view you must keep an array of scroll positions in your UIViewController and update it when inner collection view gets scrolled. Then when reusing outer collection view cells you can reset the scroll position in collectionView(collectionView:, cellForItemAt indexPath:) method.
Your outer collection view population method should look something like this:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CategoryCell
cell.nameLabel.text = "Horizontal list #\(indexPath.item)"
cell.scrollPosition = this.scrollPositions[indexPath.item]
return cell
}
From the answer of #zahaniza, this code fixes his issue and works well for iPhone X :
var storedOffsets = [Int: CGFloat]()
override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
guard let collectionViewCell = cell as? CategoryCell,
let innerCollectionView = collectionViewCell.collectionView else { return }
// Default collection offset is -adjustedContentInset.left and not 0
let minOffset = -innerCollectionView.adjustedContentInset.left
let maxOffset = innerCollectionView.contentSize.width - innnerCollectionView.frame.width
maxOffset += innerCollectionView.adjustedContentInset.left
if let offset = storedOffsets[indexPath.row] {
innerCollectionView.contentOffset = CGPoint(max(minOffset, miin(maxOffset, offset.x)), 0)
} else {
innerCollectionView.contentOffset = CGPoint(minOffset, 0);
}
collectionViewCell.collectionViewOffset = storedOffsets[indexPath.row] ?? 0
}
override func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
guard let collectionViewCell = cell as? CategoryCell else { return }
storedOffsets[indexPath.row] = collectionViewCell.collectionView.contentOffset
}

Swift: How to reuse a ViewController properly

I got a HomeController of type UICollectionViewController which handles some PictureCells (contains a picture and a label).
Now I am sending one PictureCell to another ViewController to edit the label. This all works perfectly. I could send it back to the HVC using a protocol but instead of going back I want to go one step further and Display the edited PictureCell in a new ViewController.
Instead of creating a completely new one, I am subclassing the existing HomeController to reuse his CollectionView. All works fine and the view shows up but the edited PictureCell is not showing up at all, even tho I can show it's layer, the Cell itself with its content doesn't show up.
(Messy) Class-Diagram looks like this:
ClassDiagram
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout, MyProtocol {
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = UIColor.black
collectionView?.register(PictureCell.self, forCellWithReuseIdentifier: Constants.cellId)
}
//MARK: Get value from second VC
var valueSentFromSecondViewController: String?
var cellSentFromSecondViewController: PictureCell?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
//Acting with Protocol here
}
//HERE ARE THE COLLECTIONVIEWFUNCTIONS
}
class PictureEditViewController: UIViewController, UITextFieldDelegate {
var delegate:MyProtocol?
var myCell: PictureCell?
let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = UIColor.white
return cv
}()
init(pictureCellInit: PictureCell?) {
self.myCell = pictureCellInit
super.init(nibName: nil, bundle: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
showThings()
}
#objc func showNextVC() {
let newViewController = PictureShowViewController(withCell: self.myCell)
newViewController.modalPresentationStyle = .overCurrentContext
present(newViewController, animated: true) //with dismiss
}
#objc func showThings() {
view.addSubview(collectionView)
self.collectionView.frame = CGRect(x: x, y: y, width: width, height: height)
self.setupViews()
}
func setupViews() {
//ADDING THE SUBVIEWS
}
func confBounds() {
//LAYOUT
}
#objc func handleDismiss() {
self.dismiss(animated: true, completion: nil)
}
class PictureShowViewController: HomeController {
//MARK: Variable/Constant declaration
var myCellToShow: PictureCell?
init(withCell: PictureCell?) {
let layoutUsing = UICollectionViewFlowLayout()
myCellToShow = withCell
super.init(collectionViewLayout: layoutUsing)
}
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = .white
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
collectionView?.addSubview(myCellToShow!)
self.collectionView?.reloadData()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = myCellToShow {
cell.layer.borderColor = UIColor.red.cgColor
cell.layer.borderWidth = 2
return cell
}
else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Constants.cellId, for: indexPath) as! PictureCell
return cell
}
}
//Size of Cell
override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cellSize = CGFloat(view.frame.width)
return CGSize(width: cellSize, height: cellSize)
}
}
Does anyone have an idea where I went wrong?
It is a bad idea to use PictureCell to move your data around view controllers. UICollectionView reuses instances of cells so the content of the cell is bound to change anytime.
So instead of using your cell, hand over the underlying data and insert the data in to the newly dequeued collection view cell.
In the end,
var cellSentFromSecondViewController: PictureCell?
should be var pictureFromSecondViewController: YourPictureData
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Constants.cellId, for: indexPath) as! PictureCell
//Set your data
cell.picture = pictureFromSecondViewController
return cell
}

Manually add delegate & datasource to UICollectionView of xib file

I put the UICollectionView on the UIView in the xib file.
UICollectionView is installed (GUI) in the xib file, and IBOutlet is connected.
In this case, how should we write delegate and dataSource?
(Conjecture: Perhaps, I have to write it manually as a code on my own)
Also, we could not attach Cell to UICollectionView in xib.
Does that mean i do not have to put it?
Collection.swift
//Collection.swift
import UIKit
class Home: UIView, UICollectionViewDelegate, UICollectionViewDataSource{
#IBOutlet weak var propCollectionView: UICollectionView!
let photos = ["sierra"] //Already put to AssetsFolder
//Just instance. plz do not care about this.
class func instance() -> Home {
return UINib(nibName: "Home", bundle: nil).instantiate(withOwner: self, options: nil)[0] as! Home
}
func initValue(){
propCollectionView.register(UINib(nibName: "PropCell", bundle: nil), forCellWithReuseIdentifier: "PropCell")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = propCollectionView.dequeueReusableCell(withReuseIdentifier: "PropCell", for: indexPath) as! PropCell
let propImage = cell.contentView.viewWithTag(1) as! UIImageView
let img = UIImage(named: photos[indexPath.row])
propImage.image = img
return cell
}
}
PropCell.swift
//PropCell.swift
//yeah, nothing. plz don't care this too.
import UIKit
class PropCell: UICollectionViewCell {
override func awakeFromNib() {
super.awakeFromNib()
}
}
Xib of CollectionSwift
Xib of PropCell
(If you do not understand the meaning of the question, please comment.)
import UIKit
class Home: UIView, UICollectionViewDelegate, UICollectionViewDataSource{
#IBOutlet weak var propCollectionView: UICollectionView!
let photos = ["sierra"] //Already put to AssetsFolder
//Just instance. plz do not care about this.
class func instance() -> Home {
return UINib(nibName: "Home", bundle: nil).instantiate(withOwner: self, options: nil)[0] as! Home
}
func configureView() {
propCollectionView.delagate = self
propCollectionView.dataSource = self
}
func initValue(){
propCollectionView.register(UINib(nibName: "PropCell", bundle: nil), forCellWithReuseIdentifier: "PropCell")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = propCollectionView.dequeueReusableCell(withReuseIdentifier: "PropCell", for: indexPath) as! PropCell
let propImage = cell.contentView.viewWithTag(1) as! UIImageView
let img = UIImage(named: photos[indexPath.row])
propImage.image = img
return cell
}
}
USES
let home = Home.instance()
home.configureView() //called configureView() with the home instance

Resources