替换为不推荐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中,他们引入了NSAttributedString
的boundingRectWithSize:...
方法。 这是建立在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}];