2014-10-15 7 views
17

Ci sono vari temi riguardanti il ​​corretto dimensionamento un tableHeaderView con configurazione automatica (one such thread) ma tendono a pre-data IOS 8.-systemLayoutSizeFittingSize: ritorno altezza corretto per tableHeaderView sotto iOS 8

Ho una situazione con numerosi visualizzazioni di tabelle, tutte con intestazioni, con dimensioni corrette in iOS 7, ma in modo errato in iOS 8, utilizzando il codice che la maggior parte dei suddetti thread campione. Nei regolatori per le tabelle, ho il seguente metodo:

- (void)rejiggerTableHeaderView 
{ 
    self.tableView.tableHeaderView = nil; 

    UIView *header = self.headerView; 

    [header setNeedsLayout]; 
    [header layoutIfNeeded]; 

    CGFloat height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; 

    CGRect headerFrame = header.frame; 
    headerFrame.size.height = height; 

    header.frame = headerFrame; 

    self.tableView.tableHeaderView = header; 
} 

Con un'etichetta multilinea sotto iOS 7, questo dimensioni correttamente intestazione della vista tabella in questo modo:

Ma lo stesso codice eseguito sotto iOS 8 produce il seguente:

Qual è il trucco per ottenere -sys temLayoutSizeFittingSize: per restituire la dimensione corretta in iOS 8? Here's a sample project che dimostra il problema.

risposta

14

Modifica della funzione headerview alle seguenti opere per me:

- (void)rejiggerTableHeaderView 
{ 
    self.tableView.tableHeaderView = nil; 

    UIView *header = self.headerView; 
    CGRect frame = header.frame; 
    frame.size.width = self.tableView.frame.size.width; 
    header.frame = frame; 

    [header setNeedsLayout]; 
    [header layoutIfNeeded]; 

    CGFloat height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; 

    CGRect headerFrame = header.frame; 
    headerFrame.size.height = height; 

    header.frame = headerFrame; 

    self.tableView.tableHeaderView = header; 
} 
+1

Sì, lo risolve. Grazie mille. Per quel che vale, iOS 8.1 ha aggiustato le cose così si è comportato come in 7.1 (lo screenshot qui sopra è 8.0.2). Ma dopo aver fatto ulteriori spunti nel mio progetto di esempio, mi sono reso conto che entrambi gli screenshot qui sopra non sono corretti. L'altezza della vista si stava impostando per racchiudere correttamente la stringa se ruotata in modalità orizzontale, quindi la tua correzione di affermare esplicitamente quale sia la larghezza reale della vista lo corregge. –

+1

Questo non ha funzionato per me. Ho due etichette all'interno dell'intestazione, una delle quali non è ridimensionata correttamente. Sono mostrate solo tre linee. –

+5

Ho trovato che il colpevole era un vincolo mancante: è fondamentale avere un puntone dal 'UILabel' in tutte e 4 le direzioni contro il superview. Un singolo vincolo mancante impedirà il corretto funzionamento di 'systemLayoutSizeFittingSize: UILayoutFittingCompressedSize'. – SwiftArchitect

9

problema può essere nel non-set preferredMaxLayoutWidth. Se lo imposti per correggere la larghezza del marchio UIL, determinerà correttamente i vincoli.

È possibile visualizzare tutti gli UILabel nell'intestazione e impostare preferredMaxLayoutWidth in larghezza dell'etichetta.

Swift 3 esempio:

extension UITableView { 
    public func relayoutTableHeaderView() { 
     if let tableHeaderView = tableHeaderView { 
      let labels = tableHeaderView.findViewsOfClass(viewClass: UILabel.self) 
      for label in labels { 
       label.preferredMaxLayoutWidth = label.frame.width 
      } 
      tableHeaderView.setNeedsLayout() 
      tableHeaderView.layoutIfNeeded() 
      tableHeaderView.frame.height = tableHeaderView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height 
      self.tableHeaderView = tableHeaderView 
     } 
    } 

    public func findViewsOfClass<T:UIView>(viewClass: T.Type) -> [T] { 
     var views: [T] = [] 
     for subview in subviews { 
      if subview is T { 
       views.append(subview as! T) 
      } 
      views.append(contentsOf: subview.findViewsOfClass(viewClass: T.self)) 
     } 
     return views 
    } 
} 

UPDATE 2:

Inoltre è possibile avere un problema con calcolo altezza non corretto se si dispone di visualizzazione secondaria con vincolo proporzioni e allo stesso tempo proporzionale alla larghezza superview vincolo

2

Poiché questa domanda ha un anno e mezzo, ecco una versione aggiornata e completa, in Swift. Parte del codice della risposta accettata è errata o obsoleta.

func fixHeaderHeight() { 
    // Set your label text if needed 
    // ... 
    // 

    guard let header = tableView.tableHeaderView else { 
     return 
    }  
    let height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height 
    header.frame.height = height    
    tableView.tableHeaderView = header 
} 

Da qualche altra parte nel codice, è necessario impostare la preferredMaxLayoutWidth dell'etichetta (s) nell'intestazione. Questo dovrebbe essere uguale al TableView (o alla larghezza dello schermo) meno il padding. Il metodo della presa dell'etichetta didSet è un buon posto:

@IBOutlet weak var headerMessageLabel: UILabel! { 
     didSet { 
      headerMessageLabel.preferredMaxLayoutWidth = UIScreen.mainScreen().bounds.width - headerMessageLabelPadding 
     } 
    } 

Nota: Se la risposta accettata funzionato per voi, non si sta utilizzando correttamente le classi dimensionali.

0

Se l'intestazione contiene solo una singola etichetta poi utilizzo un'estensione UILabel per trovare un'altezza un'etichetta multilinea proposta una larghezza:

public extension UILabel { 
    public class func size(withText text: String, forWidth width: CGFloat) -> CGSize { 
     let measurementLabel = UILabel() 
     measurementLabel.text = text 
     measurementLabel.numberOfLines = 0 
     measurementLabel.lineBreakMode = .byWordWrapping 
     measurementLabel.translatesAutoresizingMaskIntoConstraints = false 
     measurementLabel.widthAnchor.constraint(equalToConstant: width).isActive = true 
     let size = measurementLabel.systemLayoutSizeFitting(UILayoutFittingCompressedSize) 
     return size 
    } 
} 

Nota: quanto sopra è in Swift 3 sintassi.

Con il size calcolato sopra è possibile restituire la giusta altezza nel metodo UITableViewDelegate:

func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat 
0

La soluzione adeguata per questo problema a Swift 3 sta usando questa classe invece di UILabel di serie:

class UILabelPreferedWidth : UILabel { 
    override var bounds: CGRect { 
     didSet { 
      if (bounds.size.width != oldValue.size.width) { 
       self.setNeedsUpdateConstraints() 
      } 
     } 
    } 

    override func updateConstraints() { 
     if(preferredMaxLayoutWidth != bounds.size.width) { 
      preferredMaxLayoutWidth = bounds.size.width 
     } 
     super.updateConstraints() 
    } 
} 

Assicurati inoltre di non aver disabilitato questi due nella classe Cell:

translatesAutoresizingMaskIntoConstraints = false 
contentView.translatesAutoresizingMaskIntoConstraints = false 
0

Ho avuto lo stesso problema. Questo funziona bene per me su iOS 8.4.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 
    [self.myLabel sizeToFit]; 
    [self.tableView.tableHeaderView layoutIfNeeded]; 
    return UITableViewAutomaticDimension; 
} 
Problemi correlati