Jak obliczyć wysokość UILabel dynamicznie?
Chcę obliczyć liczbę linii i wysokość UILabel dynamicznie z podanego tekstu dla tego samego.
12 answers
Spróbuj tego
// UILabel *myLabel;
CGSize labelSize = [myLabel.text sizeWithFont:myLabel.font
constrainedToSize:myLabel.frame.size
lineBreakMode:NSLineBreakByWordWrapping];
CGFloat labelHeight = labelSize.height;
int lines = [myLabel.text sizeWithFont:myLabel.font
constrainedToSize:myLabel.frame.size
lineBreakMode:NSLineBreakByWordWrapping].height/16;
// '16' is font size
Lub
int lines = labelHeight/16;
NSLog(@"lines count : %i \n\n",lines);
Lub
int lines = [myLabel.text sizeWithFont:myLabel.font
constrainedToSize:myLabel.frame.size
lineBreakMode:UILineBreakModeWordWrap].height /myLabel.font.pointSize; //fetching font size from font
Używając Categories, po prostu utwórz klasę category o nazwie
UILabel+UILabelDynamicHeight.h
UILabel+UILabelDynamicHeight.m
Koniec z napięciem związanym z obliczaniem wysokości. Zapoznaj się z poniższą realizacją.
Aktualizacje dla iOS7 i powyżej, iOS 7 poniżej: dynamicznie Oblicz UILabel wysokość
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
#define iOS7_0 @"7.0"
UILabel+UILabelDynamicHeight.h
#import <UIKit/UIKit.h>
@interface UILabel (UILabelDynamicHeight)
#pragma mark - Calculate the size the Multi line Label
/*====================================================================*/
/* Calculate the size of the Multi line Label */
/*====================================================================*/
/**
* Returns the size of the Label
*
* @param aLabel To be used to calculte the height
*
* @return size of the Label
*/
-(CGSize)sizeOfMultiLineLabel;
@end
UILabel+UILabelDynamicHeight.m
#import "UILabel+UILabelDynamicHeight.h"
@implementation UILabel (UILabelDynamicHeight)
#pragma mark - Calculate the size,bounds,frame of the Multi line Label
/*====================================================================*/
/* Calculate the size,bounds,frame of the Multi line Label */
/*====================================================================*/
/**
* Returns the size of the Label
*
* @param aLabel To be used to calculte the height
*
* @return size of the Label
*/
-(CGSize)sizeOfMultiLineLabel{
//Label text
NSString *aLabelTextString = [self text];
//Label font
UIFont *aLabelFont = [self font];
//Width of the Label
CGFloat aLabelSizeWidth = self.frame.size.width;
if (SYSTEM_VERSION_LESS_THAN(iOS7_0)) {
//version < 7.0
return [aLabelTextString sizeWithFont:aLabelFont
constrainedToSize:CGSizeMake(aLabelSizeWidth, MAXFLOAT)
lineBreakMode:NSLineBreakByWordWrapping];
}
else if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(iOS7_0)) {
//version >= 7.0
//Return the calculated size of the Label
return [aLabelTextString boundingRectWithSize:CGSizeMake(aLabelSizeWidth, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{
NSFontAttributeName : aLabelFont
}
context:nil].size;
}
return [self bounds].size;
}
@end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-30 05:48:05
Wywołanie -sizeToFit
na instancji UILabel automatycznie zmieni jej rozmiar tak, aby pasował do wyświetlanego tekstu, bez konieczności obliczania. Jeśli potrzebujesz rozmiaru, możesz go pobrać z właściwości frame label.
label.numberOfLines = 0; // allows label to have as many lines as needed
label.text = @"some long text";
[label sizeToFit];
NSLog(@"Label's frame is: %@", NSStringFromCGRect(label.frame));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-24 10:38:08
Podsumowując, możesz obliczyć Wysokość etykiety, używając jej ciągu znaków i wywołując boundingRectWithSize
. Musisz podać font
jako atrybut i dołączyć .usesLineFragmentOrigin
dla etykiet wielowierszowych.
let labelWidth = label.frame.width
let maxLabelSize = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude)
let actualLabelSize = label.text!.boundingRect(with: maxLabelSize, options: [.usesLineFragmentOrigin], attributes: [.font: label.font], context: nil)
let labelHeight = actualLabelSize.height
Niektóre rozszerzenia do tego:
Wersja Swift:
extension UILabel {
func textHeight(withWidth width: CGFloat) -> CGFloat {
guard let text = text else {
return 0
}
return text.height(withWidth: width, font: font)
}
func attributedTextHeight(withWidth width: CGFloat) -> CGFloat {
guard let attributedText = attributedText else {
return 0
}
return attributedText.height(withWidth: width)
}
}
extension String {
func height(withWidth width: CGFloat, font: UIFont) -> CGFloat {
let maxSize = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)
let actualSize = self.boundingRect(with: maxSize, options: [.usesLineFragmentOrigin], attributes: [.font : font], context: nil)
return actualSize.height
}
}
extension NSAttributedString {
func height(withWidth width: CGFloat) -> CGFloat {
let maxSize = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)
let actualSize = boundingRect(with: maxSize, options: [.usesLineFragmentOrigin], context: nil)
return actualSize.height
}
}
Objective-Wersja C:
UILabel + Utility.h
#import <UIKit/UIKit.h>
@interface UILabel (Utility)
- (CGFloat)textHeightForWidth:(CGFloat)width;
- (CGFloat)attributedTextHeightForWidth:(CGFloat)width;
@end
UILabel + Utility.m
@implementation NSString (Utility)
- (CGFloat)heightForWidth:(CGFloat)width font:(UIFont *)font {
CGSize maxSize = CGSizeMake(width, CGFLOAT_MAX);
CGSize actualSize = [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : font} context:nil].size;
return actualSize.height;
}
@end
@implementation NSAttributedString (Utility)
- (CGFloat)heightForWidth:(CGFloat)width {
CGSize maxSize = CGSizeMake(width, CGFLOAT_MAX);
CGSize actualSize = [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size;
return actualSize.height;
}
@end
@implementation UILabel (Utility)
- (CGFloat)textHeightForWidth:(CGFloat)width {
return [self.text heightForWidth:width font:self.font];
}
- (CGFloat)attributedTextHeightForWidth:(CGFloat)width {
return [self.attributedText heightForWidth:width];
}
@end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-05 00:04:21
[1]}obecne rozwiązanie zostało wycofane z systemu iOS 7.
Oto zaktualizowane rozwiązanie:
+ (CGFloat)heightOfCellWithIngredientLine:(NSString *)ingredientLine
withSuperviewWidth:(CGFloat)superviewWidth
{
CGFloat labelWidth = superviewWidth - 30.0f;
// use the known label width with a maximum height of 100 points
CGSize labelContraints = CGSizeMake(labelWidth, 100.0f);
NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
CGRect labelRect = [ingredientLine boundingRectWithSize:labelContraints
options:NSStringDrawingUsesLineFragmentOrigin
attributes:nil
context:context];
// return the calculated required height of the cell considering the label
return labelRect.size.height;
}
Powodem, dla którego moje rozwiązanie jest tak skonfigurowane, jest to, że używam UITableViewCell i dynamicznie zmieniam rozmiar komórki w stosunku do tego, ile miejsca zajmie Etykieta.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-30 23:34:26
Bez wywoływania sizeToFit, możesz to wszystko zrobić numerycznie za pomocą rozwiązania plug and play:
+ (CGFloat)heightForText:(NSString*)text font:(UIFont*)font withinWidth:(CGFloat)width {
CGSize size = [text sizeWithAttributes:@{NSFontAttributeName:font}];
CGFloat area = size.height * size.width;
CGFloat height = roundf(area / width);
return ceilf(height / font.lineHeight) * font.lineHeight;
}
Używam go często dla UITableViewCells, które mają dynamicznie przydzielane wysokości.
Rozwiązuje również problem z atrybutami @Salman Zaidi.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-17 01:14:12
Skopiuj i wklej tę metodę i użyj jej w następujący sposób:
[lblText setFrame:CGRectMake(lblText.frame.origin.x, lblText.frame.origin.y, width, [self getLabelHeight:lblText])];
- (CGFloat)getLabelHeight:(UILabel*)label
{
CGSize constraint = CGSizeMake(label.frame.size.width, CGFLOAT_MAX);
CGSize size;
NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
CGSize boundingBox = [label.text boundingRectWithSize:constraint
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:label.font}
context:context].size;
size = CGSizeMake(ceil(boundingBox.width), ceil(boundingBox.height));
return size.height;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-22 13:14:43
CGSize maxSize = CGSizeMake(lbl.frame.size.width, CGFLOAT_MAX);
CGSize requiredSize = [lbl sizeThatFits:maxSize];
CGFloat height=requiredSize.height
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-27 13:17:34
Swift 4 Aby uzyskać wysokość dla NSAttributedString użyj poniższej funkcji. Gdzie width - Szerokość twojego UILabel lub UITextView
func getHeight(for attributedString: NSAttributedString, font: UIFont, width: CGFloat) -> CGFloat {
let textStorage = NSTextStorage(attributedString: attributedString)
let textContainter = NSTextContainer(size: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude))
let layoutManager = NSLayoutManager()
layoutManager.addTextContainer(textContainter)
textStorage.addLayoutManager(layoutManager)
textStorage.addAttribute(NSAttributedStringKey.font, value: font, range: NSMakeRange(0, textStorage.length))
textContainter.lineFragmentPadding = 0.0
layoutManager.glyphRange(for: textContainter)
return layoutManager.usedRect(for: textContainter).size.height
}
Aby uzyskać wysokość dla String Użyj tej funkcji, jest ona prawie identyczna jak poprzednia metoda:
func getHeight(for string: String, font: UIFont, width: CGFloat) -> CGFloat {
let textStorage = NSTextStorage(string: string)
let textContainter = NSTextContainer(size: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude))
let layoutManager = NSLayoutManager()
layoutManager.addTextContainer(textContainter)
textStorage.addLayoutManager(layoutManager)
textStorage.addAttribute(NSAttributedStringKey.font, value: font, range: NSMakeRange(0, textStorage.length))
textContainter.lineFragmentPadding = 0.0
layoutManager.glyphRange(for: textContainter)
return layoutManager.usedRect(for: textContainter).size.height
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-12 15:57:17
W moim przypadku używałem nagłówka o stałym rozmiarze dla każdej sekcji, ale z dynamicznym rozmiarem komórki w każdym nagłówku. Wysokość komórki zależy od wysokości etykiety.
Praca z:
tableView.estimatedRowHeight = SomeNumber
tableView.rowHeight = UITableViewAutomaticDimension
Działa ale przy użyciu:
tableView.reloadSections(IndexSet(integer: sender.tag) , with: .automatic)
Gdy wiele nagłówków nie jest zwiniętych, tworzy wiele błędów, takich jak powielanie nagłówków (typ nagłówka x poniżej tego samego typu) i dziwne animacje, gdy framework przeładowuje się animacją, nawet gdy używa z typem .none
(FYI, stała wysokość nagłówka i wysokość komórki działa).
Rozwiązaniem jest wykorzystanie heightForRowAt
callback i obliczenie wysokości etykiety przez siebie (Plus animacja wygląda dużo lepiej). Pamiętaj, że wysokość jest nazywana jako pierwsza .
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
let object = dataDetailsController.getRowObject(forIndexPath: indexPath)
let label = UILabel(frame: tableView.frame)
let font = UIFont(name: "HelveticaNeue-Bold", size: 25)
label.text = object?.name
label.font = font
label.numberOfLines = 0
label.textAlignment = .center
label.sizeToFit()
let size = label.frame.height
return Float(size) == 0 ? 34 : size
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-20 10:27:54
Jest to rozszerzenie, którego używam do obliczania wysokości wieloliniowych UILabel, jest to skorygowany fragment z poprzedniego postu o przepełnieniu stosu:
extension UILabel {
func estimatedHeight(forWidth: CGFloat, text: String, ofSize: CGFloat) -> CGFloat {
let size = CGSize(width: forWidth, height: CGFloat(MAXFLOAT))
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
let attributes = [NSFontAttributeName: UIFont.systemFont(ofSize: ofSize)]
let rectangleHeight = String(text).boundingRect(with: size, options: options, attributes: attributes, context: nil).height
return ceil(rectangleHeight)
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-30 10:52:00
Musisz utworzyć rozszerzenie String i wywołać tę metodę
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
return ceil(boundingBox.height)
}
Musisz wysłać szerokość etykiety
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-15 08:22:26
Jeśli chcesz, aby etykieta miała dynamiczne linie, możesz użyć tego
label.numberOfLines = 0; // allows label to have as many lines as needed
label.text = @"some long text ";
[label sizeToFit];
NSLog(@"Label's frame is: %@", NSStringFromCGRect(label.frame));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-12 02:59:36