2016-04-26 6 views
12

Vorrei aggiungere un'intestazione al mio TableView. Questa intestazione contiene 1 UILabel. L'altezza dell'intestazione deve essere calcolata in base al numero di righe dell'etichetta.Come si crea l'intestazione UITableView la cui altezza è determinata dall'altezza della sua etichetta?

Nel mio codice, sto aggiungendo vincoli con tutti i bordi dell'intestazione dell'etichetta <>. Questo è il mio tentativo:

//Add header to tableView 
    header = UIView() 
    header.backgroundColor = UIColor.yellowColor() 
    tableView!.tableHeaderView = header 

    //Create Label and add it to the header 
    postBody = UILabel() 
    postBody.text = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog." 
    postBody.font = UIFont(name: "Lato-Regular", size: 16.0) 
    postBody.numberOfLines = 0 
    postBody.backgroundColor = FlatLime() 
    header.addSubview(postBody) 

    //Enable constraints for each item 
    postBody.translatesAutoresizingMaskIntoConstraints = false 
    header.translatesAutoresizingMaskIntoConstraints = false 

    //Add constraints to the header and post body 
    let postBodyLeadingConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0) 
    postBodyLeadingConstraint.active = true 

    let postBodyTrailingConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0) 
    postBodyTrailingConstraint.active = true 


    let postBodyTopConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0) 
    postBodyTopConstraint.active = true 


    let postBodyBottomConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0) 
    postBodyBottomConstraint.active = true 


    //Calculate header size 
    let size = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) 
    var frame = header.frame 
    frame.size.height = size.height 
    header.frame = frame 
    tableView!.tableHeaderView = header 
    header.layoutIfNeeded() 

Questo è il mio tavolo:

let nib = UINib(nibName: "MessagesTableViewCell", bundle: nil) 
    let nibSimple = UINib(nibName: "SimpleMessagesTableViewCell", bundle: nil) 
    self.tableView!.registerNib(nib, forCellReuseIdentifier: "MessagesTableViewCell") 
    self.tableView!.registerNib(nibSimple, forCellReuseIdentifier: "SimpleMessagesTableViewCell") 
    self.tableView!.dataSource = self 
    self.tableView!.delegate = self 
    self.tableView!.rowHeight = UITableViewAutomaticDimension 
    self.tableView!.estimatedRowHeight = 100.0 
    self.tableView!.separatorStyle = UITableViewCellSeparatorStyle.None 
    self.tableView!.separatorColor = UIColor(hex: 0xf5f5f5) 
    self.tableView!.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0) 
    self.tableView!.clipsToBounds = true 
    self.tableView!.allowsSelection = false 
    self.tableView!.allowsMultipleSelection = false 
    self.tableView!.keyboardDismissMode = .OnDrag 

Come si può vedere, l'intestazione non prende in considerazione l'altezza dell'etichetta (che ho fatto NumberOfLines = 0)

Header does not auto-height

+0

È possibile pubblicare il codice del metodo principale di visualizzazione tabella? –

+0

Se si imposta un punto di interruzione come appare il fotogramma quando lo si assegna all'intestazione? – Joe

+0

Non ti mancano postBody.translatesAutoresizingMaskIntoConstraints = false? – Terry

risposta

13

UILabel s sfruttare il UIView 's intrinsicContentSize() per indicare al layout automatico quale dimensione devono essere. Per un'etichetta multilinea, tuttavia, la dimensione del contenuto intrinseco è ambigua; il tavolo non sa se dovrebbe essere corto e largo, alto e stretto, o qualsiasi altra via di mezzo.

Per combattere questo, UILabel ha una proprietà denominata preferredMaxLayoutWidth. Impostando questo si dice a un'etichetta multilinea che dovrebbe essere al massimo questa larghezza, e permette a intrinsicContentSize() di capire e restituire un'altezza appropriata per abbinare. Non impostando preferredMaxLayoutWidth nell'esempio, l'etichetta lascia la sua larghezza illimitata e quindi calcola l'altezza per una singola riga di testo lunga.

L'unica complicazione con preferredMaxLayoutWidth è che in genere non si conosce la larghezza desiderata per l'etichetta fino a quando il layout automatico non ne ha calcolato uno per l'utente. Per questo motivo, il luogo per impostare in una sottoclasse View Controller (che sembra che il tuo esempio di codice potrebbe essere da) è in viewDidLayoutSubviews:

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 
    postBody.preferredMaxLayoutWidth = CGRectGetWidth(postBody.frame) 
    // then update the table header view 
    if let header = tableView?.tableHeaderView { 
     header.frame.size.height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height 
     tableView?.tableHeaderView = header 
    } 
} 

Ovviamente, è necessario aggiungere una proprietà per il postBody etichetta per farlo funzionare.

Fammi sapere se non sei in una sottoclasse UIViewController qui e io modificherò la mia risposta.

-2

si può calcolare l'altezza di un'etichetta utilizzando la sua stringa

let labelWidth = label.frame.width 
let maxLabelSize = CGSize(width: labelWidth, height: CGFloat.max) 
let actualLabelSize = label.text!.boundingRectWithSize(maxLabelSize, options: [.UsesLineFragmentOrigin], attributes: [NSFontAttributeName: label.font], context: nil) 
let labelHeight = actualLabelSize.height 
+1

Bene, questo è per l'intestazione della sezione, non per l'intestazione della tabella. Una cosa molto diversa. – Sulthan

9

Il primo problema che abbiamo è che l'intestazione non può essere ridimensionato autolayout, per dettagli vedi Is it possible to use AutoLayout with UITableView's tableHeaderView?

Pertanto, dobbiamo calcolare l'altezza dell'intestazione manualmente, ad esempio:

@IBOutlet var table: UITableView! 

var header: UIView? 
var postBody: UILabel? 

override func viewDidLoad() { 
    super.viewDidLoad() 

    let header = UIView() 
    // don't forget to set this 
    header.translatesAutoresizingMaskIntoConstraints = true 
    header.backgroundColor = UIColor.yellowColor() 

    let postBody = UILabel() 
    postBody.translatesAutoresizingMaskIntoConstraints = false 
    postBody.text = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog." 
    postBody.font = UIFont.systemFontOfSize(16.0) 

    // don't forget to set this 
    postBody.lineBreakMode = .ByWordWrapping 
    postBody.numberOfLines = 0 

    header.addSubview(postBody) 

    let leadingConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0) 
    let trailingConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0) 
    let topConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0) 
    let bottomConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0) 

    header.addConstraints([leadingConstraint, trailingConstraint, topConstraint, bottomConstraint]) 

    self.table.tableHeaderView = header 

    self.header = header 
    self.postBody = postBody 
} 

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 

    let text = postBody!.attributedText! 

    let height = text.boundingRectWithSize(
     CGSizeMake(table.bounds.size.width, CGFloat.max), 
     options: [.UsesLineFragmentOrigin], 
     context: nil 
    ).height 

    header!.frame.size.height = height 
} 

Si potrebbe anche voler utilizzare il codice in stefandouganhyde's answer. Non importa come calcoli l'altezza. Il punto è che l'autolayout non funzionerà automaticamente per tableHeaderView.

Risultato:

resulting table

10

Attuazione utilizzando lo storyboard

  1. In UItableView add on UITableViewCell nuova UIView e lo mise UILabel li collega via Autolayout
  2. Nel UILabel mettere il numero di linee a 0.
  3. In ViewDidLoad tua UILabel chiamata un metodo sizeToFit() e specificare una dimensione per UIView, e che sarà la vostra HeaderVew headerView.frame.size.height = headerLabel.frame.size.height

Codice

@IBOutlet weak var tableView: UITableView! 
    @IBOutlet weak var headerView: UIView! 
    @IBOutlet weak var headerLabel: UILabel! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     headerLabel.text = "tableViewdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarning" 
     headerLabel.sizeToFit() 
     headerView.frame.size.height = headerLabel.frame.size.height 
    } 

ScreenShot

enter image description here

TestProject

test project link

2

Usiamo NSLayoutManager di stimare rapidamente l'altezza per gli elementi che hanno bisogno di ridimensionare in base al testo. Questa è l'idea di base:

override class func estimatedHeightForItem(text: String, atWidth width: CGFloat) -> CGFloat { 

    let storage = NSTextStorage(string: text!) 
    let container = NSTextContainer(size: CGSize(width: width, height: CGFloat.max)) 
    let layoutManager = NSLayoutManager() 
    layoutManager.addTextContainer(container) 
    storage.addLayoutManager(layoutManager) 
    storage.addAttribute(NSFontAttributeName, value: UIFont.Body, range: NSRange(location: 0, length: storage.length)) 
    container.lineFragmentPadding = 0.0 

    return layoutManager.usedRectForTextContainer(container).size.height 
} 

Beslan's answer è probabilmente la soluzione migliore per il vostro caso d'uso, ma trovo bello avere un maggiore controllo come il layout viene gestito.

-1

// potrebbe essere utile per voi.

header = UIView(frame: CGRectMake(tableview.frame.origin.x,tableview.frame.origin.y, tableview.frame.size.width, 40)) 
header.backgroundColor = UIColor.yellowColor() 

//Create Label and add it to the header 
postBody = UILabel(frame: header.frame) 
postBody.text = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog." 
postBody.font = UIFont(name: "Lato-Regular", size: 16.0) 
postBody.numberOfLines = 0 
postBody.backgroundColor = FlatLime() 
header.addSubview(postBody) 

let maximumLabelSize: CGSize = CGSizeMake(postBody.size.width, CGFloat.max); 

let options: NSStringDrawingOptions = NSStringDrawingOptions.UsesLineFragmentOrigin 
let context: NSStringDrawingContext = NSStringDrawingContext() 
     context.minimumScaleFactor = 0.8 
     let attr: Dictionary = [NSFontAttributeName: postBody.font!] 
     var size: CGSize? = postBody.text?.boundingRectWithSize(maximumLabelSize, options:options, attributes: attr, context: context).size 

let frame = header.frame 
frame.size.height = size?.height 
header.frame = frame 
postBody.frame = frame 
tableView!.tableHeaderView = header 
Problemi correlati