i have a collectionView class
class LC: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout{
//in LC
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let VC = segue.destination as? VC2 {
VC.Rpe = Pass
}
}
it's working fine , in VC2 i have a function when executed it should segue to the next cell in the collection view
i'm not sure how or what is the best way to do it (reload VC2 with the next collection view cell details?, or run the collection view functions programmatically )
update
import Foundation
import UIKit
class View2: UIViewController {
#IBOutlet var Q_Pic: UIImageView!
#IBOutlet var Q_que: UILabel!
var SelectedCell: Ques!
override func viewDidLoad() {
super.viewDidLoad()
Q_Pic.image = UIImage(named: SelectedCell.LIMG)
Q_que.text = SelectedCell.Q
}
#IBAction func herewego(_ sender: Any) {
print("when the user press this button it should take him directly to the next cell detail , i don't want the user to go back to collection view and choose the next cell")
}
}
data
let Q_A_TEST_MOH = [
Ques(Q: "Q1? ",LIMG: "1"),
Ques(Q: "Q2? ",LIMG: "2"),
Ques(Q: "Q3?",LIMG: "3"),
Ques(Q: "Q4?",LIMG: "4"),
Ques(Q: "Q5?",LIMG: "5")
]
struct Ques {
var Q : String
var LIMG: String
}
UICollectionViewController
import Foundation
import UIKit
class test:UIViewController,UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
#IBOutlet var CollectionView: UICollectionView!
var Levelssss: [Ques]!
var ToPass: Ques!
var SelectedCategory: String!
var Level: Int!
override func viewDidLoad() {
super.viewDidLoad()
CollectionView.delegate = self
CollectionView.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return Q_A_TEST_MOH.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "LevelCell2", for: indexPath) as? cell1 {
let r = Q_A_TEST_MOH[indexPath.item]
cell.congigureCell(EditLater: r)
return cell
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
ToPass = Q_A_TEST_MOH[indexPath.item]
performSegue(withIdentifier: "To", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let detalsVC = segue.destination as? View2 {
detalsVC.SelectedCell = ToPass
}
}
}
UICollectionViewCell
import UIKit
class cell1: UICollectionViewCell {
#IBOutlet var BB: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
BB.layer.cornerRadius = 10
}
func congigureCell(EditLater: Ques){
BB.setImage(UIImage(named: EditLater.LIMG), for: .normal)
}
}
Download project from here : download the project
Here is the fixed variant: https://www.dropbox.com/s/bc7ktktrbqg9x7t/test%202.zip?dl=0
Logic is simple: pass a whole array of data and index of selected object.
In VC2 on button click you just increment index and update content of your views.
Now you should just check is index not greater then count of element in array.
Related
This question already has answers here:
passing tapped cell data to another view via segue in Swift
(2 answers)
Pass data through segue
(3 answers)
Closed 8 months ago.
Hi dear professionals.
I have main ViewController, where I put Three horizontal CollectionView with cells into (but I hope at least solve problem with 1 of these).
One of this named - FirstPlaylistCollectionView
Cells also custom - FirstPlaylistCollectionViewCell
On tap on cell with specific video it needed pass Video object to the Player (PlayerViewController).
I cant figure it out how, in my case, make this Segue (pass Video object with necessary data) from CollectionView by code !
I almost don't use Storyboard in this project.
Maybe with help of Delegate, but I'm also couldn't understand how to use them for my case.
Method didSelectItemAt - works and get Video object, but i don't understand how to pass it correctly.
Will be very grateful for answer. I couldn't apply for now any solution from Stack, help please.
FirstPlaylistCollectionView code
import UIKit
protocol FirstPlaylistCollectionViewDelegate: AnyObject {
func playVideo()
}
class FirstPlaylistCollectionView: UICollectionView, UICollectionViewDelegate, UICollectionViewDataSource, ModelDelegate {
var playlistsModel = PlaylistsModel()
private var firstPlaylist: [Video] = []
weak var delegate2: FirstPlaylistCollectionViewDelegate?
// MARK: - Data Source
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return firstPlaylist.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = dequeueReusableCell(withReuseIdentifier: FirstPlaylistCollectionViewCell.reuseId, for: indexPath) as! FirstPlaylistCollectionViewCell
let video = self.firstPlaylist[indexPath.row]
cell.setCell(video)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.delegate2?.playVideo()
print("selected video \(firstPlaylist[indexPath.row]) with \(collectionView)! DONE!")
}
FirstPlaylistCollectionViewCell code
class FirstPlaylistCollectionViewCell: UICollectionViewCell {
static let reuseId = "FirstPlaylistCollectionViewCell"
var video: Video?
PlayerViewController code
import UIKit
import WebKit
class PlayerViewController: UIViewController {
#IBOutlet weak var handleArea: UIView!
#IBOutlet weak var openCloseArrow: UIImageView!
var video: Video?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("I'm here!!!")
let vc2 = segue.destination as! PlayerViewController
if let cell = sender as? Video {
self.video = cell
vc2.titleOfVideoLabel.text = video?.title
}
}
}
extension PlayerViewController: FirstPlaylistCollectionViewDelegate {
func playVideo() {
performSegue(withIdentifier: "homeToPlayer", sender: self)
}
}
Answering this by assuming some of the things, I hope you want to navigate to PlayerViewController from ViewController through a segue. Keeping that in my mind, I have assumed your FirstPlaylistCollectionView is in your ViewController class as mentioned below.
class ViewController: UIViewController {
var firstPlaylistCollectionView: FirstPlaylistCollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// First try to get notified from your collection list to here
// and then from here to your player
firstPlaylistCollectionView.listDelegate = self
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
if let id = segue.identifier, id == "playerSegue",
let lVideo = sender as? Video,
let destination = segue.destination as? PlayerViewController{
destination.video = lVideo
}
}
}
extension ViewController: FirstPlaylistCollectionViewDelegate {
func firstPlaylistCollectionView(_ listView: FirstPlaylistCollectionView, didSlect video: Video) {
self.performSegue(withIdentifier: "playerSegue", sender: video)
}
}
And below is the update for the collection view
class FirstPlaylistCollectionView: UICollectionView {
var playlistsModel = PlaylistsModel()
private var firstPlaylist: [Video] = []
weak var listDelegate: FirstPlaylistCollectionViewDelegate?
}
extension FirstPlaylistCollectionView: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return firstPlaylist.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = dequeueReusableCell(withReuseIdentifier: FirstPlaylistCollectionViewCell.reuseId, for: indexPath) as! FirstPlaylistCollectionViewCell
/* Here it goes your cell configuration
.
.
*/
return cell
}
}
extension FirstPlaylistCollectionView: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
listDelegate?.firstPlaylistCollectionView(self, didSlect: firstPlaylist[indexPath.row])
}
}
And finally verify that the playerViewController has received the data or not
class PlayerViewController: UIViewController {
#IBOutlet weak var handleArea: UIView!
#IBOutlet weak var openCloseArrow: UIImageView!
var video: Video?
override func viewDidLoad() {
super.viewDidLoad()
print("Video object from player vc :: \(video)")
}
}
Added protocol is
protocol FirstPlaylistCollectionViewDelegate: AnyObject {
func firstPlaylistCollectionView(_ listView: FirstPlaylistCollectionView, didSlect video: Video) ->Void
}
you can use Prepare for segue or Did Select Row method try these out.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedProgram = programy[indexPath.row]
let destinationVC = PlayerTableViewController()
destinationVC.programVar = selectedProgram
destinationVC.performSegueWithIdentifier("playerSegue", sender: self)
}
So I have my program where I have two collection views on the same ViewController. However when I run the app I can only see one. I have set the constraints on the image the same way on both.
the arrays productsImages and StoresImages are names of images I have in my assets folder. Firthermore pillImage and compStoreImage I have as outlet on my ColectionViewCell files.
HomeViewController.swift
import UIKit
class HomeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource{
#IBOutlet weak var productCollectionView: UICollectionView!
#IBOutlet weak var storesCollectionView: UICollectionView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if(collectionView == storesCollectionView) {
return storesImages.count
}
return productsImages.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = productCollectionView.dequeueReusableCell(withReuseIdentifier: "productsCell", for: indexPath) as! productCollectionViewCell
cell.pillImage.image = UIImage(named: productsImages[indexPath.row])
if(collectionView == storesCollectionView) {
let cell2 = storesCollectionView.dequeueReusableCell(withReuseIdentifier: "storesCell", for: indexPath) as! StoreCollectionViewCell
cell2.compstoreImage.image = UIImage(named: storesImages[indexPath.row])
return cell2
}
return cell
}
var productsImages:[String] = ["pillImage", "pillyImage", "pillsImage"]
var storesImages:[String] = ["compstoreImage", "compeImage", "compeStore"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
StoreCollectionViewCell.swift
import UIKit
class StoreCollectionViewCell: UICollectionViewCell {
#IBOutlet var compstoreImage: UIImageView!
}
productCollectionViewCell.swift
import UIKit
class productCollectionViewCell: UICollectionViewCell {
#IBOutlet var pillImage: UIImageView!
}
Screenshot
I am still learning swift, and I am trying to create a UICollectionView that would return the number of items that I set in the initial view controller using the slider, but my code doesn't work, how would I do this? Here is my code below:
class ViewController: UIViewController {
//MARK: - Outlets
#IBOutlet weak var firstLabel: UILabel! {
didSet {
firstLabel.text = "0"
}
}
#IBOutlet weak var firstSlider: UISlider! {
didSet {
firstSlider.value = 0
firstSlider.minimumValue = 0
firstSlider.maximumValue = 500
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func firstSliderAction(_ sender: UISlider) {
let firstSliderAction = Int(round(sender.value))
firstLabel.text = "\(firstSliderAction)"
}
}
// CollectionViewController
private let reuseIdentifier = "cell"
class CollectionViewController: UICollectionViewController {
var vc: ViewController!
override func viewDidLoad() {
super.viewDidLoad()
vc = UIStoryboard(name: "Main", bundle: nil)
.instantiateViewController(withIdentifier: "ViewController") as? ViewController
}
// MARK: UICollectionViewDataSource
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return Int(vc.firstSlider.value)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CollectionCell
cell.backgroundColor = .green
return cell
}
}
First let me tell you why your code is not working as expected.
vc = UIStoryboard(name: "Main", bundle: nil)
.instantiateViewController(withIdentifier: "ViewController") as? ViewController
Every time when we initiate view controller from corresponding storyboard it will create new object of that view controller, so based on that vc object will not have those value which has been set by earlier user interaction, in-short for that object didSet haven't called yet.
Now how you can achieve the above,
Well first we need to observe how you are navigating from ViewController to CollectionViewController based on code it looks like you are using segue so you can do below stuff.
class ViewController: UIViewController {
#IBOutlet weak var firstLabel: UILabel!
#IBOutlet weak var firstSlider: UISlider!
var sliderValue:Int = 0 {
didSet {
firstLabel.text = "\(sliderValue)"
}
}
override func viewDidLoad() {
super.viewDidLoad()
setUpInitialValues()
}
func setUpInitialValues() {
firstSlider.value = 0
firstSlider.minimumValue = 0
firstSlider.maximumValue = 500
}
// Value changed action
#IBAction func firstSliderAction(_ sender: UISlider) {
self.sliderValue = Int(round(sender.value))
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "navigateCollection" {
if let destinationVC = segue.destination as? CollectionViewController {
destinationVC.sliderValue = self.sliderValue
}
}
}
}
private let reuseIdentifier = "Cell"
class CollectionViewController: UICollectionViewController {
var sliderValue:Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Register cell classes
self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
self.collectionView.reloadData()
// Do any additional setup after loading the view.
}
// MARK: UICollectionViewDataSource
override func numberOfSections(in collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return sliderValue
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
// Configure the cell
cell.backgroundColor = .yellow
return cell
}
}
I have two ViewController: MainVC, and ChildVC. The MainVC includes a CollectionView with 5 cell. Each of these cell segues to the ChildVC. On this ChildVC, you can select different items which increases (or decreases) a counter on the ChildVC (the counter just reads "## selected".)
Basically, I just want this counter data on the ChildVC to be passed back onto a label of the respective MainVC cell that was tapped. For example: If user taps the second cell on the MainVC, selects 13 items on the ChildVC, then returns back to the MainVC, there will be a "13" in a label on the second cell. Then if the user taps the first cell, selects 5 items on the ChildVC, then returns back to the MainVC, there will be a "5" in a label on the first cell along with the "13" on second cell.
My progress:
I have decided that delegation is an appropriate solution for my requirements, as delegation makes it easy to pass data to/from VC's. I need assistance in passing data BACK from a ChildVC TO a CollectionView Cell.
My questions:
Along with the selected counter count (Int), what other information should be passed to and from within the protocol? (I wasn't sure if the indexPath should be passed, so that the data displays on the correct cell on the MainVC?)
On the MainVC, should the data received from the protocol ChildVC be sent to the CollectionViewCell? or the MainVC cellForItemAt method?
Update:
I have some progress below. But it's not working as intended.
In the below code, I have created both the ViewController (MainVC) and ChildVC. In the Child VC, there is a UISlider to emulate the selected counter. I would like this counter data passed back to the respective MainVC CollectionView Cells. What's happening now is the MainVC CollectionView gets a new cell added once I change the value of the slider! The 'Clear All Animals' btn needs to "zero out" the slider data for all the cells, but I haven't gotten that far yet..
View Controller (MainVC in my question above)
class ViewController: UIViewController {
var allAnimals = AnimalData.getAllAnimals()
#IBOutlet weak var mainCV: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
mainCV.dataSource = self
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "AnimalSegue" {
let childVC = segue.destination as! ChildVC
childVC.delegate = self
if let indexPath = self.mainCV.indexPath(for: sender as! AnimalCollectionViewCell) {
let animalData = self.allAnimals[indexPath.item]
childVC.animal = animalData
childVC.indexPath = indexPath
}
childVC.allIndexPaths = getAllIndexPaths()
}
}
func getAllIndexPaths() -> [IndexPath] {
var indexPaths: [IndexPath] = []
for i in 0..<mainCV.numberOfSections {
for j in 0..<mainCV.numberOfItems(inSection: i) {
indexPaths.append(IndexPath(item: j, section: i))
}
}
return indexPaths
}
}
extension ViewController: DataDelegate {
func zeroOut(for animalObject: AnimalModel, at indexPath: [IndexPath]) {
print("ZERO OUT")
self.mainCV.reloadData()
}
func updatedData(for animalObject: AnimalModel, at indexPath: IndexPath ) {
self.allAnimals[indexPath.item] = animalObject
self.mainCV.reloadItems(at: [indexPath])
}
}
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return allAnimals.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AnimalCell", for: indexPath as IndexPath) as! AnimalCollectionViewCell
let animal = allAnimals[indexPath.item]
cell.animal = animal
return cell
}
}
ChildVC
class ChildVC: UIViewController {
#IBOutlet weak var animalTitleLabel: UILabel!
#IBOutlet weak var labelCounter: UILabel!
#IBOutlet weak var sliderLabel: UISlider!
var delegate: DataDelegate?
var animal: AnimalModel?
var indexPath: IndexPath?
var allIndexPaths: [IndexPath]?
override func viewDidLoad() {
super.viewDidLoad()
animalTitleLabel.text = animal?.name
animalTitleLabel.textColor = animal?.color ?? .white
sliderLabel.value = Float(animal?.amountCounter ?? 0)
self.labelCounter.text = "\(Int(sliderLabel.value))"
}
#IBAction func closeButtonPressed(_ sender: UIButton) {
if let delegate = self.delegate,
let indexPath = self.indexPath,
let animal = self.animal {
delegate.updatedData(for: animal, at: indexPath)
}
self.dismiss(animated: true, completion: nil)
}
#IBAction func sliderChanged(_ sender: UISlider) {
let newValue = Int(sender.value)
labelCounter.text = "\(newValue)"
self.animal?.amountCounter = newValue
}
#IBAction func clearAllBtnPressed(_ sender: UIButton) {
if let delegate = self.delegate,
let all = self.allIndexPaths,
var animal = self.animal {
animal.amountCounter = 0
delegate.zeroOut(for: animal, at: all)
}
self.dismiss(animated: true, completion: nil)
}
}
Animal Collection View Cell
class AnimalCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var animalLabel: UILabel!
#IBOutlet weak var counterLabel: UILabel!
var animal: AnimalModel! {
didSet {
self.updateUI()
}
}
func updateUI() {
animalLabel.text = animal.name
counterLabel.text = "\(animal.amountCounter)"
self.backgroundColor = animal.color
}
}
Data
struct AnimalData {
static func getAllAnimals() -> [AnimalModel] {
return [
AnimalModel(name: "Cats", amountCounter: 0, color: UIColor.red),
AnimalModel(name: "Dogs", amountCounter: 0, color: UIColor.blue),
AnimalModel(name: "Fish", amountCounter: 0, color: UIColor.green),
AnimalModel(name: "Goats", amountCounter: 0, color: UIColor.yellow),
AnimalModel(name: "Lizards", amountCounter: 0, color: UIColor.cyan),
AnimalModel(name: "Birds", amountCounter: 0, color: UIColor.purple)
]
}
}
Delegate
protocol DataDelegate {
func updatedData(for animalObject: AnimalModel, at: IndexPath)
func zeroOut(for animalObject: AnimalModel, at: [IndexPath])
}
Screenshots below of what is happening. See how Dogs is being added as another cell with the value of 23? What should happen is the 0 should change to a 23 on the second blue Dogs cell. I don't understand updating the data source and reloading the correct cells??
How do i simply pass back the slider data into the cell that was originally tapped?
Any help is appreciated
You have the right idea with your delegation, but you need to be able to provide context back to your delegate; ie. what animal was being updated? To do this, either MainVC needs to keep a property of the item that is being updated, or this information needs to be provided to the ChildVC so that it can provide the information back to the MainVC. I will use the latter approach.
Protocol
protocol DataDelegate {
func updatedData(for animalObject: AnimalModel, at: IndexPath)
func clearAll()
}
MainVC
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "AnimalSegue" {
let childVC = segue.destination as! ChildVC
childVC.delegate = self
if let indexPath = self.mainCV.indexPath(for: sender as! AnimalCollectionViewCell) {
let animalData = self.allAnimals[indexPath.item]
childVC.animal = animalData
childVC.indexPath = indexPath
}
}
}
extension ViewController: DataDelegate {
func updatedData(for animalObject: AnimalModel, at indexPath: IndexPath ) {
self.allAnimals[indexPath.item] = animalObject
self.mainCV.reloadItems(at: [indexPath])
}
func clearAll() {
for index in 0..<self.allAnimals.count {
self.allAnimals[index].count =0
}
self.mainCV.reloadData()
}
ChildVC
class ChildVC: UIViewController {
#IBOutlet weak var animalTitleLabel: UILabel!
#IBOutlet weak var labelCounter: UILabel!
#IBOutlet weak var sliderLabel: UISlider!
var delegate: DataDelegate?
var animal: AnimalModel?
var indexPath: IndexPath?
override func viewDidLoad() {
super.viewDidLoad()
animalTitleLabel.text = animal?.name
animalTitleLabel.textColor = animal?.color ?? .white
sliderLabel.value = animal?.count ?? 0
self.labelCounter.text = "\(Int(sliderLabel.value))"
}
#IBAction func closeButtonPressed(_ sender: UIButton) {
if let delegate = self.delegate,
let indexPath = self.indexPath,
let animal = self.animal {
delegate.updatedData(for: animal, at: indexPath)
}
self.dismiss(animated: true, completion: nil)
}
#IBAction func sliderChanged(_ sender: UISlider) {
let newValue = Int(sender.value)
labelCounter.text = "\(newValue)"
self.animal.count = newValue
}
#IBAction func clearAllBtnPressed(_ sender: UIButton) {
delegate.clearAll()
}
}
Updated
I have updated my answer to show how you could implement the clear all. In this case there is no reason to have the ChildVC update the data model; it simply needs to invoke a delegate method to let the MainVC know that it should update the model and refresh the collection view.
I think that this gives a hint as to why the ChildVC is the wrong place for the "clear all" button; if the code feels a bit clunky then the user experience may be a bit clunky too. The clear all button should just be on your MainVC - it doesn't make sense for a button on a animal-specific view to be affecting other animals. It also isn't "discoverable"; I don't find out about the clear all until I select an animal. I realise that this is just a "learning app" but user experience is an important part of iOS app development and so it is never too early to consider it; it can also impact the way you design your code as you can see here.
So this is a very incomplete display, but i believe this solution is something that you are lookin for
class mainVC {
var counters: [Int] = [0,0,0,0,0]
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(forIndexPath: indexPath) as CustomCell
cell.counterLabel = counters[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let childVC = ChildVC()
childVC.finishedSelecting = { counter in
self.counters.insert(counter, at: indexPath.item)
childVC.dismiss()
self.theCollectionView.reloadItems(at: [indexPath])
//Or
self.theCollectionView.reloadData()
}
present(childVC, animated: true)
}
}
class childVC {
var finishedSelecting: ((Int) -> ())?
var counter = 5
#objc func finishedButtonPressed() {
finishedSelecting?(counter)
}
func count() {
counter+=1
}
}
I'm making a medals page for an app I have in mind. I have the app set up in such a way that when a medal is clicked, it will open up a page containing a picture of that medal.
If possible, I also wish to add in a description for every medal in their view controllers. How do I achieve that?
Here's a sample of the code I have:
Medal.swift
import UIKit
class Medals: UICollectionViewController
{
// Defining the array
let imageArray = [UIImage(named: "1"), UIImage(named: "2")]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//Allows you to populate the cells you've created
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
// cell was from the identifier we named earlier
// we let collectionviewcell handle the connection to UIcollectionviewcell
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! CollectionViewCell
cell.imageView?.image = self.imageArray[indexPath.row]
return cell
}
// How many cells do we want to have inside the collection view? Just count the number of images assigned
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("showImage", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showImage"
{
let indexPaths = self.collectionView!.indexPathsForSelectedItems()!
let indexPath = indexPaths[0] as NSIndexPath
let vc = segue.destinationViewController as! MedalDetail
vc.image = self.imageArray[indexPath.row]!
}
}
}
CollectionViewCell.swift
import UIKit
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
}
medaldetails.swift
import UIKit
class MedalDetail: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var setTitle: UINavigationItem!
var image = UIImage()
var medalTitle = UINavigationItem()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.imageView.image = self.image
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Thanks for you help
edit:
This is how I want the medal page to look like when clicked:
First create array of medalDescriptions in Medals ViewController then in didSelectItemAtIndexPath call performSegue to MedalDetail viewController
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let index = indexPath.row
self.performSegueWithIdentifier("SegueMedalDetail", sender: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SegueChallenge" {
let medalDetailViewController = segue.destinationViewController as! MedalDetail
medalDetailViewController.medalDescription = medalDescriptions[index]
}
}
In MedalDetail create medalDescription and in the same viewController change navbar title
override func viewDidAppear(animated: Bool) {
self.navigationController?.navigationBarHidden = false
self.navigationItem.title = medalDescription
self.navigationController!.navigationBar.tintColor = UIColor.whiteColor()
let attributes = [
NSForegroundColorAttributeName: UIColor.whiteColor(),
NSFontAttributeName: UIFont(name: "Helvetica", size: 50)!
]
self.navigationController?.navigationBar.titleTextAttributes = attributes
}
For future do not name your controllers or other class with just their names add also ViewController or View at the end. For example, MedalDetailViewController. That would be better to understand and read
Nevermind, I found another way to do it. I instantiated separate view controller for each medal and thus I can have diffwrent properties per view controller.