boundingRectWithSize为NSAttributedString返回错误的大小

时间:2012-11-29 07:48:50

标签: objective-c nsattributedstring

我试图获取一个属性字符串的rect,但是boundingRectWithSize调用不符合我传入的大小并返回一个带有单行高度而不是大高度的矩形(它是一个长字符串) 。我已经通过传递一个非常大的高度值和0以及下面的代码进行了实验,但返回的矩总是相同的。

CGRect paragraphRect = [attributedText boundingRectWithSize:CGSizeMake(300,0.0)
  options:NSStringDrawingUsesDeviceMetrics
  context:nil];

这是否已损坏,或者我是否需要做其他事情以使其返回包裹文本的矩形?

24 个答案:

答案 0 :(得分:301)

看起来您没有提供正确的选项。对于包装标签,请至少提供:

CGRect paragraphRect =
  [attributedText boundingRectWithSize:CGSizeMake(300.f, CGFLOAT_MAX)
  options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
  context:nil];

注意:如果原始文本宽度低于300.f,则不会换行,因此请确保绑定大小正确,否则您仍会得到错误的结果。

答案 1 :(得分:117)

这种方法在很多方面看起来都很麻烦。首先,正如您所注意到的,它不考虑宽度约束。另一方面,我看到它崩溃了,因为它似乎假设所有属性都是NSObject类型(例如,它试图将_isDefaultFace传递给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);

答案 2 :(得分:44)

由于某种原因,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; 

如果您正在计算while循环中的大小,请不要忘记在自动释放池中添加它,因为将创建n个UITextView,如果我们不使用autoreleasepool,应用程序的运行时内存将会增加

答案 3 :(得分: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];

rect 的高度不正确。请注意, anotherString (附加到 string )是在没有属性字典的情况下初始化的。这是 anotherString 的合法初始化程序,但 boundingRectWithSize:在这种情况下不能给出准确的大小。

答案 4 :(得分:26)

经过长时间的调查,我的最终决定:
 - boundingRectWithSize函数仅为不间断的字符序列返回正确的大小! 如果字符串包含空格或其他内容(由Apple称为“某些字形”) - 则无法获得显示文本所需的实际大小尺寸!
我用字母替换了字符串中的空格,并立即得到了正确的结果。

Apple在这里说: https://developer.apple.com/documentation/foundation/nsstring/1524729-boundingrectwithsize

“此方法返回字符串中字形的实际边界。允许某些字形(例如空格)与传入的大小指定的布局约束重叠,因此在某些情况下,宽度值为返回的CGRect的大小组件可能超过size参数的宽度值。“

所以有必要找到另一种计算实际矩形的方法......


经过长时间的调查,解决方案终于找到!!! 我不确定它是否适用于与UITextView相关的所有案例,但是检测到主要和重要的事情!

当使用正确的矩形时,

boundingRectWithSize函数以及CTFramesetterSuggestFrameSizeWithConstraints(以及许多其他方法)将计算大小和文本部分的正确性。 例如 - UITextViewtextView.bounds.size.width - 此值不是系统在UITextView上进行文字绘制时使用的实际矩形。

我发现了非常有趣的参数并在代码中进行了简单的计算:

CGFloat padding = textView.textContainer.lineFragmentPadding;  
CGFloat  actualPageWidth = textView.bounds.size.width - padding * 2;

神奇的作品 - 我的所有文本现在都正确计算了! 享受!

答案 5 :(得分:9)

Swift四个版本

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

使用CTFramesetter测量文本效果最佳,因为它提供整数大小并且可以很好地处理表情符号和其他unicode字符。

答案 6 :(得分:9)

我对这些建议都没有好运。我的字符串包含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);

答案 7 :(得分:9)

如果您想通过截断尾部来获取边框,this question可以帮助您。

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];

答案 8 :(得分:7)

@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));
}

感谢HADDAD ISSA&gt;&gt;&gt; http://haddadissa.blogspot.in/2010/09/compute-needed-heigh-for-fixed-width-of.html

答案 9 :(得分: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;

答案 10 :(得分:6)

事实证明,如果你希望boundingRectWithSize真正起作用,那么NSAttributedString的每个部分都必须设置一个至少设置了NSFontAttributeName和NSForegroundColorAttributeName的字典!

我不会在任何地方看到记录。

答案 11 :(得分:4)

我遇到了同样的问题,没有使用这些技术获得准确的大小,我已经改变了我的方法,使其工作。

我有一个很长的属性字符串,我一直试图将其放入滚动视图中,以便正确显示而不会被截断。我为使文本可靠地工作所做的是不将高度设置为约束,而是允许内在大小接管。现在文本正确显示而不会被截断,我不必计算高度。

我想如果我确实需要可靠地获得高度,我会创建一个隐藏的视图和这些约束,并在应用约束后获得帧的高度。

答案 12 :(得分:3)

我在游戏中有点晚了 - 但是我一直试图想出一种方法,可以找到适合于某个属性字符串的边界框来制作像Finder中编辑文件一样的焦点环。当字符串末尾有空格或字符串内有多个空格时,我尝试过的所有内容都失败了。 boundingRectWithSize对此以及CTFramesetterCreateWithAttributedString失败了。

使用NSLayoutManager以下代码似乎可以解决我到目前为止找到的所有情况并返回完全绑定字符串的矩形。额外奖励:如果您选择文本,选择的边缘将直到返回的rect的边界。下面的代码使用NSTextView中的layoutManager。

NSLayoutManager* layout = [self layoutManager];
NSTextContainer* container = [self textContainer];

CGRect focusRingFrame = [layout boundingRectForGlyphRange:NSMakeRange(0, [[self textStorage] length]) inTextContainer:container];

答案 13 :(得分:2)

textView.textContainerInset = UIEdgeInsetsZero;
NSString *string = @"Some string";
NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:12.0f], NSForegroundColorAttributeName:[UIColor blackColor]};
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:string attributes:attributes];
[textView setAttributedText:attributedString];
CGRect textViewFrame = [textView.attributedText boundingRectWithSize:CGSizeMake(CGRectGetWidth(self.view.frame)-8.0f, 9999.0f) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) context:nil];
NSLog(@"%f", ceilf(textViewFrame.size.height));

完美适用于所有字体!

答案 14 :(得分:1)

    NSDictionary *stringAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                      [UIFont systemFontOfSize:18], NSFontAttributeName,
                                      [UIColor blackColor], NSForegroundColorAttributeName,
                                      nil];

    NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:myLabel.text attributes:stringAttributes];
    myLabel.attributedText = attributedString; //this is the key!

    CGSize maximumLabelSize = CGSizeMake (screenRect.size.width - 40, CGFLOAT_MAX);

    CGRect newRect = [myLabel.text boundingRectWithSize:maximumLabelSize
                                                       options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                                    attributes:stringAttributes context:nil];

    self.myLabelHeightConstraint.constant = ceilf(newRect.size.height);

我尝试了这个页面上的所有内容,但仍然有一个UILabel没有正确格式化的情况。实际上在标签上设置attributedText最终修复了问题。

答案 15 :(得分:1)

这里的许多答案都很棒,David Rees 很好地总结了 options

但有时当有特殊字符或多个空格时,大小似乎总是错误的。

无效字符串的示例(对我而言):

"hello    .   .  world"

我发现将 NSAttributedStringkern 设置为 1 有助于返回正确的大小。

像这样:

NSAttributedString(
    string: "some string",
    attributes: [
        .font: NSFont.preferredFont(forTextStyle: .body), 
        .kern: 1])

答案 16 :(得分:1)

我遇到了同样的问题,但我发现已经正确设置了高度限制。所以我做了以下事情:

-(CGSize)MaxHeighForTextInRow:(NSString *)RowText width:(float)UITextviewWidth {

    CGSize constrainedSize = CGSizeMake(UITextviewWidth, CGFLOAT_MAX);

    NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                                          [UIFont fontWithName:@"HelveticaNeue" size:11.0], NSFontAttributeName,
                                          nil];

    NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:RowText attributes:attributesDictionary];

    CGRect requiredHeight = [string boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin context:nil];

    if (requiredHeight.size.width > UITextviewWidth) {
        requiredHeight = CGRectMake(0, 0, UITextviewWidth, requiredHeight.size.height);
    }

    return requiredHeight.size;
}

答案 17 :(得分:1)

我注意到的一件事是,从(CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context返回的矩形的宽度将大于我传入的矩形。当发生这种情况时,我的字符串将被截断。我这样解决了:

NSString *aLongString = ...
NSInteger width = //some width;            
UIFont *font = //your font;
CGRect rect = [aLongString boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
                                        options:(NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin)
                                     attributes:@{ NSFontAttributeName : font,
                                                   NSForegroundColorAttributeName : [UIColor whiteColor]}
                                        context:nil];

if(rect.size.width > width)
{
    return rect.size.height + font.lineHeight;
}
return rect.size.height;

更多情况;我有多行文本,我试图找到正确的高度来显示它.bondRectWithSize有时返回的宽度大于我指定的宽度,因此当我使用我的过去的宽度和计算的高度来显示我的文本,它会截断。从boundingRectWithSize使用错误宽度时的测试开始,它将使高度短的量为1行。所以我会检查宽度是否更大,如果是这样,添加字体的lineHeight以提供足够的空间以避免截断。

答案 18 :(得分:0)

遇到了完全相同的问题。

对我来说,问题是由TTTAttributedLabel

解决的
+ (CGSize)sizeThatFitsAttributedString:(NSAttributedString *)attributedString
                       withConstraints:(CGSize)size
                limitedToNumberOfLines:(NSUInteger)numberOfLines

方法,因为它可以提供准确的结果。

答案 19 :(得分:0)

我在计算 NSTextField 的高度时遇到问题。我尝试过的任何方法总是返回太小的值。
对我来说,问题是由于某种原因,NSTextFieldattributedStringValue 属性从未包含我通过 Interface Builder 设置的任何属性。如果我没有以编程方式设置属性字符串,它实际上根本不包含任何属性。连字体都没有。这就是为什么所有的高度计算都被搞砸了。

为了让它工作,我为 Category 创建了一个 NSTextField,它实现了一个自定义函数来获取正确的属性字符串。

这是该 Category 的实现文件:

//
// --------------------------------------------------------------------------
// NSTextField+Additions.m
// Created for Mac Mouse Fix (https://github.com/noah-nuebling/mac-mouse-fix)
// Created by Noah Nuebling in 2021
// Licensed under MIT
// --------------------------------------------------------------------------
//

#import "NSTextField+Additions.h"

@implementation NSTextField (Additions)

// Copy paste template for adding attributes to an attributed string. Contains all possible attributes

//    [str addAttributes:@{
//        NSFontAttributeName:                NSNull.null,
//        NSParagraphStyleAttributeName:      NSNull.null,
//        NSForegroundColorAttributeName:     NSNull.null,
//        NSBackgroundColorAttributeName:     NSNull.null,
//        NSLigatureAttributeName:            NSNull.null,
//        NSKernAttributeName:                NSNull.null,
//        NSStrikethroughStyleAttributeName:  NSNull.null,
//        NSUnderlineStyleAttributeName:      NSNull.null,
//        NSStrokeColorAttributeName:         NSNull.null,
//        NSStrokeWidthAttributeName:         NSNull.null,
//        NSShadowAttributeName:              NSNull.null,
//        NSTextEffectAttributeName:          NSNull.null,
//        NSAttachmentAttributeName:          NSNull.null,
//        NSLinkAttributeName:                NSNull.null,
//        NSBaselineOffsetAttributeName:      NSNull.null,
//        NSUnderlineColorAttributeName:      NSNull.null,
//        NSStrikethroughColorAttributeName:  NSNull.null,
//        NSObliquenessAttributeName:         NSNull.null,
//        NSExpansionAttributeName:           NSNull.null,
//        NSWritingDirectionAttributeName:    NSNull.null,
//        NSVerticalGlyphFormAttributeName:   NSNull.null,
//    } range:NSMakeRange(0, str.length)];

/// In my testing NSTextField.attributedStringValue actually returned a string without _any_ attributes. Not even a font or anything.
/// This lead to issues when trying to calculate the fitting height for a certain width of the NSTextField.
/// This function takes some of the properties of the NSTextField and returns an NSAttributed string based on those.
/// I'm not sure this is perfect, but the returned attributed string describes the way that the text of the NSTextField is rendered close enough to be usable for my height calculations
- (NSAttributedString *)effectiveAttributedStringValue {
    
    NSMutableAttributedString *str = self.attributedStringValue.mutableCopy;

    // Create paragraph style from NSTextField properties
    
    // Not sure if we're setting these properties correctly, and there could be more properties we should be setting
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.alignment = self.alignment;
    paragraphStyle.baseWritingDirection = self.baseWritingDirection;
    paragraphStyle.lineBreakMode = self.lineBreakMode;
    paragraphStyle.allowsDefaultTighteningForTruncation = self.allowsDefaultTighteningForTruncation;
    if (@available(macOS 10.15, *)) paragraphStyle.lineBreakStrategy = self.lineBreakStrategy;
    
    // Add attributes to AttributedString based on NSTextField properties
     
    [str addAttributes:@{
        NSFontAttributeName:                self.font,
        NSParagraphStyleAttributeName:      paragraphStyle,
        NSForegroundColorAttributeName:     self.textColor,
        NSBackgroundColorAttributeName:     self.backgroundColor,
//        NSLigatureAttributeName:            NSNull.null,
//        NSKernAttributeName:                NSNull.null,
//        NSStrikethroughStyleAttributeName:  NSNull.null,
//        NSUnderlineStyleAttributeName:      NSNull.null,
//        NSStrokeColorAttributeName:         NSNull.null,
//        NSStrokeWidthAttributeName:         NSNull.null,
//        NSShadowAttributeName:              NSNull.null, //self.shadow,
//        NSTextEffectAttributeName:          NSNull.null,
//        NSAttachmentAttributeName:          NSNull.null,
//        NSLinkAttributeName:                NSNull.null,
//        NSBaselineOffsetAttributeName:      NSNull.null, //self.baselineOffsetFromBottom,
//        NSUnderlineColorAttributeName:      NSNull.null,
//        NSStrikethroughColorAttributeName:  NSNull.null,
//        NSObliquenessAttributeName:         NSNull.null,
//        NSExpansionAttributeName:           NSNull.null,
//        NSWritingDirectionAttributeName:    NSNull.null, //self.baseWritingDirection,
//        NSVerticalGlyphFormAttributeName:   NSNull.null,
    } range:NSMakeRange(0, str.length)];
    
    // return NSAttributedString
    
    return str;
    
}

@end


随机旁注

  • 我在此线程中读到的一些关于人们使用 UILabel 的问题听起来很可能是相关的。
  • 我最终决定使用 NSTextView 而不是 NSTextField,因为它获取属性字符串的方法是开箱即用的,并且将 NSTextField 用于可点击链接也完全是拙劣的。我的印象是 NSTextField 只是一个有问题的混乱,除了最基本的用例之外,您应该避免。

答案 20 :(得分:0)

好的,所以我花了很多时间调试这个。我发现由boundingRectWithSize允许显示文字的UITextView定义的最大文字高度低于框架尺寸。

在我的情况下,框架最多为140pt,但UITextView最多可容忍文本为131pt。

我必须手动识别并硬编码“真正的”最大高度。

这是我的解决方案:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    NSString *proposedText = [textView.text stringByReplacingCharactersInRange:range withString:text];
    NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:proposedText];
    CGRect boundingRect;
    CGFloat maxFontSize = 100;
    CGFloat minFontSize = 30;
    CGFloat fontSize = maxFontSize + 1;
    BOOL fit;
    NSLog(@"Trying text: \"%@\"", proposedText);
    do {
        fontSize -= 1;
        //XXX Seems like trailing whitespaces count for 0. find a workaround
        [attributedText addAttribute:NSFontAttributeName value:[textView.font fontWithSize:fontSize] range:NSMakeRange(0, attributedText.length)];
        CGFloat padding = textView.textContainer.lineFragmentPadding;
        CGSize boundingSize = CGSizeMake(textView.frame.size.width - padding * 2, CGFLOAT_MAX);
        boundingRect = [attributedText boundingRectWithSize:boundingSize options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading context:nil];
        NSLog(@"bounding rect for font %f is %@; (max is %f %f). Padding: %f", fontSize, NSStringFromCGRect(boundingRect), textView.frame.size.width, 148.0, padding);
        fit =  boundingRect.size.height <= 131;
    } while (!fit && fontSize > minFontSize);
    if (fit) {
        self.textView.font = [self.textView.font fontWithSize:fontSize];
        NSLog(@"Fit!");
    } else {
        NSLog(@"No fit");
    }
    return fit;
}

答案 21 :(得分:0)

Add Following methods in ur code for getting correct size of attribute string 
1.
    - (CGFloat)findHeightForText:(NSAttributedString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font
 {
    UITextView *textView = [[UITextView alloc] init];
    [textView setAttributedText:text];
    [textView setFont:font];
    CGSize size = [textView sizeThatFits:CGSizeMake(widthValue, FLT_MAX)];
    return size.height;

}

2. Call on heightForRowAtIndexPath method
     int h = [self findHeightForText:attrString havingWidth:yourScreenWidth andFont:urFont];

答案 22 :(得分:0)

我想补充一下自己的想法,因为我遇到了同样的问题。

我正在使用UITextView,因为它有更好的文本对齐(证明,当时在UILabel中不可用),但是为了“模拟”非交互式 - 不可滚动的{ {1}},我会关闭完全滚动,弹跳和用户互动。

当然,问题是文本是动态的,虽然宽度是固定的,但每次设置新文本值时都应重新计算高度。

UILabel对我来说效果不好,从我看到的情况来看,boundingRectWithSizeUITextView上添加了一些余额,boundingRectWithSize不会计入,因此,从boundingRectWithSize检索到的高度小于应有的高度。

由于文本没有快速更新,它只是用于一些可能每2-3秒更新一次的信息,我已经决定采用以下方法:

/* This f is nested in a custom UIView-inherited class that is built using xib file */
-(void) setTextAndAutoSize:(NSString*)text inTextView:(UITextView*)tv
{
    CGFloat msgWidth = tv.frame.size.width; // get target's width

    // Make "test" UITextView to calculate correct size
    UITextView *temp = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, msgWidth, 300)]; // we set some height, really doesn't matter, just put some value like this one.
    // Set all font and text related parameters to be exact as the ones in targeted text view
    [temp setFont:tv.font];
    [temp setTextAlignment:tv.textAlignment];
    [temp setTextColor:tv.textColor];
    [temp setText:text];

    // Ask for size that fits :P
    CGSize tv_size = [temp sizeThatFits:CGSizeMake(msgWidth, 300)];

    // kill this "test" UITextView, it's purpose is over
    [temp release];
    temp = nil;

    // apply calculated size. if calcualted width differs, I choose to ignore it anyway and use only height because I want to have width absolutely fixed to designed value
    tv.frame = CGRectMake(tv.frame.origin.x, tv.frame.origin.y, msgWidth, tv_size.height );
}

*以上代码不是直接从我的源代码复制的,我不得不调整它/从本文不需要的其他东西中清除它。不要把它用于复制粘贴和工作代码。

明显的缺点是它为每次调用都有alloc和release。

但是,优点是你可以避免依赖于boundingRectWithSize如何绘制文本之间的兼容性,并计算它的大小和UITextView中的文本绘图的实现(或UILabel,你也可以使用它来替换{​​{1}与UITextView)。苹果公司可能遇到的任何“错误”都是这样避免的。

P.S。看起来你不应该需要这个“临时”UILabel并且可以直接从目标中询问UITextView,但这对我不起作用。虽然逻辑会说它应该工作并且不需要临时sizeThatFits的分配/释放,但事实并非如此。但是这个解决方案可以完美地用于我想要的任何文本。

答案 23 :(得分:0)

    NSAttributedString *attributedText =[[[NSAttributedString alloc]
                                          initWithString:joyMeComment.content
                                          attributes:@{ NSFontAttributeName: [UIFont systemFontOfSize:TextFont]}] autorelease];

    CGRect paragraphRect =
    [attributedText boundingRectWithSize:CGSizeMake(kWith, CGFLOAT_MAX)
                                 options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                 context:nil];
    contentSize = paragraphRect.size;

    contentSize.size.height+=10;
    label.frame=contentSize;

如果标签的框架没有添加10,这种方法永远不会起作用!希望这可以帮到你! goog luck。