0
votes

Tapping on UICollectionViewCell Button

I have a UICollectionView and a UITableView in a UIViewController. Selecting rows in the UITableView adds items to the UICollectionView and in the same manner deselecting rows in the UITableView removes the items from the UICollectionView. This is done by adding/removing the UITableView object to an array of its class. If the table has been selected (user has been added to the array) the accessoryType for that cell changes to checkmark and when the user is removed it changes back to none.

var selectedUsers = [User]()

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if let cell = tableView.cellForRow(at: indexPath) as? NewGroupUserTableViewCell {
            if tableView.cellForRow(at: indexPath)?.accessoryType == .checkmark {
                tableView.cellForRow(at: indexPath)?.accessoryType = .none
                if let user = cell.user {
                    self.selectedUsers.removeAll{$0.uid == user.uid}
                }
            } else {
                tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
                    if let user = cell.user {
                        self.selectedUsers.append(user)
                    }
            }
            self.collectionView.reloadData()
        }
    }

In the UICollectionViewCell class I have a protocol to call a function in the UIViewController when the delete button is tapped. Whenever the delete button is tapped, the user is deleted from the array therefore removing the item from the UICollectionView. The problem I’m running into is updating the accessoryType in the UITableViewCell when the delete button in the UICollectionViewCell is tapped. I don’t know how to reference the particular UITableViewCell from the UICollectionView.

The best way I can come up with is with a for loop for the UITableViewCells looking for an object with a matching ID then updating the accessoryType if a match is found. That doesn’t always work.

Here is the function in my UICollectionViewCell class delegate.

func didTapDelete(user: User) {
    let selectedUser = selectedUsers.first(where: { $0.uid == user.uid })
    for section in 0 ..< 2 {
        let rowCount = tableView.numberOfRows(inSection: section)

        for row in 0 ..< rowCount {
            let cell = tableView.cellForRow(at: NSIndexPath(row: row, section: section) as IndexPath) as! NewGroupUserTableViewCell
            if cell.user.uid == selectedUser?.uid {
                cell.accessoryType = .none
            }
        }
    }

    selectedUsers.removeAll{$0.uid == user.uid}
    self.collectionView.reloadData()
}

How can I refer to a UITableViewCell when tapping on a button from a UICollectionViewCell?

1
Did you tried with tableView!.reloadRows(at: [indexPath], with: UITableViewRowAnimation.automatic) ?Nazmul Hasan
No, because they will not necessarily have the same index. I can select UITableViewCells 0, 1 and 3 but that will make indexes in UICollectionView 0,1 and 2.GIJoeCodes

1 Answers

1
votes

First of all your approach can be simplified, don't try to change the tableviewcell's property inside the collection view delegate:

In your cellForRowAt method do as below, move the selection style updation to this method:

func tableView(_ tableView: UITableView,
               cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "NewGroupUserTableViewCell",
                                             for: indexPath) as! NewGroupUserTableViewCell
    let user = users[indexPath.row]
    cell.textLabel?.text = user.uid // Whatever your want to show here, Did this for sample
    if itemsSelected.contains(user) {
        cell.accessoryType = .checkmark
    } else {
        cell.accessoryType = .none
    }
    return cell
}

In the UICollectionViewCell Delegate Method do as below: Here I am adding one more parameter to pass the cell back.

func didTapOnDelete(_ cell: ItemCollectionViewCell, item: User) {
    guard let indexPath = collectionView.indexPath(for: cell) else { return }
    if let index = itemsSelected.firstIndex(of: item) {
        itemsSelected.remove(at: index)
    } else {
        itemsSelected.append(item)
    }
    collectionView.deleteItems(at: [indexPath])
    tableView.reloadData()
}

And your didSelectRowAt will be as below:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let userToAdd = users[indexPath.row]
    if let index = itemsSelected.firstIndex(of: userToAdd) {
        itemsSelected.remove(at: index)
    } else {
        itemsSelected.append(userToAdd)
    }
    collectionView.reloadData()
    tableView.reloadRows(at: [indexPath], with: .automatic)
}

Note: For the ease in comparing I have made the User class Equatable as below:

extension User: Equatable {
   static func == (lhs: User, rhs: User) -> Bool {
    return lhs.uid == rhs.uid
   }
}

Also assumption is made that same item cannot be added repeatedly to collectionView.

Hope it helps!.