J'ai un UITableView avec un UITableViewCell personnalisé. Chaque cellule contient un bouton et je voudrais rendre tous les boutons non cliquables lorsqu'un bouton est cliqué. Il est facile d'accéder à la cellule qui contient le bouton cliqué, mais je dois également accéder à toutes les autres cellules pour rendre leur bouton non cliquable.
Donc, lorsqu'un bouton est cliqué dans une cellule, je dois parcourir toutes les autres cellules ... J'ai trouvé un moyen de remonter la hiérarchie afin que dans la méthode d'action du bouton, je monte d'une couche au-dessus pour accéder à UITableView et à partir de là, je peux accéder à chaque cellule et à partir de chaque cellule, je peux accéder à leur bouton et modifier le isUserInteractionEnabled. Cependant, cela ne semble pas être une bonne pratique pour qu'une cellule accède à la TableView puis à toutes les autres cellules.
class AnswerCell2: UITableViewCell { let answerTextButton: UIButton = { let answerButton = UIButton() answerButton.setTitle("initial text", for: .normal) return answerButton }() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String!) { answerTextButton.addTarget(self, action: #selector(answerClicked), for: .touchUpInside) } @objc func answerClicked(sender: UIButton) { // HERE I CAN ACCESS EASILY THE CELL WHERE THE BUTTON WAS CLICKED // AND THEN USE THE TABLEVIEW TO ACCESS OTHER CELLS AND THEIR BUTTONS // BUT THIS IS NOT A NICE WAY }
J'ai donc une solution comme je l'ai dit mais je J'aimerais plus une belle façon de le faire. Toutes les solutions que je trouve en ligne concernent la façon d'accéder à la cellule où le bouton a été cliqué mais celle-ci est facile, ce dont j'ai besoin est d'accéder aux autres cellules et j'aimerais éviter de le faire dans la méthode d'action answerClicked () si possible afin que le code reste propre.
Merci.
3 Réponses :
Je ne sais pas pourquoi vous devez parcourir la hiérarchie et modifier spécifiquement les caractéristiques des cellules existantes à l'écran.
Il suffit de stocker une valeur qui représente l'index du bouton sélectionné.
var indexPathForSelectedButton: IndexPath?
À chaque fois que cela change, mettez à jour l'index dans func answerClicked (sender: UIButton)
et rechargez la vue de table.
dans la cellule de la méthode at, vérifiez si l'indexPath actuel est le même que celui stocké et si c'est le cas, activez le bouton, désactivez sinon
Le rechargement de la vue de la table entière est un peu drastique. Il vaudrait mieux recharger les cellules visibles ou même mettre à jour directement le bouton dans les cellules visibles.
@ Paulw11 Pas vraiment, seules les cellules visibles seraient de toute façon rechargées en raison de la réutilisation.
Merci pour votre réponse @Scriptable, j'ai sélectionné l'autre réponse car je voulais éviter d'accéder à la tableview depuis la cellule (ma réponseClicked est dans la classe de cellule personnalisée), sauf si j'ai mal compris votre réponse.
@Scriptable, cela peut être i dans ce cas, mais si vous avez des cellules de hauteur variable, vous pouvez obtenir un scintillement et des cellules sautant car la vue de la table doit recalculer les hauteurs hors écran.
Vous pouvez créer une fermeture
dans UITableViewCell
personnalisé et l'appeler chaque fois qu'un bouton
est enfoncé dans la cellule
, c'est-à-dire
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell cell.textLabel?.text = arr[indexPath.row] cell.handler = { if let visibleCells = tableView.visibleCells as? [TableViewCell] { visibleCells.forEach({ $0.button.isEnabled = ($0 === cell) }) } } return cell }
Maintenant, définissez la fermeture
dans la méthode tableView (_: cellForRowAt :)
et utilisez visibleCells code > propriété pour activer / désactiver les
boutons
dans d'autres cellules
, c'est-à-dire
class TableViewCell: UITableViewCell { @IBOutlet weak var button: UIButton! var handler: (()->())? @IBAction func buttonClicked(_ sender: UIButton) { handler?() } }
Dans Si vous souhaitez conserver les états activer / désactiver bouton
lors du rechargement, vous devez stocker dans votre modèle
.
p >
Vous devrez conserver le paramètre quelque part s'il y a une chance que le tableau puisse encore défiler et afficher de nouvelles cellules non mises à jour via visibleCells
. Dans ce cas, l'état actuel (pourrait simplement être un booléen sur le VC) serait nécessaire dans cellForRowAt
pour garantir que ces cellules ont également leurs boutons correctement activés / désactivés.
Merci @PGDev, cela semble être une bonne solution, je vais y aller.
Ceci pourrait être réalisé dans une approche relativement légère par des fermetures ou des fonctions de délégation. Étant donné que tableView est déjà lourde en délégués, je préférerais légèrement cette approche.
créer un protocole simple pour permettre à la cellule d'informer le viewController
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = //dequeue cell and configure as normal cell.delegate. = self cell.button.isEnabled = buttonsAreEnabled return cell }
Ajouter une variable de délégué à votre classe AnswerCell2
func cellButtonChangedSate(enabled: Bool) { buttonsAreEnabled = enabled if let visibleCells = tableView.visibleCells as? [AnswerCell2] { visibleCells.forEach { $0.button.isEnabled = enabled } } }
et adaptez votre answerClicked (sender: UIButton)
pour appeler la méthode déléguée
delegate?.cellButtonChangedState(enabled: sender.isEnabled)
Si un bouton est cliqué une fois et que tous les autres sont rendus non cliquables, alors quand un autre bouton peut-il redevenir cliquable?