I have given constraints for image and label like this
Image constraints. Label Constraints
code: with this code i am able to get selectedNamesArray
but unable to change cell colour. where am i wrong? is there anything wrong in storyboard constraints so that cell BG is not changing? or any other coding mistake? could anyone please explain the issue and the solution for cell background change
class TestCollectionCell: UICollectionViewCell{
@IBOutlet weak var roundImg: UIImageView!
@IBOutlet weak var titleLbl: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func layoutSubviews() {
super.layoutSubviews()
roundImg.layer.cornerRadius = roundImg.frame.width / 2
roundImg.contentMode = .scaleToFill
roundImg.clipsToBounds = true
}
}
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
let layOut = UICollectionViewFlowLayout()
layOut.scrollDirection = .vertical
collectionView.collectionViewLayout = layOut
collectionView.allowsMultipleSelection = true
GenericCodableServicecall()
}
var cvWidth: CGFloat = -1.0
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if cvWidth != collectionView.frame.size.width {
cvWidth = collectionView.frame.size.width
if let fl = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
let nColumns: Int = 4
let sideSpace: CGFloat = fl.sectionInset.left + fl.sectionInset.right
let totalEmptyspace: CGFloat = sideSpace + (CGFloat(nColumns) * 3.0)
let w = (cvWidth - totalEmptyspace) / CGFloat(nColumns)
fl.itemSize = .init(width: w, height: w)
fl.minimumInteritemSpacing = 0.0
}
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
namesArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TestCollectionCell", for: indexPath) as! TestCollectionCell
cell.layoutIfNeeded()
cell.titleLbl.text = namesArray[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("in select..")
let cell = collectionView.cellForItem(at: indexPath) as! TestCollectionCell
let selectedName = namesArray[indexPath.row]
if let inx = selectedNamesArray.firstIndex(of: selectedName){
selectedNamesArray.remove(at: inx)
cell.backgroundColor = UIColor.red
}
else{
selectedNamesArray.append(selectedName)
cell.backgroundColor = UIColor.yellow
}
print(selectedNamesArray)
}
unable to change cell background when i select/deselect always showing green background only.
EDIT:
// MARK: - TestAPIModel
struct TestAPIModel: Codable {
let page, perPage, total, totalPages: Int
var data: [Datum]
let support: Support
enum CodingKeys: String, CodingKey {
case page
case perPage = "per_page"
case total
case totalPages = "total_pages"
case data, support
}
}
// MARK: - Datum
struct Datum: Codable {
let id: Int
let name: String
let year: Int
let color, pantoneValue: String
var isSelected: Bool = false
enum CodingKeys: String, CodingKey {
case id, name, year, color
case pantoneValue = "pantone_value"
case isSelected = "is_selected"
}
}
after changing model like above o/p:
decodingFailed(Alamofire.AFError.responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.decodingFailed(error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "is_selected", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: "is_selected", intValue: nil) ("is_selected").", underlyingError: nil)))))
this is my serviceCAll case here how to check nil data please guide
var jsonData: TestAPIModel? { didSet{ print(jsonData?.data) }
}
NetworkService.request("https://reqres.in/api/unknown", method: .get, parameters: parameters) { (result: Result<TestAPIModel, APIError>) in
switch result {
case .success(let user):
print("response \(user)")
self.jsonData = user
self.collectionView.reloadData()
case .failure(let error):
print("Error: \(error)")
}
}
An extra array for the selected
state is very bad practice. It's cumbersome to maintain and you have to set the color accordingly in cellForItemAt
because cells are reused when the user scrolls.
A better way is a struct for the data source with a member isSelected
struct Person {
let name: String
var isSelected = false
}
Then the data source array is
var people = [Person]()
and the data source and methods are
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
people.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TestCollectionCell", for: indexPath) as! TestCollectionCell
cell.layoutIfNeeded()
let person = people[indexPath.row]
cell.titleLbl.text = person.name
cell.backgroundColor = person.isSelected ? .red : .yellow
return cell
}
In didSelect
just toggle isSelected
of the item at given indexPath
and reload the item
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("in select..")
people[indexPath.row].isSelected.toggle()
collectionView.reloadItems(at: [indexPath])
}