In my View Controller, I have a collection view that, when rendered, displays 3 cells, each of which has a label, and a button. The label displays the name of a color, and the button has a background image that displays a color swatch.
I want it so that whenever you click on one of the buttons, that button gets a dark border around it, while the other buttons get a light border on them, to indicate the clicked-on button as being "selected". Alternately, I could probably do this by changing the image out based on the selected state of the image - but my question remains the same.
How do I access the other two buttons, to toggle their properties?
I have a script implemented that allows me to add a border to the button that somebody clicked on - but I cannot figure out how to access the other buttons, in the other cells of the CollectionView to alter their border properties as well.
Here is my source code (with irrelevant/unrelated bits stripped out)
class trimSelectorVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
@IBOutlet weak var trimSelector: UICollectionView!
struct trimObject {
var trimName: String
var trimButton: String
var trimID: Int
}
var trimArray: [trimObject] = []
override func viewDidLoad() {
super.viewDidLoad()
trimArray.append(trimObject(trimName: "Chrome", trimButton: "chrome-swatch", trimID: 0))
trimArray.append(trimObject(trimName: "Gold", trimButton: "gold-swatch", trimID: 1))
trimArray.append(trimObject(trimName: "Gun Metal", trimButton: "gunmetal-swatch", trimID: 2))
trimSelector.delegate = self
trimSelector.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return trimArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! trimSelectionCell
//Set the label text
cell.trimLabel.text = trimArray[indexPath.item].trimName
//Set the image for the button
cell.trimButton.setImage(UIImage(named: trimArray[indexPath.item].trimButton), for: UIControlState.normal)
//Sets a target function for the button
cell.trimButton.addTarget(self, action: #selector(selectedSwatch), for: .touchUpInside)
return cell
}
func selectedSwatch(sender: UIButton) {
//These set the "selected" border to the button you clicked on.
sender.layer.borderWidth = 2
sender.layer.borderColor = UIColor(red: 83/255, green: 71/255, blue: 65/255, alpha: 1.00).cgColor
}
}
Can anybody please tell me how to access the other buttons in my "selectedSwatch" function?
There are various ways you can handle this. A UICollectionView
view has a method visibleCells()
that returns an array of it's visible cells. You could use that to get pointers to your cells. You would need a way to figure out which one is which. You could use indexPath(for: UICollectionViewCell)
to figure out the index path of each cell, for example.
I don't know if this might help, but what about if you store the IndexPath on your struct on cellForItemAt method?
You will have:
struct trimObject {
var trimName: String
var trimButton: String
var trimID: Int
var idx : IndexPath
}
Then on:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! trimSelectionCell
....
trimArray[indexPath.item].idx = indexPath
....
}
And in your selectedSwatch method:
func selectedSwatch(sender: UIButton) {
//These set the "selected" border to the button you clicked on.
sender.layer.borderWidth = 2
sender.layer.borderColor = UIColor(red: 83/255, green: 71/255, blue: 65/255, alpha: 1.00).cgColor
if let cell = (sender.superview as? UICollectionViewCell) {
//Cell with the button selected:
let idx = collectionView.indexPath(for: cell)
//array of the other objects:
let allOtherObjects = trimArray.filter { ($0 as! trimObject).idx != idx }
allOtherObject.forEach({ (trimObj) in
let cell = collection.cellForItem(at: trimObj.idx)
//Do whatever yo need to do...
//cell.trimButton.layer
})
}
}
Its may be to late but still useful for somebody
Swift 4 version:
You can use sender superview as UiCollectionViewCell
* Consider hierarchy of sender in collection view cell
func selectedSwatch(sender: UIButton) {
let cell = sender.superview?.superview as! trimSelectionCell
//cell.yourbtn
}
Try this,
class trimSelectorVC: UIViewController, UICollectionViewDelegate,
UICollectionViewDataSource {
@IBOutlet weak var trimSelector: UICollectionView!
struct trimObject {
var trimName: String
var trimButton: String
var trimID: Int
var isSelected : String
}
var trimArray: [trimObject] = []
override func viewDidLoad() {
super.viewDidLoad()
trimArray.append(trimObject(trimName: "Chrome", trimButton: "chrome-swatch", trimID: 0,isSelected : "0"))
trimArray.append(trimObject(trimName: "Gold", trimButton: "gold-swatch", trimID: 1,isSelected : "0"))
trimArray.append(trimObject(trimName: "Gun Metal", trimButton: "gunmetal-swatch", trimID: 2,isSelected : "0"))
trimSelector.delegate = self
trimSelector.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return trimArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! trimSelectionCell
//Set the label text
cell.trimLabel.text = trimArray[indexPath.item].trimName
//Set the image for the button
cell.trimButton.setImage(UIImage(named:
trimArray[indexPath.item].trimButton), for: UIControlState.normal)
if(trimArray[indexPath.item].isSelected == "0"){
// button not clicked
// change shadow color of button
}
else
{
// button clicked
cell.trimButton.layer.borderWidth = 2
cell.trimButton.layer.borderColor = UIColor(red: 83/255, green:
71/255,blue: 65/255, alpha: 1.00).cgColor
}
// set tag to the button
cell.trimButton.tag = indexPath.item
//Sets a target function for the button
cell.trimButton.addTarget(self, action:#selector(selectedSwatch),
for: .touchUpInside)
return cell
}
func selectedSwatch(sender: UIButton) {
//These set the "selected" border to the button you clicked on.
let index = sender.tag
for obj in trimArray {
obj.isSelected = "0"
}
trimArray[index].isSelected = "1"
collectionView.reloadData()
}
}