159

属性付き文字列の四角形を取得しようとしていますが、boundingRectWithSize呼び出しは、渡したサイズを尊重せず、高さが大きい(長い文字列)のではなく、1行の高さの四角形を返します。以下のコードのように、高さと0に非常に大きな値を渡すことで実験しましたが、返されるrectは常に同じです。

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

これは壊れていますか、それともラップされたテキストの長方形を返すために何か他のことをする必要がありますか?

4

23 に答える 23

322

正しいオプションを提供していないようです。ラッピング ラベルの場合、少なくとも次の情報を提供してください。

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

注: 元のテキスト幅が 300.f 未満の場合、行の折り返しは行われないため、バインドされたサイズが正しいことを確認してください。そうしないと、間違った結果が得られます。

于 2013-03-14T01:48:29.773 に答える
51

何らかの理由で、boundingRectWithSize は常に間違ったサイズを返します。私は解決策を考え出しました。テキスト セットの適切なサイズを返す UItextView -sizeThatFits のメソッドがあります。したがって、boundingRectWithSize を使用する代わりに、ランダムなフレームで UITextView を作成し、その sizeThatFits をそれぞれの幅と CGFLOAT_MAX の高さで呼び出します。適切な高さになるサイズを返します。

   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 を使用しない場合、アプリのランタイム メモリが増加します。

于 2014-12-04T08:25:36.910 に答える
32

Ed McManus は、これを機能させるための鍵を確かに提供してくれました。うまくいかないケースを見つけた

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:は正確なサイズを提供しません。

于 2013-06-14T21:09:36.863 に答える
30

長い調査の結果、
- boundingRectWithSize関数は連続した文字列に対してのみ正しいサイズを返します! 文字列にスペースなどが含まれている場合 (Apple では「グリフの一部」と呼ばれています)、テキストを表示するために必要な rect の実際のサイズを取得することはできません!
文字列のスペースを文字に置き換えたところ、すぐに正しい結果が得られました。

Apple はここで言う: https://developer.apple.com/documentation/foundation/nsstring/1524729-boundingrectwithsize

「このメソッドは、文字列内のグリフの実際の境界を返します。一部のグリフ (スペースなど) は、渡されたサイズによって指定されたレイアウト制約とオーバーラップすることが許可されているため、場合によっては、サイズ コンポーネントの幅の値返さCGRectれる値は、サイズ パラメータの幅の値を超えることができます。」

したがって、実際の四角形を計算する別の方法を見つける必要があります...


長い調査プロセスの末、ついに解決策が見つかりました!!! に関連するすべてのケースでうまく機能するかどうかはわかりませんUITextViewが、主要かつ重要なことが検出されました!

boundingRectWithSize関数とCTFramesetterSuggestFrameSizeWithConstraints(および他の多くのメソッド) は、正しい四角形が使用されている場合、サイズとテキスト部分を正しく計算します。たとえば、 -has- でUITextViewありtextView.bounds.size.width、この値は、テキスト描画時にシステムによって使用される実際の四角形ではありませんUITextView

非常に興味深いパラメーターを見つけ、コードで簡単な計算を実行しました。

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

そして魔法が効きます - すべてのテキストが正しく計算されるようになりました! 楽しみ!

于 2014-09-19T19:31:26.537 に答える
8

好ましい解決策は改行を処理しないことがわかりました。

このアプローチはすべての場合に機能することがわかりました。

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;
于 2015-11-13T16:32:19.697 に答える
7

@warrenmフレームセッターの方法がうまくいかなかったと言って申し訳ありません。

これを取得しました。この関数は、特定の Width の iphone/Ipad SDK で NSAttributedString の文字列範囲に必要なフレーム サイズを決定するのに役立ちます。

UITableView セルの動的な高さに使用できます

- (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 に感謝 >>> http://haddadissa.blogspot.in/2010/09/compute-needed-heigh-for-fixed-width-of.html

于 2014-03-27T11:17:47.643 に答える
3

ゲームに少し遅れていますが、Finder でファイルを編集するのと同じように、属性付きの文字列の周りに収まる境界ボックスを見つけてフォーカス リングを作成する方法を見つけようとしています。文字列の末尾にスペースがある場合、または文字列内に複数のスペースがある場合、私が試したすべてが失敗しました。boundingRectWithSizeは、これと同様に惨めに失敗しますCTFramesetterCreateWithAttributedString

次のコードを使用するNSLayoutManagerと、これまでに見つけたすべてのケースでうまくいくようで、文字列を完全に囲む四角形を返します。おまけ: テキストを選択すると、選択範囲の端が、返された四角形の境界まで移動します。以下のコードは、 からの layoutManager を使用しますNSTextView

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

CGRect focusRingFrame = [layout boundingRectForGlyphRange:NSMakeRange(0, [[self textStorage] length]) inTextContainer:container];
于 2016-01-12T14:48:09.657 に答える
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;
}
于 2013-12-11T08:02:10.217 に答える
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 のケースが 1 つあります。実際にラベルに attributedText を設定すると、最終的に問題が修正されました。

于 2014-05-21T15:43:40.230 に答える
1

私が気づいたことの 1 つは、返される rect(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;

もう少しコンテキストがあります。複数行のテキストがあり、それを表示するのに適切な高さを見つけようとしていました.boundRectWithSizeは、指定した幅よりも大きい幅を返すことがあったため、過去の幅と計算された高さを使用してテキストを表示すると、切り捨てます。boundingRectWithSize が間違った幅を使用したときのテストから、高さが短くなる量は 1 行でした。したがって、幅が大きいかどうかを確認し、そうである場合は、フォントの lineHeight を追加して、切り捨てを回避するのに十分なスペースを提供します。

于 2015-03-06T08:08:29.080 に答える
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 を加算しない場合、このメソッドは機能しません! これがあなたを助けることを願っています! 運がいい。

于 2013-11-29T09:33:04.463 に答える
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];
于 2015-12-19T06:30:12.580 に答える
0

まったく同じ問題が発生しました。

私にとって、問題はTTTAttributedLabelによって解決されます

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

正確な結果が得られるためです。

于 2020-08-10T09:17:49.493 に答える