L'API corretta da utilizzare è UIView systemLayoutSizeFittingSize:, passando UILayoutFittingCompressedSizeo UILayoutFittingExpandedSize.
Per un normale UIViewautolayout dovrebbe funzionare solo se i tuoi vincoli sono corretti. Se vuoi usarlo su un UITableViewCell(per determinare l'altezza della riga, ad esempio), dovresti chiamarlo contro la tua cella contentViewe afferrare l'altezza.
Ulteriori considerazioni esistono se si hanno una o più UILabel nella propria vista che sono multilinea. Per questi è imperativo che la preferredMaxLayoutWidthproprietà sia impostata correttamente in modo tale che l'etichetta fornisca un valore corretto intrinsicContentSize, che verrà utilizzato nel systemLayoutSizeFittingSize'scalcolo.
MODIFICA: su richiesta, aggiungendo un esempio di calcolo dell'altezza per una cella della vista tabella
L'uso del layout automatico per il calcolo dell'altezza della cella non è molto efficiente ma è sicuramente conveniente, soprattutto se si dispone di una cella con un layout complesso.
Come ho detto sopra, se stai usando una multilinea UILabelè fondamentale sincronizzare la preferredMaxLayoutWidthlarghezza dell'etichetta. Uso una UILabelsottoclasse personalizzata per fare questo:
@implementation TSLabel
- (void) layoutSubviews
{
[super layoutSubviews];
if ( self.numberOfLines == 0 )
{
if ( self.preferredMaxLayoutWidth != self.frame.size.width )
{
self.preferredMaxLayoutWidth = self.frame.size.width;
[self setNeedsUpdateConstraints];
}
}
}
- (CGSize) intrinsicContentSize
{
CGSize s = [super intrinsicContentSize];
if ( self.numberOfLines == 0 )
{
// found out that sometimes intrinsicContentSize is 1pt too short!
s.height += 1;
}
return s;
}
@end
Ecco una sottoclasse di UITableViewController inventata che dimostra heightForRowAtIndexPath:
#import "TSTableViewController.h"
#import "TSTableViewCell.h"
@implementation TSTableViewController
- (NSString*) cellText
{
return @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
}
#pragma mark - Table view data source
- (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView
{
return 1;
}
- (NSInteger) tableView: (UITableView *)tableView numberOfRowsInSection: (NSInteger) section
{
return 1;
}
- (CGFloat) tableView: (UITableView *) tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath
{
static TSTableViewCell *sizingCell;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sizingCell = (TSTableViewCell*)[tableView dequeueReusableCellWithIdentifier: @"TSTableViewCell"];
});
// configure the cell
sizingCell.text = self.cellText;
// force layout
[sizingCell setNeedsLayout];
[sizingCell layoutIfNeeded];
// get the fitting size
CGSize s = [sizingCell.contentView systemLayoutSizeFittingSize: UILayoutFittingCompressedSize];
NSLog( @"fittingSize: %@", NSStringFromCGSize( s ));
return s.height;
}
- (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath
{
TSTableViewCell *cell = (TSTableViewCell*)[tableView dequeueReusableCellWithIdentifier: @"TSTableViewCell" ];
cell.text = self.cellText;
return cell;
}
@end
Una semplice cella personalizzata:
#import "TSTableViewCell.h"
#import "TSLabel.h"
@implementation TSTableViewCell
{
IBOutlet TSLabel* _label;
}
- (void) setText: (NSString *) text
{
_label.text = text;
}
@end
Ed ecco una foto dei vincoli definiti nello Storyboard. Si noti che non ci sono vincoli di altezza / larghezza sull'etichetta - questi sono dedotti da quelli dell'etichetta intrinsicContentSize:
