Using a button to deselect cells in a collectionvi

2019-09-19 08:10发布

问题:

I have two collection views. Tapping unselected cells in Collection View 1 selects them, and adds the selected cell to Collection View 2. Tapping on selected cells in Collection View 1 (allHobbiesCV) will unselect them and remove them from Collection View 2 (myHobbiesCV). Essentially, all it's doing is toggling.

Cells in Collection View 2 can also be manually removed by selecting as few or many as desired, then pressing a 'Remove' button. This process works great, except the cells in Collection View 1 still remain selected, even if that particular cell was removed from Collection View 2.

How do I use the remove button to deselect cells from Collection View 1 if they were manually selected and removed from Collection View 2?

Class level -

var allHobbiesArray = [String]()
var allHobbiesArraySelected = [String]()

var myHobbiesArray = [String]()
var myHobbiesArraySelected = [String]()

didSelectItemAt

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {


    // All Hobbies
    if collectionView == allHobbiesCV {
        let item = allHobbiesArray[indexPath.item]
        let cell = allHobbiesCV.cellForItem(at: indexPath) as! AllHobbiesCell

        if let itemIndex = allHobbiesArraySelected.index(of:item) {
            // DID DESELECT
            allHobbiesArraySelected.remove(at:itemIndex)
            myHobbiesArray.remove(at: itemIndex)
            myHobbiesCV.deleteItems(at: [IndexPath(item: itemIndex, section:0)])
            cell.backgroundColor = UIColor.brown
        }
        else {
            // DID SELECT
            allHobbiesArraySelected.insert(item, at: 0)
            myHobbiesArray.insert(item, at: 0)
            myHobbiesCV.insertItems(at: [IndexPath(item: 0, section:0)])
            cell.backgroundColor = UIColor.green
        }

        allHobbiesCV.deselectItem(at: indexPath, animated: false)

        for cell in myHobbiesCV.visibleCells {
            cell.backgroundColor = UIColor.white
        }
        myHobbiesArraySelected.removeAll()
        //myHobbiesCV.reloadData() // needed?
    }

    // My Hobbies
    else {
        let item = myHobbiesArray[indexPath.item]
        let cell = myHobbiesCV.cellForItem(at: indexPath) as! MyHobbiesCell

        if let itemIndex = myHobbiesArraySelected.index(of:item) {
            // DID DESELECT
            myHobbiesArraySelected.remove(at: itemIndex)
            cell.backgroundColor = UIColor.white
        }
        else {
            // DID SELECT
            myHobbiesArraySelected.insert(item, at: 0)
            cell.backgroundColor = UIColor.red
        }
        myHobbiesCV.deselectItem(at: indexPath, animated: true)
    }
}

cellForItem

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    if collectionView == allHobbiesCV {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ALL", for: indexPath) as! AllHobbiesCell
        cell.allHobbiesCellLabel.text = allHobbiesArray[indexPath.item]

        let allHobbies = allHobbiesArray[indexPath.item]
        if allHobbiesArraySelected.index(of: allHobbies) != nil {
            cell.backgroundColor = UIColor.green
        }
        else {
            cell.backgroundColor = UIColor.brown
        }

        return cell
    }

    else { // myHobbiesCV
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MY", for: indexPath) as! MyHobbiesCell
        cell.myHobbiesCellLabel.text = myHobbiesArray[indexPath.item]

        let myHobbies = myHobbiesArray[indexPath.item]
        if myHobbiesArraySelected.index(of: myHobbies) != nil {
            cell.backgroundColor = UIColor.red
        }
        else {
            cell.backgroundColor = UIColor.white
        }


        return cell
    }

}

numberOfItemsInSection

    if collectionView == allHobbiesCV {
        return allHobbiesArray.count
    }
    else {
        return myHobbiesArray.count
    }

Delete button

@IBAction func deleteHobbyButtonPressed(_ sender: UIButton) {

    print("all Hobbies - \(allHobbiesCV.indexPathsForSelectedItems!)")

    if let selectedItemPaths = myHobbiesCV.indexPathsForSelectedItems {

        var allItemIndexPaths = [IndexPath]()
        var tempSelectedItems = Array(allHobbiesArraySelected) // Need to use a temporary copy otherwise the element indexes will change
        for itemPath in selectedItemPaths {

            let removeItem = allHobbiesArraySelected[itemPath.item]
            if let removeIndex = tempSelectedItems.index(of: removeItem) {
                print("if let removeIndex")
                tempSelectedItems.remove(at: removeIndex)
            }

            if let allItemsIndex = allHobbiesArray.index(of: removeItem) {
                print("if let allItemsIndex")
                allItemIndexPaths.append(IndexPath(item: allItemsIndex, section: 0))
            }
        }

        allHobbiesArraySelected = tempSelectedItems // Selected items array without the removed items
        myHobbiesCV.deleteItems(at:selectedItemPaths)
        myHobbiesCV.reloadData()
        allHobbiesCV.reloadItems(at: allItemIndexPaths)  // Reload to update the selected status
    }

}

The problem now is nothing is evaluating in the remove button. That first print statement always returns an empty array. And nothing prints in the if let check. Is there a way to use myHobbiesArraySelected instead of indexPathsForSelectedItems? (Since I'm saving the selected items in an array now) Along with the original intended functionality of deselecting the cell in allHobbiesCV if it was manually deleted in myHobbiesCV.

Thanks friends.

回答1:

It is a bad idea to store selected index paths, as these are coupled to the collection view. If you store the selected items then you can always determine the appropriate index path, using the item's index in the array. You can also determine an item quickly from a given index path.

In the code below I have used the type Item for your underlying item, but it could be String or Int or any object type. If you use your own class or struct, ensure you make it conform to Equatable and Hashable.

var allItems:[Item]
var selectedItems[Item]

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    if collectionView == allItemsCV {
        let item = allItems[IndexPath.row]
        if let itemIndex = selectedItems.index(of:item) {
            selectedItems.remove(at:itemIndex)
            selectedItemsCV.deleteItems(at: [IndexPath(item: itemIndex, section:0)])
        } else {
            selectedItems.insert(item, at: 0)
            selectedItemsCV.insertItems(at: [IndexPath(item: 0, section:0)])
        }
        allItemsCV.deselectItem(at: indexPath, animated: true)
       // cell for item at indexPath needs to render the selected/deselected 
          state correctly based on the item being in the selectedItems array

        allItemsCV.reloadItems(at: [indexPath])

    }
}

@IBAction func removeButtonPressed(_ sender: UIButton) {
//...
    if let selectedItemPaths = selectedItemCV.indexPathsForSelectedItems {
        var allItemIndexPaths = [IndexPath]()
        var tempSelectedItems = Array(selectedItems) // Need to use a temporary copy otherwise the element indexes will change
        for itemPath in selectedItemPaths {
            let removeItem = selectedItems[itemPath.item]
            if let removeIndex = tempSelectedItems.index(of: removeItem) {
                tempSelectedItems.remove(at: removeItem)
            }
            if let allItemsIndex = allItems.index(of: removeItem) {
                allItemIndexPaths.append(IndexPath(item: allItemsIndex, section: 0))
            }
        }
        selectedItems = tempSelectedItems // Selected items array without the removed items
        selectedItemsCV.deleteItems(at:selectedItemPaths)
        allItemsCV.reloadItems(at: allItemIndexPaths)  // Reload to update the selected status
    }
}


回答2:

Update: IndexPath conforms Equatable (see comment from @Paulw11) you compare the objects IndexPath in contains but but even if an instance of indexPath path have the same sections and rows the object itself is different.

1. solution: compare values change the contains to to compare the sections and rows

  1. solution: stick on item id stick on an unique item id which you store in the array. then you are on the more save situation, if collection1 and collection2 has different sizes and sections

i would suggest to implement solution 2