1
votes

Accéder à toutes les cellules lorsqu'un bouton dans une cellule est cliqué

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.


1 commentaires

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?


3 Réponses :


0
votes

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


4 commentaires

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.



0
votes

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 >


2 commentaires

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.



0
votes

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)


0 commentaires