L'API corretta da utilizzare è UIView systemLayoutSizeFittingSize:
, passando UILayoutFittingCompressedSize
o UILayoutFittingExpandedSize
.
Per un normale UIView
autolayout 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 contentView
e afferrare l'altezza.
Ulteriori considerazioni esistono se si hanno una o più UILabel nella propria vista che sono multilinea. Per questi è imperativo che la preferredMaxLayoutWidth
proprietà sia impostata correttamente in modo tale che l'etichetta fornisca un valore corretto intrinsicContentSize
, che verrà utilizzato nel systemLayoutSizeFittingSize's
calcolo.
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 preferredMaxLayoutWidth
larghezza dell'etichetta. Uso una UILabel
sottoclasse 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
: