2016-03-26 41 views
17

Sorpreso che questo non funzioni immediatamente, poiché sembra essere un caso d'uso importante per le viste dello stack. Ho una sottoclasse UITableViewCell che aggiunge un UIStackView a contentView. Sto aggiungendo etichette alla vista stack in tableView(_cellForRowAtIndexPath:) e tableview è impostato per utilizzare altezze di riga dinamiche, ma non sembra funzionare, almeno in Xcode 7.3. Avevo anche l'impressione che nascondere le sottoview organizzate in una vista stack fosse animabile, ma sembra anche spezzato.Altezza riga UITableView dinamica con UIStackView?

Qualche idea su come farlo funzionare correttamente?

Broken dynamic row heights

class StackCell : UITableViewCell { 
    enum VisualFormat: String { 
     case HorizontalStackViewFormat = "H:|[stackView]|" 
     case VerticalStackViewFormat = "V:|[stackView(>=44)]|" 
    } 

    var hasSetupConstraints = false 
    lazy var stackView : UIStackView! = { 
     let stack = UIStackView() 
     stack.axis = .Vertical 
     stack.distribution = .FillProportionally 
     stack.alignment = .Fill 
     stack.spacing = 3.0 
     stack.translatesAutoresizingMaskIntoConstraints = false 
     return stack 
    }() 

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) { 
     super.init(style: style, reuseIdentifier: reuseIdentifier) 
     contentView.addSubview(stackView) 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    override func updateConstraints() { 
     if !hasSetupConstraints { 
      hasSetupConstraints = true 
      let viewsDictionary: [String:AnyObject] = ["stackView" : stackView] 
      var newConstraints = [NSLayoutConstraint]() 
      newConstraints += self.newConstraints(VisualFormat.HorizontalStackViewFormat.rawValue, viewsDictionary: viewsDictionary) 
      newConstraints += self.newConstraints(VisualFormat.VerticalStackViewFormat.rawValue, viewsDictionary: viewsDictionary) 
      addConstraints(newConstraints) 
     } 
     super.updateConstraints() 
    } 

    private func newConstraints(visualFormat: String, viewsDictionary: [String:AnyObject]) -> [NSLayoutConstraint] { 
     return NSLayoutConstraint.constraintsWithVisualFormat(visualFormat, options: [], metrics: nil, views: viewsDictionary) 
    } 

class ViewController: UITableViewController { 

    private let reuseIdentifier = "StackCell" 
    private let cellClass = StackCell.self 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     configureTableView(self.tableView) 
    } 

    private func configureTableView(tableView: UITableView) { 
     tableView.registerClass(cellClass, forCellReuseIdentifier: reuseIdentifier) 
     tableView.separatorStyle = .SingleLine 
     tableView.estimatedRowHeight = 88 
     tableView.rowHeight = UITableViewAutomaticDimension 
    } 

    private func newLabel(title: String) -> UILabel { 
     let label = UILabel() 
     label.text = title 
     return label 
    } 

    // MARK: - UITableView 
    override func numberOfSectionsInTableView(tableView: UITableView) -> Int { 
     return 4 
    } 

    override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 
     return 44.0 
    } 

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

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
     let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath) as! StackCell 
     cell.stackView.arrangedSubviews.forEach({$0.removeFromSuperview()}) 
     cell.stackView.addArrangedSubview(newLabel("\(indexPath.section)-\(indexPath.row)")) 
     cell.stackView.addArrangedSubview(newLabel("Second Label")) 
     cell.stackView.addArrangedSubview(newLabel("Third Label")) 
     cell.stackView.addArrangedSubview(newLabel("Fourth Label")) 
     cell.stackView.addArrangedSubview(newLabel("Fifth Label")) 
     return cell 
    } 

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
     let cell = tableView.cellForRowAtIndexPath(indexPath) as! StackCell 
     for (idx, view) in cell.stackView.arrangedSubviews.enumerate() { 
      if idx == 0 { 
       continue 
      } 
      view.hidden = !view.hidden 
     } 
     UIView.animateWithDuration(0.3, animations: { 
      cell.contentView.layoutIfNeeded() 
      tableView.beginUpdates() 
      tableView.endUpdates() 

     }) 
    } 
} 

risposta

16

Sembra che per far funzionare tutto questo i vincoli devono essere aggiunti nella init del UITableViewCell e aggiunto al contentView invece di vista della cellula.

enter image description here

codice Il funzionamento è simile al seguente:

import UIKit 
class StackCell : UITableViewCell { 
    enum VisualFormat: String { 
     case HorizontalStackViewFormat = "H:|[stackView]|" 
     case VerticalStackViewFormat = "V:|[stackView(>=44)]|" 
    } 

    var hasSetupConstraints = false 
    lazy var stackView : UIStackView! = { 
     let stack = UIStackView() 
     stack.axis = UILayoutConstraintAxis.Vertical 
     stack.distribution = .FillProportionally 
     stack.alignment = .Fill 
     stack.spacing = 3.0 
     stack.translatesAutoresizingMaskIntoConstraints = false 
     stack.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical) 
     return stack 
    }() 

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) { 
     super.init(style: style, reuseIdentifier: reuseIdentifier) 
     contentView.addSubview(stackView) 
     addStackConstraints() 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    private func addStackConstraints() { 
     let viewsDictionary: [String:AnyObject] = ["stackView" : stackView] 
     var newConstraints = [NSLayoutConstraint]() 
     newConstraints += self.newConstraints(VisualFormat.HorizontalStackViewFormat.rawValue, viewsDictionary: viewsDictionary) 
     newConstraints += self.newConstraints(VisualFormat.VerticalStackViewFormat.rawValue, viewsDictionary: viewsDictionary) 
     contentView.addConstraints(newConstraints) 
     super.updateConstraints() 
    } 

    private func newConstraints(visualFormat: String, viewsDictionary: [String:AnyObject]) -> [NSLayoutConstraint] { 
     return NSLayoutConstraint.constraintsWithVisualFormat(visualFormat, options: [], metrics: nil, views: viewsDictionary) 
    } 
} 
+3

Ogni volta che ho posto una domanda in cui sto scrivendo UIStackViews di programmazione, tutti odiano su di me. Quindi sono felice di vedere qualcun altro a farlo. Anche grazie per la risposta;) – Trip

+1

@Trip +1 per programmaticamente – netigger

+0

Ho anche dovuto impostare 'EstimateRowHeight' sul TableView e poi ha iniziato magicamente a funzionare! – Inti