Run*_*oop 149 objective-c nsattributedstring
我试图获取一个属性字符串的rect,但是boundingRectWithSize调用不符合我传入的大小并且返回一个具有单行高度而不是大高度的矩形(它是一个长字符串).我已经通过传递一个非常大的高度值和0以及下面的代码进行了实验,但是返回的rect总是相同的.
CGRect paragraphRect = [attributedText boundingRectWithSize:CGSizeMake(300,0.0)
options:NSStringDrawingUsesDeviceMetrics
context:nil];
Run Code Online (Sandbox Code Playgroud)
这是否已损坏,或者我是否需要做其他事情以使其返回包裹文本的矩形?
Ed *_*nus 305
看起来你没有提供正确的选项.对于包装标签,至少提供:
CGRect paragraphRect =
[attributedText boundingRectWithSize:CGSizeMake(300.f, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
context:nil];
Run Code Online (Sandbox Code Playgroud)
注意:如果原始文本宽度低于300.f,则不会换行,因此请确保绑定大小正确,否则您仍会得到错误的结果.
war*_*enm 118
这种方法在很多方面看起来都很麻烦.首先,正如您所注意到的,它不考虑宽度约束.另一方面,我看到它崩溃了,因为它似乎假设所有属性都是NSObject
类型的(例如,它试图传递_isDefaultFace
给a CTFontRef
).当提供字符串绘制上下文时,它有时也会崩溃,因为它试图在场景后面的可变属性字符串中添加一个零值属性.
我鼓励你完全避免这种方法.如果可以处理为需要绘制的每个字符串创建框架集的开销,则可以直接使用Core Text来估计字符串大小.它也没有精确地遵守宽度约束,但根据我的经验,它似乎在几个像素内.
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attrString);
CGSize targetSize = CGSizeMake(320, CGFLOAT_MAX);
CGSize fitSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, [attrString length]), NULL, targetSize, NULL);
CFRelease(framesetter);
Run Code Online (Sandbox Code Playgroud)
sho*_*oan 45
由于某种原因,boundingRectWithSize总是返回错误的大小.我想出了一个解决方案.UItextView -sizeThatFits有一种方法,它返回文本集的正确大小.因此,不使用boundingRectWithSize,而是使用随机帧创建UITextView,并使用相应的宽度和CGFLOAT_MAX高度调用其sizeThatFits.它返回具有适当高度的大小.
UITextView *view=[[UITextView alloc] initWithFrame:CGRectMake(0, 0, width, 10)];
view.text=text;
CGSize size=[view sizeThatFits:CGSizeMake(width, CGFLOAT_MAX)];
height=size.height;
Run Code Online (Sandbox Code Playgroud)
如果你在while循环中计算大小,不要忘记在自动释放池中添加它,因为将创建n个UITextView,如果我们不使用autoreleasepool,应用程序的运行时内存将增加.
Pau*_*ler 31
埃德麦克马纳斯当然提供了使这项工作成功的关键.我找到了一个不起作用的案例
UIFont *font = ...
UIColor *color = ...
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
font, NSFontAttributeName,
color, NSForegroundColorAttributeName,
nil];
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString: someString attributes:attributesDictionary];
[string appendAttributedString: [[NSAttributedString alloc] initWithString: anotherString];
CGRect rect = [string boundingRectWithSize:constraint options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) context:nil];
Run Code Online (Sandbox Code Playgroud)
rect将没有正确的高度.请注意,anotherString(附加到字符串)是在没有属性字典的情况下初始化的.这是anotherString的合法初始值设定项,但boundingRectWithSize:在这种情况下不提供准确的大小.
小智 27
经过长时间的调查后我的最终决定:
- boundingRectWithSize
函数只返回正确的大小,只有不间断的字符序列!如果字符串包含空格或其他东西(由Apple称为"一些字形") - 则无法获得显示文本所需的实际大小!
我用字母替换了字符串中的空格,并立即得到了正确的结果.
Apple在这里说:https: //developer.apple.com/documentation/foundation/nsstring/1524729-boundingrectwithsize
"此方法返回字符串中字形的实际边界.某些字形(例如,空格)允许与传入的大小指定的布局约束重叠,因此在某些情况下,大小组件的宽度值返回的内容CGRect
可以超过size参数的宽度值."
所以有必要找到另一种计算实际矩形的方法......
经过长时间的调查,终于找到解决方 我不确定它是否适用于所有相关的案例UITextView
,但主要和重要的事情被检测到!
boundingRectWithSize
CTFramesetterSuggestFrameSizeWithConstraints
当使用正确的矩形时,函数以及(以及许多其他方法)将计算大小和文本部分的正确性.例如 - UITextView
has textView.bounds.size.width
- 并且此值不是系统在文本绘制时使用的实际矩形UITextView
.
我发现非常有趣的参数并在代码中执行简单的计算:
CGFloat padding = textView.textContainer.lineFragmentPadding;
CGFloat actualPageWidth = textView.bounds.size.width - padding * 2;
Run Code Online (Sandbox Code Playgroud)
神奇的作品 - 我的所有文本现在计算正确!请享用!
Dav*_*ees 11
斯威夫特四个版本
let string = "A great test string."
let font = UIFont.systemFont(ofSize: 14)
let attributes: [NSAttributedStringKey: Any] = [.font: font]
let attributedString = NSAttributedString(string: string, attributes: attributes)
let largestSize = CGSize(width: bounds.width, height: .greatestFiniteMagnitude)
//Option one (best option)
let framesetter = CTFramesetterCreateWithAttributedString(attributedString)
let textSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRange(), nil, largestSize, nil)
//Option two
let textSize = (string as NSString).boundingRect(with: largestSize, options: [.usesLineFragmentOrigin , .usesFontLeading], attributes: attributes, context: nil).size
//Option three
let textSize = attributedString.boundingRect(with: largestSize, options: [.usesLineFragmentOrigin , .usesFontLeading], context: nil).size
Run Code Online (Sandbox Code Playgroud)
使用CTFramesetter测量文本效果最好,因为它提供了整数大小并且可以很好地处理表情符号和其他unicode字符.
如果你想通过截断尾部来获得边界框,这个问题可以帮助你.
CGFloat maxTitleWidth = 200;
NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
paragraph.lineBreakMode = NSLineBreakByTruncatingTail;
NSDictionary *attributes = @{NSFontAttributeName : self.textLabel.font,
NSParagraphStyleAttributeName: paragraph};
CGRect box = [self.textLabel.text
boundingRectWithSize:CGSizeMake(maxTitleWidth, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:attributes context:nil];
Run Code Online (Sandbox Code Playgroud)
我对这些建议都没有好运.我的字符串包含unicode项目符号,我怀疑它们在计算中引起了悲痛.我注意到UITextView正在处理绘图,所以我希望利用它的计算.我做了以下操作,这可能不如NSString绘图方法那么理想,但至少它是准确的.它也比初始化UITextView只是为了调用稍微优化一些-sizeThatFits:
.
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(width, CGFLOAT_MAX)];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[layoutManager addTextContainer:textContainer];
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:formattedString];
[textStorage addLayoutManager:layoutManager];
const CGFloat formattedStringHeight = ceilf([layoutManager usedRectForTextContainer:textContainer].size.height);
Run Code Online (Sandbox Code Playgroud)
@warrenm很抱歉说框架方法对我不起作用.
我得到了这个.这个函数可以帮助我们确定给定宽度的iphone/Ipad SDK中NSAttributedString的字符串范围所需的帧大小:
它可以用于UITableView Cells的动态高度
- (CGSize)frameSizeForAttributedString:(NSAttributedString *)attributedString
{
CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedString((CFAttributedStringRef)attributedString);
CGFloat width = YOUR_FIXED_WIDTH;
CFIndex offset = 0, length;
CGFloat y = 0;
do {
length = CTTypesetterSuggestLineBreak(typesetter, offset, width);
CTLineRef line = CTTypesetterCreateLine(typesetter, CFRangeMake(offset, length));
CGFloat ascent, descent, leading;
CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
CFRelease(line);
offset += length;
y += ascent + descent + leading;
} while (offset < [attributedString length]);
CFRelease(typesetter);
return CGSizeMake(width, ceil(y));
}
Run Code Online (Sandbox Code Playgroud)
感谢HADDAD ISSA >>> http://haddadissa.blogspot.in/2010/09/compute-needed-heigh-for-fixed-width-of.html
小智 7
我发现首选解决方案不能处理换行符.
我发现这种方法适用于所有情况:
UILabel* dummyLabel = [UILabel new];
[dummyLabel setFrame:CGRectMake(0, 0, desiredWidth, CGFLOAT_MAX)];
dummyLabel.numberOfLines = 0;
[dummyLabel setLineBreakMode:NSLineBreakByWordWrapping];
dummyLabel.attributedText = myString;
[dummyLabel sizeToFit];
CGSize requiredSize = dummyLabel.frame.size;
Run Code Online (Sandbox Code Playgroud)
事实证明,如果你希望boundingRectWithSize真正起作用,那么NSAttributedString的每个部分都必须设置一个至少设置了NSFontAttributeName和NSForegroundColorAttributeName的字典!
我没有看到任何记录.
经过更多的尝试和错误并从其他答案获得反馈,特别是那些指出使用NSString.DrawingOptions.usesDeviceMetrics 的答案,我发现这个选项绝对是一个游戏规则改变者,尽管它本身还不够。
使用.deviceMetrics
返回正确的height
,但在某些情况下它不能正确地适合 aUILabel
或 a NSTextField
。
我能够使其适合所有情况的唯一方法是使用CATextLayer。适用于 iOS 和 macOS。
let attributedString = NSAttributedString(string: "my string")
let maxWidth = CGFloat(300)
let size = attributedString.boundingRect(
with: .init(width: maxWidth,
height: .greatestFiniteMagnitude),
options: [
.usesFontLeading,
.usesLineFragmentOrigin,
.usesDeviceMetrics])
let textLayer = CATextLayer()
textLayer.frame = .init(origin: .zero, size: size)
textLayer.contentsScale = 2 // for retina
textLayer.isWrapped = true // for multiple lines
textLayer.string = attributedString
Run Code Online (Sandbox Code Playgroud)
然后您可以将 添加CATextLayer
到任何NSView
/ UIView
。
let view = NSView()
view.wantsLayer = true
view.layer?.addSublayer(textLayer)
Run Code Online (Sandbox Code Playgroud)
let view = UIView()
view.layer.addSublayer(textLayer)
Run Code Online (Sandbox Code Playgroud)
这里的许多答案都很棒,大卫·里斯很好地总结了这些选项。
但有时,当存在特殊字符或多个空格时,大小似乎总是错误的。
无效字符串的示例(对我来说):
"hello . . world"
Run Code Online (Sandbox Code Playgroud)
我发现设置紧距有助于返回正确的大小NSAttributedString
。1
像这样:
NSAttributedString(
string: "some string",
attributes: [
.font: NSFont.preferredFont(forTextStyle: .body),
.kern: 1])
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
120518 次 |
最近记录: |