2017-06-28 3 views
0

J'ai un UIStackView à l'intérieur de contentView. En fonction de l'interaction de l'utilisateur, j'ajoute/retire des éléments dans le UIStackView. Après avoir modifié les éléments dans UIStackView, je m'attends à ce que le cell mette à jour sa hauteur en conséquence. Mais, il ne met pas à jour sa hauteur à moins que j'appelle tableView.reloadData(). Mais appeler reloadData() dans cellForRowAtIndexPath/willDisplayCell devient récursif.UITableViewCell ne met pas à jour la hauteur après l'ajout d'une vue à UIStackView

Quelle est la bonne façon d'ajuster la hauteur cell au moment de l'exécution en fonction des éléments de UIStackView?

J'utilise UITableViewAutomaticDimension

Mise à jour du problème:

Here est un simple prototype de ce que je suis en train de faire.

Mon problème actuel est dequeuing la cellule.

Dans le prototype, j'ai 2 cellules réutilisables et 3 rangées. Pour les lignes 0 et 2, je supprime la file d'attente cellA et pour la ligne 1, je désqueue cellB. Voici l'aperçu de la condition que j'utilise.

if indexPath.row == 0 { 
    // dequeue cellA with 2 items in stackView 
} 

if indexPath.row == 1 { 
    // dequeue cellB with 25 items in stackView 
} 

if indexPath.row == 2 { 
    // dequeue cellA with 8 items in stackView 
} 

Mais la sortie est, ligne 0 contient 2 objets dans stackView - prévu ligne 1 contient des 25 articles en stackView - attendu ligne 2 contient 2 objets dans stackView - inattendue, la rangée 0 est dequeued

J'ai également essayé de supprimer toutes les sous-vues organisées de stackView en cellForRowAtIndexPath. Mais, ce faisant, scintille l'interface utilisateur lors du défilement. Comment puis-je obtenir la sortie désirée?

+0

avez-vous appliquer de premier plan, Trailing, Haut, Bas pour des contraintes ContentView pour StackView? – KKRocks

+0

Oui .. S'il vous plaît vérifier la source ci-joint – iOS

Répondre

1

Je crois que le problème est quand vous ajoutez des vues à la vue de la pile.

En général, l'ajout d'éléments doit avoir lieu lorsque la cellule est initialisée.

willDisplay cell: est où l'on gère modifiant attributs du contenu des cellules.

Si vous déplacez votre code de willDisplay cell: à cellForRowAt indexPath:, vous devriez voir une grande différence.

Je viens de faire une modification au code que vous avez lié à, et les lignes sont maintenant auto-dimensionnement en fonction du contenu de la vue de la pile.En regardant votre code mis à jour ... le problème était toujours que vous ajoutiez vos votredispositions au mauvais endroit. Et vous le composez en appelant reloadData().

Deuxième édition: Oublié de gérer les sous-vues ajoutées précédemment lorsque les cellules sont réutilisées.

code mis à jour ... remplacer votre code ViewController avec:

// 
// ViewController.swift 
// 

import UIKit 

class ViewController: UITableViewController { 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     tableView.tableFooterView = UIView() 
     tableView.estimatedRowHeight = 56 
    } 

    override func numberOfSections(in tableView: UITableView) -> Int { 
     return 1 
    } 

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return 3 
    } 

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 

     var cell = UITableViewCell() 

     if indexPath.row == 0 || indexPath.row == 2 { 
      cell = tableView.dequeueReusableCell(withIdentifier: "cell")! 

      if let stackView = cell.viewWithTag(999) as? UIStackView { 
       let numberOfItemsInStackView = (indexPath.row == 0) ? 2 : 8 
       let color = (indexPath.row == 0) ? UIColor.gray : UIColor.black 

       // cells are reused, so clear out any previously added subviews... 
       // but leave the first view that is part of the cell prototype 
       while stackView.arrangedSubviews.count > 1 { 
        stackView.arrangedSubviews[1].removeFromSuperview() 
       } 

       // use "i" so we can count 
       for i in 1...numberOfItemsInStackView { 

        // use label instead of view so we can number them for testing 
        let newView = UILabel() 
        newView.text = "\(i)" 
        newView.textColor = .yellow 

        // add a border, so we can see the frames 
        newView.layer.borderWidth = 1.0 
        newView.layer.borderColor = UIColor.red.cgColor 

        newView.backgroundColor = color 
        let heightConstraint = newView.heightAnchor.constraint(equalToConstant: 54) 
        heightConstraint.priority = 999 
        heightConstraint.isActive = true 
        stackView.addArrangedSubview(newView) 
       } 
      } 

     } 

     if indexPath.row == 1 { 
      cell = tableView.dequeueReusableCell(withIdentifier: "lastCell")! 

      if let stackView = cell.viewWithTag(999) as? UIStackView { 
       let numberOfItemsInStackView = 25 

       // cells are reused, so clear out any previously added subviews... 
       // but leave the first view that is part of the cell prototype 
       while stackView.arrangedSubviews.count > 1 { 
        stackView.arrangedSubviews[1].removeFromSuperview() 
       } 

       // use "i" so we can count 
       for i in 1...numberOfItemsInStackView { 

        // use label instead of view so we can number them for testing 
        let newView = UILabel() 
        newView.text = "\(i)" 
        newView.textColor = .yellow 

        // add a border, so we can see the frames 
        newView.layer.borderWidth = 1.0 
        newView.layer.borderColor = UIColor.red.cgColor 

        newView.backgroundColor = UIColor.darkGray 
        let heightConstraint = newView.heightAnchor.constraint(equalToConstant: 32) 
        heightConstraint.priority = 999 
        heightConstraint.isActive = true 
        stackView.addArrangedSubview(newView) 
       } 
      } 

     } 

     return cell 

    } 

// override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { 
//  if cell.reuseIdentifier == "cell" { 
//   if let stackView = cell.viewWithTag(999) as? UIStackView { 
//    let numberOfItemsInStackView = (indexPath.row == 0) ? 2 : 8 
//    let color = (indexPath.row == 0) ? UIColor.gray : UIColor.black 
//    guard stackView.arrangedSubviews.count == 1 else { return } 
//    for _ in 1...numberOfItemsInStackView { 
//     let newView = UIView() 
//     newView.backgroundColor = color 
//     let heightConstraint = newView.heightAnchor.constraint(equalToConstant: 54) 
//     heightConstraint.priority = 999 
//     heightConstraint.isActive = true 
//     stackView.addArrangedSubview(newView) 
//    } 
//    tableView.reloadData() 
//   } 
//  } 
//   
//  if cell.reuseIdentifier == "lastCell" { 
//   if let stackView = cell.viewWithTag(999) as? UIStackView { 
//    let numberOfItemsInStackView = 25 
//    guard stackView.arrangedSubviews.count == 1 else { return } 
//    for _ in 1...numberOfItemsInStackView { 
//     let newView = UIView() 
//     newView.backgroundColor = UIColor.darkGray 
//     let heightConstraint = newView.heightAnchor.constraint(equalToConstant: 32) 
//     heightConstraint.priority = 999 
//     heightConstraint.isActive = true 
//     stackView.addArrangedSubview(newView) 
//    } 
//    tableView.reloadData() 
//   } 
//  } 
// } 

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 
     return UITableViewAutomaticDimension 
    } 
} 
+0

J'ai mis à jour le problème que je fais face. Problème réel Je suis confronté à nous déqueuing la cellule. J'ai également mis à jour la source définissant le problème – iOS

+0

Merci pour la mise à jour du code. J'ai utilisé votre code dans le prototype. Il y a un problème dequeuing avec cela. La 3ème rangée devrait avoir 8 items, mais elle n'en contient que 2 – iOS

+0

Oui - j'avais légèrement changé de dimension pour pouvoir voir les trois rangées en même temps ... ce qui m'a fait oublier que j'avais oublié de gérer supprimer les vues précédemment ajoutées lorsque les cellules sont réutilisées. Voir mon code "Second Edit". – DonMag

2

Essayez de recharger uniquement la cellule en utilisant: https://developer.apple.com/documentation/uikit/uitableview/1614935-reloadrows

code Exemple

Voici un exemple. Nous avons des cellules de vue de table de base (TableViewCell) à l'intérieur d'un contrôleur de vue. Les cellules ont deux étiquettes dans une vue de pile. Nous pouvons cacher ou montrer la deuxième étiquette en utilisant les méthodes collapse/reveal.

class TableViewCell : UITableViewCell { 
    @IBOutlet private var stackView: UIStackView! 
    @IBOutlet private var firstLabel: UILabel! 
    @IBOutlet private var secondLabel: UILabel! 

    func collapse() { 
     secondLabel.isHidden = true 
    } 

    func reveal() { 
     secondLabel.isHidden = false 
    } 
} 

class ViewController : UIViewController { 

    @IBOutlet var tableView: UITableView! 

    fileprivate var collapsedCells: Set<IndexPath> = [] 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     tableView.rowHeight = UITableViewAutomaticDimension 
     tableView.estimatedRowHeight = 128 
    } 

    @IBAction private func buttonAction(_ sender: Any) { 
     collapseCell(at: IndexPath(row: 0, section: 0)) 
    } 

    private func collapseCell(at indexPath: IndexPath) { 
     if collapsedCells.contains(indexPath) { 
      collapsedCells.remove(indexPath) 
     } else { 
      collapsedCells.insert(indexPath) 
     } 
     tableView.reloadRows(at: [indexPath], with: .automatic) 
    } 
} 


extension ViewController : UITableViewDataSource { 
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell 
     if collapsedCells.contains(indexPath) { 
      cell.collapse() 
     } else { 
      cell.reveal() 
     } 
     return cell 
    } 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return 10 
    } 
} 
+0

J'ai essayé. Ça n'a pas fonctionné pour moi – iOS

+0

Pouvons-nous voir un peu de votre code? –

+0

J'ai joint le code à la question. J'ai commenté les lignes 'reloadRowsAtIndexPaths' dans mon code. Il suffit de les décommenter et de vérifier le comportement de l'application – iOS