天道酬勤,学无止境

NSString boundingRectWithSize 返回不必要的高度(NSString boundingRectWithSize returning unnecessarily tall height)

问题

当使用[NSString boundingRectWithSize:options:attributes] ,返回的矩形的大小比我对某些字符串的预期要高。 返回的高度似乎表示具有给定属性的字符串的最大可能高度,而不是字符串本身的高度。

假设相同的属性和选项,为字符串“ cars ”返回的高度与为字符串“ ÉTAS-UNIS ”返回的高度相同(注意 E 上的重音符号)。

我希望boundingRectWithSize只考虑给定字符串中的字符,在我看来,它会为字符串“ cars ”返回一个较短的高度。

在附加的屏幕截图中,我填充了从boundingRectWithSize返回的矩形,并用红色勾勒出我认为边界矩形应该是什么。 矩形的宽度与我预期的差不多,但高度比我预期的要高得多。 这是为什么?

边界矩形示例

示例代码:

NSRect boundingRect = NSZeroRect;
NSSize constraintSize = NSMakeSize(CGFLOAT_MAX, 0);

NSString *lowercaseString = @"cars";
NSString *uppercaseString = @"ÉTAS-UNIS";
NSString *capitalizedString = @"Japan";

NSFont *drawingFont = [NSFont fontWithName:@"Georgia" size:24.0];
NSDictionary *attributes = @{NSFontAttributeName : drawingFont, NSForegroundColorAttributeName : [NSColor blackColor]};

boundingRect = [lowercaseString boundingRectWithSize:constraintSize options:0 attributes:attributes];
NSLog(@"Lowercase rect: %@", NSStringFromRect(boundingRect));

boundingRect = [uppercaseString boundingRectWithSize:constraintSize options:0 attributes:attributes];
NSLog(@"Uppercase rect: %@", NSStringFromRect(boundingRect));

boundingRect = [capitalizedString boundingRectWithSize:constraintSize options:0 attributes:attributes];
NSLog(@"Capitalized rect: %@", NSStringFromRect(boundingRect));

输出:

Lowercase rect: {{0, -6}, {43.1953125, 33}}
Uppercase rect: {{0, -6}, {128.44921875, 33}}
Capitalized rect: {{0, -6}, {64.5, 33}}
回答1

您可能希望在选项中使用NSStringDrawingUsesDeviceMetrics 。 从文档:

NSStringDrawingUsesDeviceMetrics

在计算布局时使用图像字形边界(而不是印刷边界)。

回答2

@omz 仍然因为我完成这项工作而受到赞誉。 他的回答让我多看看 CoreText,因为我假设像boundingRectWithSize这样的东西最终会调用 CoreText 函数。

在 WWDC 2012 的 Session 226 中有一个完整的部分专门用于计算行的度量,令我惊讶的是,他们谈到了一个名为CTLineGetBoundsWithOptions的新 CoreText 函数。

据我所知,该方法仅记录在CTLine.hCoreText Changes文档中。 在文档中进行正常搜索时,它肯定不会出现(对我而言)。

但它似乎有效,在我的测试中,它返回与我系统上安装的所有字体的boundingRectWithSize完全相同的结果。 更好的是,它似乎比boundingRectWithSize快近 2 倍。

正如 WWDC 视频所提到的,为什么您需要在不考虑行高等因素的情况下计算字符串的边界有点模糊,但如果您确实需要这样做,那么我认为这可能是最好的方法用。 一如既往,YMMV。

粗略的示例代码:

NSFont *font = [NSFont systemFontOfSize:13.0];
NSDictionary *attributes = @{(__bridge NSString *)kCTFontAttributeName : font};
NSAttributedString *attributeString = [[NSAttributedString alloc] initWithString:self.text attributes:attributes];

CTLineRef line = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)attributeString);
CGRect bounds = CTLineGetBoundsWithOptions(line, kCTLineBoundsUseGlyphPathBounds);

CFRelease(line);

return NSRectFromCGRect(bounds);
回答3

我尝试了boundingRectWithSize函数,但它对我不起作用。

什么起作用了sizeThatFits

用法:

CGSize maxSize = CGSizeMake(myLabel.frame.size.width, CGFLOAT_MAX)

CGSize size = [myLabel sizeThatFits:maxSize];
回答4

基于 omz 答案的 Swift 3+ 解决方案:

let string: NSString = "test"
let maxSize = NSSize(width: CGFloat.greatestFiniteMagnitude, height: .greatestFiniteMagnitude)
let boundingRect = string.boundingRect(with: maxSize, options: .usesDeviceMetrics, attributes: <string attributes>)

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • NSAttributedString的bo​​undingRectWithSize返回错误的大小(boundingRectWithSize for NSAttributedString returning wrong size)
    问题 我正在尝试获取属性字符串的rect,但是boundingRectWithSize调用不尊重我传入的大小,而是返回具有单行高度而不是大高度的rect(这是一个长字符串)。 我通过传递一个非常大的高度值以及下面的代码中的0进行了实验,但是返回的rect始终相同。 CGRect paragraphRect = [attributedText boundingRectWithSize:CGSizeMake(300,0.0) options:NSStringDrawingUsesDeviceMetrics context:nil]; 这是坏了吗,还是我需要做其他事情才能让它返回一个用于包装文本的矩形? 回答1 好像您没有提供正确的选项。 对于包装标签,请至少提供: CGRect paragraphRect = [attributedText boundingRectWithSize:CGSizeMake(300.f, CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) context:nil]; 注意:如果原始文本宽度小于300.f,则不会出现换行符,因此请确保装订大小正确,否则仍然会得到错误的结果。 回答2 由于某些原因
  • 在iOS 7中替换已弃用的sizeWithFont:吗?(Replacement for deprecated sizeWithFont: in iOS 7?)
    问题 在iOS 7中,现已弃用sizeWithFont: 现在如何将UIFont对象传递到替换方法sizeWithAttributes: ? 回答1 使用sizeWithAttributes:代替,现在需要一个NSDictionary 。 用键UITextAttributeFont和您的字体对象传递对,如下所示: CGRect rawRect = {}; rawRect.size = [string sizeWithAttributes: @{ NSFontAttributeName: [UIFont systemFontOfSize:17.0f], }]; // Values are fractional -- you should take the ceil to get equivalent values CGSize adjustedSize = CGRectIntegral(rawRect).size; 回答2 我相信该函数已被弃用,因为该系列的NSString+UIKit函数( sizewithFont:...等)基于UIStringDrawing库,该库不是线程安全的。 如果您尝试不在主线程上运行它们(像其他UIKit功能一样),则会出现无法预料的行为。 特别是,如果您同时在多个线程上运行该函数,则可能会使您的应用程序崩溃。 这就是为什么在iOS 6中
  • 我应该用什么替换不推荐使用的sizeWithFont:方法?(With what should I replace the deprecated sizeWithFont: method?)
    问题 我有一个方法,可以给定UINameView的最佳大小(给定字符串长度(具有相应的正确字体大小)): - (NSInteger) heightOfLabel:(NSString*) string { CGSize maximumLabelSize = CGSizeMake([[UIScreen mainScreen] bounds].size.width - 40, FLT_MAX); CGSize expectedLabelSize = [[NSString stringTrimmedForLeadingAndTrailingWhiteSpacesFromString:string] sizeWithFont:[UIFont systemFontOfSize:15] constrainedToSize:maximumLabelSize lineBreakMode:NSLineBreakByWordWrapping]; return expectedLabelSize.height + 5; } 实际上,即使在iOS7中,它也仍然非常适合我。 尽管现在它提出了一个警告方法,说我不应该使用“ sizeWithFont:contrainedToSize:lineBreakMode”。 现在它说我应该使用-boundingRectWithSize:options:attributes
  • 不推荐使用'sizeWithFont:constrainedToSize:lineBreakMode:':('sizeWithFont:constrainedToSize:lineBreakMode:'is deprecated:)
    问题 在Xcode 5上将项目从iOS5.0转换为iOS7 / iOS6。以下代码给出了编译时警告: 不推荐使用'sizeWithFont:constrainedToSize:lineBreakMode:':在ios 7.0中第一次不推荐使用-使用-boundingRectWithSize:options:attribiutes:context - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == 0) { self.lblHidden.frame = CGRectMake(58, 228, 945, 9999); self.lblHidden.text = detailShareObj.pDesc; CGSize size = [detailShareObj.pDesc sizeWithFont:self.lblHidden.font constrainedToSize:self.lblHidden.frame.size lineBreakMode:NSLineBreakByWordWrapping]; return 228.0+size.height+20; } else if
  • 计算UILabel文本大小(Calculating UILabel Text Size)
    问题 我正在以编程方式绘制UILabels 。 他们从数据库获取大小。 所以我不能只使用sizeToFit 。 我已经实现了使用传递比例重绘UILabels的功能。 因此,我需要找到的只是从我的角度来看UILabel的文本,这将需要最大比率才能重绘UILabels 。 所以最后我需要做这样的事情: double ratio = 1.00; for (UILabel* labels in sec.subviews) { float widthLabel = labels.frame.size.width; float heightLabel = labels.frame.size.height; float heightText = //get the text height here float widthText = //get the text width here if (widthLabel < widthText) { ratio = MAX(widthText/widthLabel,ratio); } if (heightLabel < heightText) { ratio = MAX(heightText/heightLabel, ratio); } } //redraw UILabels with the given ratio here 那么
  • 如何动态计算UILabel高度(How do I calculate the UILabel height dynamically [duplicate])
    问题 这个问题已经在这里有了答案: 如何动态计算UILabel高度? (14个回答) 4年前关闭。 我有以下代码: label.numberOfLines = 0; // allows label to have as many lines as needed label.text = @"some long text"; [label sizeToFit]; 如何获得以磅为单位的标签高度? 回答1 使用以下方法来计算动态UILabel高度: - (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
  • 不推荐使用sizeWithFont方法。 boundingRectWithSize返回意外值(sizeWithFont method is deprecated. boundingRectWithSize returns an unexpected value)
    问题 在iOS7中,不推荐使用sizeWithFont ,因此我正在使用boundingRectWithSize (它返回一个CGRect值)。 我的代码: UIFont *fontText = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16]; // you can use your font. CGSize maximumLabelSize = CGSizeMake(310, 9999); CGRect textRect = [myString boundingRectWithSize:maximumLabelSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:fontText} context:nil]; expectedLabelSize = CGSizeMake(textRect.size.width, textRect.size.height); 在textRect ,我得到的尺寸大于我的maximumLabelSize ,这与使用sizeWithFont时的尺寸不同。 我该如何解决这个问题? 回答1 如何创建新标签并使用sizeThatFit:(CGSize)size ?
  • 根据文本调整UILabel的高度(Adjust UILabel height depending on the text)
    问题 考虑一下我在UILabel有以下文本(一长行动态文本): 由于外星军队的数量远远超过队伍,因此玩家必须利用世界末日的世界来发挥自己的优势,例如在垃圾箱,支柱,汽车,瓦砾和其他物体后面寻求掩护。 我想调整UILabel's高度,以便可以容纳文本。我正在使用UILabel以下属性来使文本自动换行。 myUILabel.lineBreakMode = UILineBreakModeWordWrap; myUILabel.numberOfLines = 0; 如果我没有朝正确的方向前进,请告诉我。 谢谢。 回答1 sizeWithFont constrainedToSize:lineBreakMode:是要使用的方法。 下面是一个如何使用它的示例: //Calculate the expected size based on the font and linebreak mode of your label // FLT_MAX here simply means no constraint in height CGSize maximumLabelSize = CGSizeMake(296, FLT_MAX); CGSize expectedLabelSize = [yourString sizeWithFont:yourLabel.font constrainedToSize
  • 根据内容动态更改UILabel的高度(Change the height of UILabel dynamically based on content)
    问题 我有一个UILabel作为UIButton子视图,我正在从另一个视图传递值,并在UILabel填充。 现在,我希望UILabel必须根据内容更改其高度。如果文本为“ Hello”,则必须在1行中,但是如果文本为“我的文本太长而无法放入标签”,则必须更改其大小。 我用过 [self.addressLabel sizeToFit]; 但是为此,我需要在UILabel下留出空白空间。 我想要的只是,当文本强度增加时,UILabel和UIView的大小必须扩大。 回答1 在下面使用可以获取标签的高度 文字-标签文字字体-标签中使用的字体宽度-标签的宽度-(float) getHeightForText:(NSString*) text withFont:(UIFont*) font andWidth:(float) width{ CGSize constraint = CGSizeMake(width , 20000.0f); CGSize title_size; float totalHeight; SEL selector = @selector(boundingRectWithSize:options:attributes:context:); if ([text respondsToSelector:selector]) { title_size = [text
  • 在iOS 7中根据单元格文本计算单元格高度(Calculate cell height based on cell's text in iOS 7)
    问题 有很多使用“ sizeWithFont”或类似方法的解决方案,这些解决方案自iOS 7起就已弃用。 到目前为止,这是我整理的一些代码。 高度会变化,但不会完全准确: - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; // Configure the cell... cell.textLabel.text = "The Cell's Text!"; cell.textLabel.numberOfLines = 0; [cell.textLabel setLineBreakMode:NSLineBreakByWordWrapping]; [cell.textLabel sizeToFit]; return cell; } - (CGFloat)tableView:(UITableView *)tableView
  • 如何找到UILabel的实际行数?(How to find actual number of lines of UILabel?)
    问题 用text和font初始化UILabel后,如何找到它的实际行数? 我将其numberOfLines属性设置为0 ,因此它将扩展为需要多行。 但是,然后,如何确定设置text后最终得到的行数呢? 我发现了类似的问题,但似乎没有一个简单的答案,而且在我看来,必须很容易就可以轻松获得它,而不必sizeWithFont任何开销来处理boundingRectWithSize或sizeWithFont ,... 回答1 首先在UILabel中设置文本 第一选择: 首先根据字体计算文字的高度: NSInteger lineCount = 0; CGSize labelSize = (CGSize){yourLabel.frame.size.width, MAXFLOAT}; CGRect requiredSize = [self boundingRectWithSize:labelSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: yourLabel.font} context:nil]; 现在计算行数: int charSize = lroundf(yourLabel.font.lineHeight); int rHeight = lroundf
  • 根据自定义单元格增加主tableview行的高度(Increase the main tableview row height according to the custom cell)
    问题 我有一个应用程序,其中有一个Tableview,并且在该TableView的每一行上,我正在动态创建自定义TableView单元格。 下面是该代码。 NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"flowviewTableViewCell" owner:self options:nil]; cell2 = [nib objectAtIndex:0]; return cell2; “ FlowTableViewCell”是一个UITableViewCell。 在这个自定义单元格中,我有一个tableview。 我正在从数组在自定义tableview单元上显示一些数据,并且这些数据的长度各不相同。 它不是固定的。 我能够根据自定义表格视图单元格的大小来增加自定义单元格的大小,但不能增加主表格视图行的高度。 我想根据自定义tableview单元格的大小动态增加主tableview的单元格大小的高度。 使用以下代码,自定义tableView单元的高度正在增加。 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *str = [arrComments
  • 根据文本动态获取UILabel的高度,iOS 7.0和iOS 6.1返回不同的值(Dynamically getting height of UILabel according to Text return different Value for iOS 7.0 and iOS 6.1)
    问题 我正在使用此方法来动态获取UILabel的高度: +(CGSize) GetSizeOfLabelForGivenText:(UILabel*)label Font:(UIFont*)fontForLabel Size: (CGSize)LabelSize{ label.numberOfLines = 0; CGSize labelSize = [label.text sizeWithFont:fontForLabel constrainedToSize:LabelSize lineBreakMode:NSLineBreakByCharWrapping]; return (labelSize); } 使用此解决方案,如果我的代码在iOS 8以下运行,我将获得UILabel的确切大小,但是如果我在iOS7上运行我的应用程序,则它将返回不同的值。 回答1 您必须动态设置框架,如下所示: 在iOS 6到iOS 12.2上测试 迅速: let constrainedSize = CGSize(width: self.titleLable.frame.size.width, height:9999) let attributesDictionary = [NSAttributedString.Key.font: UIFont.init(name: "HelveticaNeue"
  • iOS 7 sizeWithAttributes:替换sizeWithFont:constrainedToSize(iOS 7 sizeWithAttributes: replacement for sizeWithFont:constrainedToSize)
    问题 如何从新的iOS 7方法sizeWithAttributes返回多行文本CGSize? 我希望这产生与sizeWithFont:constrainedToSize相同的结果。 NSString *text = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus eu urna quis lacus imperdiet scelerisque a nec neque. Mauris eget feugiat augue, vitae porttitor mi. Curabitur vitae sollicitudin augue. Donec id sapien eros. Proin consequat tellus in vehicula sagittis. Morbi sed felis a nibh hendrerit hendrerit. Lorem ipsum dolor sit." CGSize textSize = [text sizeWithAttributes:@{ NSFontAttributeName : [UIFont fontWithName:@"HelveticaNeue-Light" size:16.0] }]; 此方法仅产生一行文本的高度。 回答1 好吧
  • 根据UILabel动态调整uitableViewCell的大小(带段落间距)(Dynamically size uitableViewCell according to UILabel (With paragraph spacing))
    问题 我有一个UITableView,它由JSON文件中的文本和图像填充。 TableView单元格当前正正确地针对文本中不包含许多换行符的“帖子”调整大小,但是我无法获取它来计算具有4或5个换行符的“帖子”的正确高度。 获取身高的代码: -(float)height :(NSMutableAttributedString*)string { NSString *stringToSize = [NSString stringWithFormat:@"%@", string]; CGSize constraint = CGSizeMake(LABEL_WIDTH - (LABEL_MARGIN *2), 2000.f); CGSize size = [stringToSize sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:contraint lineBreakMode:NSLineBreakByWordWrapping]; return size.height; } 如何在允许换行和留白的同时计算正确的尺寸? 编辑 剩下的方法, 在TableView CellForRow内部: -(UITableViewCell*)tableView:(UITableView *)tableView
  • 在iOS 7中替换已弃用的-sizeWithFont:constrainedToSize:lineBreakMode :?(Replacement for deprecated -sizeWithFont:constrainedToSize:lineBreakMode: in iOS 7?)
    问题 在iOS 7中,方法: - (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode 和方法: - (CGSize)sizeWithFont:(UIFont *)font 不推荐使用。 我该如何更换 CGSize size = [string sizeWithFont:font constrainedToSize:constrainSize lineBreakMode:NSLineBreakByWordWrapping]; 和: CGSize size = [string sizeWithFont:font]; 回答1 您可以尝试以下方法: CGRect textRect = [text boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:FONT} context:nil]; CGSize size = textRect.size; 只需将“ FONT”更改为“ [UIFont字体....]” 回答2 由于我们无法为所有大于4
  • 在iOS 7中动态调整标签大小(Dynamically resize label in iOS 7)
    问题 在iOS 6中,我正在使用: CGSize labelSize = [self.text sizeWithFont:self.font constrainedToSize:size lineBreakMode:self.lineBreakMode]; self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y , labelSize.width, self.frame.size.height); 动态调整UILabel的大小。 这在iOS 7中不起作用,所以我尝试了: NSString *text = self.text; CGFloat width = size.width; UIFont *font = self.font; NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{ NSFontAttributeName: font }]; CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX} options
  • 如何检查UILabel是否被截断?(How to check if UILabel is truncated?)
    问题 我有一个UILabel ,其长度可以变化,这取决于我的应用程序是否在iPhone或iPad上以纵向或横向模式运行。 当文本太长而无法在一行上显示并且被截断时,我希望用户能够按它并弹出全文本。 如何检查UILabel是否将文本截断? 可能吗? 现在,我只是根据自己所处的模式来检查不同的长度,但是它不能很好地工作。 回答1 您可以计算字符串的宽度,然后查看宽度是否大于label.bounds.size.width NSString UIKit Additions具有几种用于计算具有特定字体的字符串大小的方法。 但是,如果标签具有minimumFontSize,则允许系统将文本缩小到该大小。 在这种情况下,您可能要使用sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:。 CGSize size = [label.text sizeWithAttributes:@{NSFontAttributeName:label.font}]; if (size.width > label.bounds.size.width) { ... } 回答2 Swift(作为扩展名)-适用于多行uilabel: swift4:( boundingRect attributes参数略有变化) extension UILabel {
  • 使用 iOS 7 SDK 构建时 UITextView 包装文本(UITextView wraps text when built with iOS 7 SDK)
    问题 我在UIScrollView中有一个UITextView ,它在从xcode 4.x构建的iOS 6上运行得非常好,但是现在使用xcode 5构建它不能正常工作,即使在iOS 6 。 问题是即使UITextView和UIScrollView宽度很大,文本也会用屏幕宽度换行。 我使用此代码来计算UITextView的新宽度和高度,即使 textview 向左/向右滚动,文本也会被换行,就好像宽度只是屏幕的宽度一样。 谢谢 self.responceTextView.text = [NSString stringWithFormat:@"%@%@",_responceTextView.text,responce]; [self textViewDidChange:self.responceTextView]; - (void)textViewDidChange:(UITextView *)textView { // Recalculate size of text field CGSize maxSize = CGSizeMake(MAXFLOAT, MAXFLOAT); CGSize reqSize = [textView.text sizeWithFont:[UIFont fontWithName:@"Courier" size:12] constrainedToSize
  • NSString sizeWithFont:iOS7 中的替代方案(NSString sizeWithFont: alternative in iOS7)
    问题 方法(sizeWithFont: forWidth: lineBreakMode:)在 iOS 7.0 中已弃用。 但是我怎么能做同样的事情,就像在 iOS 7.0 中下面的代码一样? CGSize fontSize =[self.text sizeWithFont:self.font forWidth:self.frame.size.width lineBreakMode:NSLineBreakByTruncatingTail]; 可以(boundingRectWithSize:options:attributes:context:)这样做吗? 我不确定,但这是我在苹果文档上搜索的方法。 感谢你的协助。 回答1 我有一个 NSString 类别来获取字符串的宽度或高度: - (CGFloat)widthWithFont:(UIFont *)font { NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil]; return [[[NSAttributedString alloc] initWithString:self attributes:attributes] size].width; } - (CGFloat