替换为不推荐sizeWithFont:在iOS 7中?

在iOS 7中, sizeWithFont:现在已被弃用。 现在如何将UIFont对象传递给替换方法sizeWithAttributes: :?

使用sizeWithAttributes:相反,现在需要一个NSDictionary 。 用键UITextAttributeFont和你的字体对象UITextAttributeFont ,如下所示:

 CGSize size = [string sizeWithAttributes: @{NSFontAttributeName: [UIFont systemFontOfSize:17.0f]}]; // Values are fractional -- you should take the ceilf to get equivalent values CGSize adjustedSize = CGSizeMake(ceilf(size.width), ceilf(size.height)); 

我相信这个函数已经被弃用了,因为这一系列NSString+UIKit函数( sizewithFont:...等等)是基于UIStringDrawing库的,它不是线程安全的。 如果您尝试在主线程上运行它们(与任何其他UIKit功能一样),则会出现不可预知的行为。 特别是,如果您同时在多个线程上运行该功能,则可能会导致应用程序崩溃。 这就是为什么在iOS 6中,他们引入了NSAttributedStringboundingRectWithSize:...方法。 这是建立在NSStringDrawing库的顶部,是线程安全的。

如果您查看新的NSString boundingRectWithSize:...函数,它会以与NSAttributeString相同的方式请求一个attributes数组。 如果我不得不猜测,iOS 7中的这个新的NSString函数仅仅是iOS 6的NSAttributeString函数的一个包装。

在那个笔记上,如果你只支持iOS 6和iOS 7,那么我肯定会把你所有的NSString sizeWithFont:...更改为NSAttributeString boundingRectWithSize 。 如果你碰巧有一个奇怪的多线程案例,它会为你节省很多头痛! 以下是我如何转换NSString sizeWithFont:constrainedToSize: ::

曾经是:

 NSString *text = ...; CGFloat width = ...; UIFont *font = ...; CGSize size = [text sizeWithFont:font constrainedToSize:(CGSize){width, CGFLOAT_MAX}]; 

可以替换为:

 NSString *text = ...; CGFloat width = ...; UIFont *font = ...; NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName: font}]; CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX} options:NSStringDrawingUsesLineFragmentOrigin context:nil]; CGSize size = rect.size; 

请注意文档中提到:

在iOS 7及更高版本中,此方法返回小数大小(在返回的CGRect的大小组件中); 要使用返回的大小来调整视图大小,您必须使用ceil函数将其值提高到最接近的较大整数。

所以要拉出计算的高度或宽度来用于大小视图,我会使用:

 CGFloat height = ceilf(size.height); CGFloat width = ceilf(size.width); 

正如你可以在苹果开发者网站上看到的sizeWithFont它已经被弃用,所以我们需要使用sizeWithAttributes

 #define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) NSString *text = @"Hello iOS 7.0"; if (SYSTEM_VERSION_LESS_THAN(@"7.0")) { // code here for iOS 5.0,6.0 and so on CGSize fontSize = [text sizeWithFont:[UIFont fontWithName:@"Helvetica" size:12]]; } else { // code here for iOS 7.0 CGSize fontSize = [text sizeWithAttributes: @{NSFontAttributeName: [UIFont fontWithName:@"Helvetica" size:12]}]; } 

我创建了一个类来处理这个问题,这里是:

 #import "NSString+StringSizeWithFont.h" @implementation NSString (StringSizeWithFont) - (CGSize) sizeWithMyFont:(UIFont *)fontToUse { if ([self respondsToSelector:@selector(sizeWithAttributes:)]) { NSDictionary* attribs = @{NSFontAttributeName:fontToUse}; return ([self sizeWithAttributes:attribs]); } return ([self sizeWithFont:fontToUse]); } 

这样,你只需要找到/替换sizeWithFont: sizeWithMyFont:然后你就可以走了。

在iOS7中,我需要逻辑来为tableview:heightForRowAtIndexPath方法返回正确的高度,但sizeWithAttributes始终返回相同的高度,而不管字符串的长度如何,因为它不知道它将被放在固定宽度的表格单元格中。 我发现这对我很好,并考虑到表格单元格的宽度来计算正确的高度! 这是基于T先生的回答。

 NSString *text = @"The text that I want to wrap in a table cell." CGFloat width = tableView.frame.size.width - 15 - 30 - 15; //tableView width - left border width - accessory indicator - right border width UIFont *font = [UIFont systemFontOfSize:17]; NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName: font}]; CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX} options:NSStringDrawingUsesLineFragmentOrigin context:nil]; CGSize size = rect.size; size.height = ceilf(size.height); size.width = ceilf(size.width); return size.height + 15; //Add a little more padding for big thumbs and the detailText label 

使用动态高度的多行标签可能需要额外的信息才能正确设置尺寸。 您可以使用sizeWithAttributes与UIFont和NSParagraphStyle来指定字体和换行符模式。

你可以定义段落样式,并像这样使用NSDictionary:

 // set paragraph style NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; [style setLineBreakMode:NSLineBreakByWordWrapping]; // make dictionary of attributes with paragraph style NSDictionary *sizeAttributes = @{NSFontAttributeName:myLabel.font, NSParagraphStyleAttributeName: style}; // get the CGSize CGSize adjustedSize = CGSizeMake(label.frame.size.width, CGFLOAT_MAX); // alternatively you can also get a CGRect to determine height CGRect rect = [myLabel.text boundingRectWithSize:adjustedSize options:NSStringDrawingUsesLineFragmentOrigin attributes:sizeAttributes context:nil]; 

如果您正在查找高度,则可以使用CGSize'adjustedSize'或CGRect作为rect.size.height属性。

有关NSParagraphStyle的更多信息,请访问: https : //developer.apple.com/library/mac/documentation/cocoa/reference/applicationkit/classes/NSParagraphStyle_Class/Reference/Reference.html

创建一个采用UILabel实例的函数。 并返回CGSize

 CGSize constraint = CGSizeMake(label.frame.size.width , 2000.0); // Adjust according to requirement CGSize size; if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0){ NSRange range = NSMakeRange(0, [label.attributedText length]); NSDictionary *attributes = [label.attributedText attributesAtIndex:0 effectiveRange:&range]; CGSize boundingBox = [label.text boundingRectWithSize:constraint options: NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size; size = CGSizeMake(ceil(boundingBox.width), ceil(boundingBox.height)); } else{ size = [label.text sizeWithFont:label.font constrainedToSize:constraint lineBreakMode:label.lineBreakMode]; } return size; 

备用解决方案 –

 CGSize expectedLabelSize; if ([subTitle respondsToSelector:@selector(sizeWithAttributes:)]) { expectedLabelSize = [subTitle sizeWithAttributes:@{NSFontAttributeName:subTitleLabel.font}]; }else{ expectedLabelSize = [subTitle sizeWithFont:subTitleLabel.font constrainedToSize:subTitleLabel.frame.size lineBreakMode:NSLineBreakByWordWrapping]; } 

建立在@bitsand上,这是我刚添加到我的NSString + Extras类别中的新方法:

 - (CGRect) boundingRectWithFont:(UIFont *) font constrainedToSize:(CGSize) constraintSize lineBreakMode:(NSLineBreakMode) lineBreakMode; { // set paragraph style NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; [style setLineBreakMode:lineBreakMode]; // make dictionary of attributes with paragraph style NSDictionary *sizeAttributes = @{NSFontAttributeName:font, NSParagraphStyleAttributeName: style}; CGRect frame = [self boundingRectWithSize:constraintSize options:NSStringDrawingUsesLineFragmentOrigin attributes:sizeAttributes context:nil]; /* // OLD CGSize stringSize = [self sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:lineBreakMode]; // OLD */ return frame; } 

我只是使用生成的框架的大小。

 // max size constraint CGSize maximumLabelSize = CGSizeMake(184, FLT_MAX) // font UIFont *font = [UIFont fontWithName:TRADE_GOTHIC_REGULAR size:20.0f]; // set paragraph style NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping; // dictionary of attributes NSDictionary *attributes = @{NSFontAttributeName:font, NSParagraphStyleAttributeName: paragraphStyle.copy}; CGRect textRect = [string boundingRectWithSize: maximumLabelSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil]; CGSize expectedLabelSize = CGSizeMake(ceil(textRect.size.width), ceil(textRect.size.height)); 

你仍然可以使用sizeWithFont 。 但是,如果字符串包含前后空格或结束行,在iOS> = 7.0方法中会导致崩溃\n

在使用前修剪文本

 label.text = [label.text stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]]; 

这也可能适用于sizeWithAttributes[label sizeToFit]

此外,每当你有nsstringdrawingtextstorage message sent to deallocated instance在iOS 7.0设备它处理这个。

更好地使用自动尺寸(Swift):

  tableView.estimatedRowHeight = 68.0 tableView.rowHeight = UITableViewAutomaticDimension 

注意:1. UITableViewCell原型应该被正确设计(例如不要忘记设置UILabel.numberOfLines = 0等)2.删除HeightForRowAtIndexPath方法

在这里输入图像描述

视频: https : //youtu.be/Sz3XfCsSb6k

 boundingRectWithSize:options:attributes:context: 

在Xamarin 接受的答案是(使用sizeWithAttributes和UITextAttributeFont):

  UIStringAttributes attributes = new UIStringAttributes { Font = UIFont.SystemFontOfSize(17) }; var size = text.GetSizeUsingAttributes(attributes); 
 - (CGSize) sizeWithMyFont:(UIFont *)fontToUse { if ([self respondsToSelector:@selector(sizeWithAttributes:)]) { NSDictionary* attribs = @{NSFontAttributeName:fontToUse}; return ([self sizeWithAttributes:attribs]); } return ([self sizeWithFont:fontToUse]); } 

这在ios 7中对我来说没有任何作用。这就是我最终做的事情。 我把它放在我的自定义单元类中,并在我的heightForCellAtIndexPath方法中调用方法。

在应用商店中查看应用时,我的单元格与描述单元格类似。

首先在故事板中,将您的标签设置为“attributesText”,将行数设置为0(这将自动调整标签大小(仅限ios 6+))并将其设置为自动换行。

然后,我只是将我的自定义单元类中的单元格内容的所有高度加起来。 在我的情况下,我有一个标签在顶部总是说“描述”(_descriptionHeadingLabel),一个较小的标签是可变的大小,包含实际的描述(_descriptionLabel)从单元格顶部的约束(_descriptionHeadingLabelTopConstraint) 。 我也加了3,把底部空出一点(关于字幕类型单元格上的相同数量的苹果位置)。

 - (CGFloat)calculateHeight { CGFloat width = _descriptionLabel.frame.size.width; NSAttributedString *attributedText = _descriptionLabel.attributedText; CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX} options: NSStringDrawingUsesLineFragmentOrigin context:nil]; return rect.size.height + _descriptionHeadingLabel.frame.size.height + _descriptionHeadingLabelTopConstraint.constant + 3; } 

并在我的表视图委托:

 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; { if (indexPath.row == 0) { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"descriptionCell"]; DescriptionCell *descriptionCell = (DescriptionCell *)cell; NSString *text = [_event objectForKey:@"description"]; descriptionCell.descriptionLabel.text = text; return [descriptionCell calculateHeight]; } return 44.0f; } 

您可以将if语句更改为“更智能”,并从某种数据源实际获取单元格标识符。 在我的情况下,细胞将被硬编码,因为它们将以特定顺序固定数量。

如果有人需要,这是等价的等价物:

 /// <summary> /// Measures the height of the string for the given width. /// </summary> /// <param name="text">The text.</param> /// <param name="font">The font.</param> /// <param name="width">The width.</param> /// <param name="padding">The padding.</param> /// <returns></returns> public static float MeasureStringHeightForWidth(this string text, UIFont font, float width, float padding = 20) { NSAttributedString attributedString = new NSAttributedString(text, new UIStringAttributes() { Font = font }); RectangleF rect = attributedString.GetBoundingRect(new SizeF(width, float.MaxValue), NSStringDrawingOptions.UsesLineFragmentOrigin, null); return rect.Height + padding; } 

可以这样使用:

 public override float GetHeightForRow(UITableView tableView, NSIndexPath indexPath) { //Elements is a string array return Elements[indexPath.Row].MeasureStringHeightForWidth(UIFont.SystemFontOfSize(UIFont.LabelFontSize), tableView.Frame.Size.Width - 15 - 30 - 15); } 
 CGSize maximumLabelSize = CGSizeMake(label.frame.size.width, FLT_MAX); CGSize expectedLabelSize = [label sizeThatFits:maximumLabelSize]; float heightUse = expectedLabelSize.height; 

试试这个语法:

 NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName: font}];