Property for subclass UICollectionViewCell - swift

Here is my class
class myCell: UICollectionViewCell {
public var myProp:String = ""
let myControl:UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.Text = myProp
return label
}()
}
I want to use the myProp within the creation of my UI elements but the compiler is saying I cannot use myProp.
or why is this incorrect
class myCell: UICollectionViewCell {
public var myLabel:UILabel = UILabel()
let myControl:UIView = {
let ui = UIView()
myLabel = {
let lbl = UILabel()
lbl.translatesAutoresizingMaskIntoConstraints = false
return lbl
}()
ui.AddSubView(myLabel)
return ui
}()
}

This will work
class CollectionViewCell: UICollectionViewCell {
public var myProp:String = ""
override init(frame: CGRect) {
super.init(frame: frame)
}
func setText() {
let myControl:UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = myProp
return label
}()
self.addSubview(myControl)
}
}
During rendering, in cellForRowAtIndex need to implement this for adding subview with text.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CollectionViewCell
cell.myProp = "text"
cell.setText()
return cell
}

Related

How to update a UICollectionViewCell Label?

I am trying to change a text label in a UICollectionViewCell, but for some reason it just will not update. Any help would be aprreciated. Thanks!
You can use didSet to make your code a bit reactive.
class CollectionViewCell : UICollectionViewCell{
var text = "" {
didSet{
self.label.text = text
}
}
private var label : UILabel = {
let label = UILabel()
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class CollectionViewClass : UIViewController,UICollectionViewDelegate,UICollectionViewDataSource{
var collectionView = UICollectionView()
let id = "cell ID"
override func viewDidLoad() {
super.viewDidLoad()
collectionView = UICollectionView(frame: self.view.frame)
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: id)
collectionView.dataSource = self
collectionView.delegate = self
self.view.addSubview(collectionView)
collectionView.backgroundColor = .white
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: id, for: indexPath) as! CollectionViewCell
cell.text = "some text"
cell.backgroundColor = .red
return cell
}
}
In the above code, cell's text value is given everytime it's loaded. Whenever text is set, didset is called which updates the label value.

Swift 5 How UICollectionViewCell changes it's content

I am so confused right now, In cellForItemAt method, I changed the label.text value, but I found that this line is called after cell Instance being created
[Here is the preview collection view][1]
let data = self.data[indexPath.item]
cell.myLabel.text = "\(indexPath.row)"
print(cell.myLabel.text)
However, In my custom cell class,
self.contentView.addSubview(myLabel)
print((myLabel.text)
myLabel is added to contentView in init()
I don't know how does changing myLabel.text in cellForItemAt update the label that is already added to contenView,
So when I trying to figure it out by printing out the text I got,
CUSTOM, 1, CUSTOM, 2, CUSTOM, 3 ...
....
Which means myLabel.text was not changed to indexPath.row before it's added into the contentView, So how this happens?? Anyone can help me? If I don't figure it out I can't continue my project, I am stuck here
Here is the some code
class Cell: UICollectionViewCell {
static var identifier: String = "Cell"
var textLabel: UILabel!
var myLabel: UILabel = {
let label = UILabel()
label.text = "CUSTOM"
label.backgroundColor = .green
label.textAlignment = .center
return label
} ()
override init(frame: CGRect) {
super.init(frame: frame)
self.contentView.addSubview(myLabel)
print(myLabel.text) // print the text after label is added to contentView
// I got Optional("CUSTOM") Which was not changed here
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
myLabel.frame = CGRect(x: 0, y: 0, width: contentView.frame.size.width - 50, height: 50)
}
}
DataSource
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return self.data.count
}
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Cell.identifier, for: indexPath) as! Cell
let data = self.data[indexPath.item]
cell.myLabel.text = "\(indexPath.row)"
print(cell.myLabel.text) // I got Optional("0"), Optional("1"), Optional("2") .. here
// But the label was already added with text "CUSTOM"
return cell
}
}
First, the .text property of a UILabel can be nil, so it is optional.
If you add this to a view controller's viewDidLoad():
let label = UILabel()
print(label.text)
label.text = "abc"
print(label.text)
the output in the debug console will be:
nil
Optional("abc")
Next, if you set the text of a label and then set it again, it replaces any existing text:
let label = UILabel()
print(label.text)
label.text = "abc"
print(label.text)
label.text = "1"
print(label.text)
now the output is:
nil
Optional("abc")
Optional("1")
If you want to get rid of the "Optional" part, you need to unwrap the text:
let label = UILabel()
if let s = label.text {
print(s)
}
label.text = "abc"
if let s = label.text {
print(s)
}
label.text = "1"
if let s = label.text {
print(s)
}
output:
abc
1
Note there is no "nil" output... because the first if let... statement fails, so the print statement does not get executed.
So, if you want your label to show "CUSTOM 1" / "CUSTOM 2" / "CUSTOM 3" / etc, you can either set it that way in cellForRowAt:
cell.myLabel.text = "CUSTOM \(indexPath.row)"
or, you can append the existing text:
// unwrap the optional text
if let s = cell.myLabel.text {
cell.myLabel.text = s + " \(indexPath.row)"
}
Note, however, that cells are reused, so you could end up with:
CUSTOM 1 7 15 8 23
Much better to set the full text to what you want it to be, than to try and append something each time the cell is used.

I really don't know why my collectionViewCell disappear

I making a calendar so first I make a array like this [0,0,0,0,1,2,3,4,...,31] by thing.optimize(month: 5). in this array, the reason I make 0 in front of 1,2,3,...,31 is
when I make cell, I'm using an if statement so if cell.text == 0 then I set cell.isHidden = true.
When I select the one cell I reload both of collectionView(collectionView,nextMonthCollectionView) and make round red shape.
When I select another button, a problem occurs,
suddenly the cell disappears. I added a photo of this.
First, this is my code.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var nowMonthName: UILabel!
#IBOutlet weak var nextMonthName: UILabel!
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var nextMonthCollectionView: UICollectionView!
var thing = realOptimaize()
var selectedIndex : IndexPath?
var items = [UIBarButtonItem]()
var forCollectionViewCount : Int?
var monthData : Array<Int>?
var nextMonthData : Array<Int>?
override func viewDidLoad() {
monthData = thing.optimaize(month: 5)
nextMonthData = thing.optimaize(month: 6)
self.title = String(CalenderBrain.init().curruntYear)
nowMonthName.text = String(CalenderBrain.init().curruntMonthName())
nextMonthName.text = String(CalenderBrain.init().nextMonthName())
self.collectionView.dataSource = self
self.collectionView.delegate = self
self.nextMonthCollectionView.dataSource = self
self.nextMonthCollectionView.delegate = self
self.collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier : "MyCell")
self.nextMonthCollectionView.register(UINib(nibName: "NextMonthCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "MyCell2")
//이해가 잘 안가는 부분!!!
if let layout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout{
layout.minimumInteritemSpacing = -0.2
}
if let layout2 = self.nextMonthCollectionView.collectionViewLayout as? UICollectionViewFlowLayout{
layout2.minimumInteritemSpacing = -0.2
}
}
}
`extension ViewController : UICollectionViewDataSource, UICollectionViewDelegate,` UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.nextMonthCollectionView {
forCollectionViewCount = nextMonthData!.count
return forCollectionViewCount!
} else {
forCollectionViewCount = monthData!.count
return forCollectionViewCount!
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { if collectionView == self.nextMonthCollectionView{
let forCollectionViewCell = nextMonthCollectionView.dequeueReusableCell(withReuseIdentifier: "MyCell2", for: indexPath) as! NextMonthCollectionViewCell
// forCollectionViewCell.button.tag = indexPath.item
if nextMonthData![indexPath.row] == 0 {
forCollectionViewCell.isHidden = true
} else {
forCollectionViewCell.Label.text = String(nextMonthData![indexPath.row])
}
return forCollectionViewCell
} else {
let forCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! CollectionViewCell
// forCollectionViewCell.button.tag = indexPath.item + 100
if monthData![indexPath.row] == 0 {
forCollectionViewCell.isHidden = true
} else {
forCollectionViewCell.Label.text = String(monthData![indexPath.row])
}
return forCollectionViewCell
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == nextMonthCollectionView {
return .init(width: 53.25 , height: 67)
} else{
return .init(width: 53.25 , height: 67)
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == self.nextMonthCollectionView {
let forCollectionViewCell = collectionView.cellForItem(at: indexPath) as! NextMonthCollectionViewCell
self.collectionView.reloadData()
collectionView.reloadData()
forCollectionViewCell.Label.textColor = .white
forCollectionViewCell.Label2.backgroundColor = .red
forCollectionViewCell.Label2.layer.cornerRadius = 0.5 * forCollectionViewCell.Label2.bounds.size.width
forCollectionViewCell.Label2.clipsToBounds = true
}else{
let forCollectionViewCell = collectionView.cellForItem(at: indexPath) as! CollectionViewCell
self.nextMonthCollectionView.reloadData()
collectionView.reloadData()
forCollectionViewCell.Label.textColor = .white
forCollectionViewCell.Label2.backgroundColor = .red
forCollectionViewCell.Label2.layer.cornerRadius = 0.5 * forCollectionViewCell.Label2.bounds.size.width
forCollectionViewCell.Label2.clipsToBounds = true
}
}
}
and this is my photo. this first photo is before I press any cell.
enter image description here
and this second photo is right after I press 13cell.
I really don't know why this happens.
I searched google looking for this information, but I didn't find an answer.
enter image description here
ps) when I don't use reloadData() function.. I did not get error.. but
I have to use reloadData.. because I have to clean my collectionView and then make a newly selected cell round red cell.
`if nextMonthData![indexPath.row] == 0 {
forCollectionViewCell.isHidden = true
} else {
forCollectionViewCell.isHidden =false
forCollectionViewCell.Label.text = String(nextMonthData![indexPath.row])
}
return forCollectionViewCell
}
`
setting else condition that will solve your problem.
The reason behind it is when collection view dequeuing cell may be that cell is already hidden that's why its disappearing.

How can I set my DropDelegate and DragDelegate for my TableView nested in my CollectionView?

I have been working at this for a while. I am not sure if it is the best approach but I have created a collectionView with a custom UICollectionViewCell to include a tableView within. So far everything is working fine, but now I am trying to add drag interaction but can't seem to get that working.
I am trying to achieve having a interactive tableView within each CollectionViewCell if that is possible.
I did try to set my delegates here but it gave me:
Cannot assign value of type 'CommodityCropCardCell' to type 'UITableViewDropDelegate?'
Here is my UICollectionViewCell Code (CommodityCropCardCell):
class CommodityCropCardCell : UICollectionViewCell {
static var identifier : String = "CommodityCropCardCell"
weak var cropCardTableView : UITableView!
var cropItems : [cropCardInputs]!
override init(frame:CGRect){
super.init(frame:frame)
let cropCards = UITableView()
let cropItems : [cropCardInputs] = []
self.contentView.addSubview(cropCards)
self.cropCardTableView = cropCards
self.cropItems = cropItems
cropCards.dataSource = self
cropCards.delegate = self
// cropCards.dragInteractionEnabled = true
// cropCards.dragDelegate = self
// cropCards.dropDelegate = self
cropCards.register(cropCardsCell.self, forCellReuseIdentifier: "cropCardsCell")
cropCards.reloadData()
cropCards.dragInteractionEnabled = true
casesLabel.isHidden = true
self.reset()
}
required init?(coder: NSCoder) {
fatalError("init code error")
}
override func prepareForReuse() {
super.prepareForReuse()
self.reset()
}
func reset(){
print("resetting")
}
}
Here is my CropCardsViewController : UICollectionViewDataSource:
extension CropCardsViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionCropCard.dequeueReusableCell(withReuseIdentifier: CommodityCropCardCell.identifier, for: indexPath) as! CommodityCropCardCell
let data = self.data[indexPath.item]
cell.titleLabel.text = data.title
cell.casesLabel.text = "\(data.cases)"
cell.cropItems = data.cards
cell.backgroundColor = .white
cell.layer.cornerRadius = 5.0
cell.layer.masksToBounds = true
return cell
}
}

UICollectionView not populating from Array with data

I have an array of 115 objects containing name and photo url string from Firebase. Printing the data shows results so i know its pulling data correctly.
The problem is the Cells are never populated by the data.
If i add a print(name) inside the class DJProfileCell: UICollectionViewCell it never gets called so i believe thats where the issue is.
class VLCDJProfileViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var similarArtistsCollection: UICollectionView!
var ref: DatabaseReference!
let profileCellID = "cellId"
var djObject = SimilarDJ(image: "image1", name: "name1")
var djsSimilarArray = [SimilarDJ]()
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
loadDJs()
collectionView?.register(DJProfileCell.self, forCellWithReuseIdentifier: profileCellID)
}
func loadDJs(){
let allDJs = self.ref.child("DJ")
allDJs.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
let djsDict = snap.value as! [String: Any]
let PhotoUrl = djsDict["PhotoUrl"] as! String
let name = djsDict["name"] as! String + " "
self.djObject = SimilarDJ (image: PhotoUrl, name: name + " ")
self.djsSimilarArray.append(self.djObject)
self.similarArtistsCollection.reloadData();
}
})
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return djsSimilarArray.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: profileCellID, for: indexPath) as! DJProfileCell
cell.djprofile = djsSimilarArray[indexPath.item]
return cell
}
class DJProfileCell: UICollectionViewCell {
var djprofile: SimilarDJ? {
didSet {
guard let djImageProfile = djprofile?.image else {return}
guard let djNameProfile = djprofile?.name else {return}
let url = URL(string: djImageProfile)
djImageView.kf.indicatorType = .activity
djImageView.kf.setImage(with: url)
djImageLabel.text = djNameProfile
djImageLabel.adjustsFontSizeToFitWidth = true
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
func setup(){
self.backgroundColor = .white
self.addSubview(djImageView)
self.addSubview(djImageLabel)
}
let djImageView: UIImageView = {
let iv = UIImageView()
// iv.contentMode = .scaleAspectFit
// iv.backgroundColor = .green
return iv
}()
let djImageLabel: MarqueeLabel = {
let label = MarqueeLabel()
label.text = "Name"
label.textColor = UIColor.black
label.font = label.font.withSize(14)
label.textAlignment = .center
return label
}()
required init?(coder aDecoder: NSCoder) {
fatalError("init has not been implemented")
}
}
struct SimilarDJ {
let image: String?
let name: String?
}
in cell class - djImageView and djImageLabel are never added to the view's hierarchy. I see no IBOutlet and no addSubview().