잘못된 크기를 반환하는 NSAttributedString에 대한 boundingRectWithSize


151

기여한 문자열에 대한 rect를 얻으려고하지만 boundingRectWithSize 호출은 전달하는 크기를 고려하지 않고 큰 높이 (긴 문자열)가 아닌 단일 행 높이의 rect를 반환합니다. 아래 코드와 같이 높이와 0에 대해 매우 큰 값을 전달하여 실험했지만 반환 된 rect는 항상 동일합니다.

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

이 문제가 해결 되었습니까? 아니면 줄 바꿈 된 텍스트에 대한 rect를 반환하려면 다른 작업을 수행해야합니까?


5
잘림 / 클리핑이있는 단락 스타일이 lineBreakMode있습니까?
danyowdee

1
UILabel이 잘못된 너비로 측정 / 포장되어 있기 때문에 이것을 읽고 있다면 stackoverflow.com/questions/46200027/…을 살펴보십시오 . 특히 앱 시작시 NSAllowsDefaultLineBreakStrategy를 false로 설정합니다.
eric

답변:


312

올바른 옵션을 제공하지 않은 것 같습니다. 라벨 포장의 경우 최소한 다음을 제공하십시오.

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

참고 : 원본 텍스트 너비가 300.f 미만인 경우 줄 바꿈이 없으므로 경계 크기가 올바른지 확인하십시오. 그렇지 않으면 여전히 잘못된 결과가 표시됩니다.


25
이 답변이 작동하기 때문에 모든 사람 이이 답변을 봐야합니다. 아마도이 방법과 일반적인 문자열에 대해서는보다 명확한 문서가 필요할 것입니다. 어디를 봐야하는지 명확하지 않습니다.
macserv

31
주의! 항상 작동하지는 않습니다! 반환 된 너비가 size 매개 변수의 너비보다 큰 경우가 있습니다. Apples 메서드 문서조차도 "size 매개 변수에 지정한 제약 조건은 렌더러가 문자열 크기를 조정하는 방법에 대한 지침입니다. 그러나이 방법으로 반환되는 실제 경계 사각형은 추가 공간이 필요한 경우 제약 조건보다 클 수 있습니다. 전체 문자열을 렌더링합니다. "
Klaas

75
NSAttributedString 및 boundingRectWithSize 용 API는 매우 충격적입니다.
malhal

27
또 다른 문제는 단락에서 반환 된 높이 (및 아마도 너비)는 거의 항상 분수 값이라는 것입니다. 따라서 높이가 141.3이라고 나올 수 있습니다. ceilf(paragraphRect.size.height)반올림 하려면 결과를 사용해야합니다 . 나는 이것을 항상 잊고 왜 내 레이블이 여전히 클리핑되는지 궁금합니다.
jamone

39
항상 boundingRectWithSize:계산을 CGRectIntegral ()로 래핑합니다 CGRectIntegral rounds the rectangle’s origin downward and its size upward to the nearest whole integers.이 경우 높이 또는 너비가 분수 값인 경우 클리핑이 발생하지 않도록 높이와 너비를 반올림합니다.
runmad

47

어떤 이유로 든 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을 사용하지 않으면 앱의 런타임 메모리가 증가합니다.


1
작동합니다. 내가 시도한 다른 방법으로는 일을 할 수 없었습니다. 내 문제는 할당 된 귀중한 문자열의 복잡성에서 비롯된 것 같습니다. RTF 파일에서 왔으며 다양한 글꼴, 줄 간격, 그림자를 사용했으며 UsesLineFragmentOrigin 및 UsesFontLeading 사용에도 불구하고 충분히 큰 결과를 얻을 수 없었으며 문제의 원인은 문자열이 길어질수록 최악입니다. 내 생각에 비교적 간단한 문자열의 경우 boundingRectWithSize 메서드 작동 할 수 있습니다. 이 작업에는 더 나은 방법이 필요합니다.
John Bushnell

메소드 호출 UITextView만큼 많은 시간 을 작성하는 것이 과도하다고 생각하지 heightForRowAtIndexPath않습니까? 시간이 걸립니다
János

@ János에 동의하지만 이것이 나를 위해 일한 유일한 솔루션이었습니다.
shoan

btw 적절한 해결책을 요청했습니다 : stackoverflow.com/questions/32495744/…
János

이것이 작동하는 유일한 솔루션입니다. 이 문제는 9 년이되었으며 Apple은이 문제를 해결하고 싶지 않거나 엔지니어가이를 해결하기 위해 약해야합니다. 우리는 iOS 11에 대해 이야기하고 있지만 여전히 같은 버그가 있습니다.
Duck

31

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은 (추가 된 캐릭터 )의 속성 사전없이 초기화. 이것은 anotherString 의 적법한 초기화 프로그램 이지만 boundingRectWithSize : 는 정확한 크기를 제공하지 않습니다.


33
감사합니다! boundingRectWithSize가 실제로 작동하려면 NSAttributedString의 모든 부분에 최소한 NSFontAttributeName 및 NSForegroundColorAttributeName이 설정된 사전 세트가 있어야합니다. 나는 어디에도 문서화되어 있지 않다.
벤 휠러

3
boundingRectWithSize가 올바르게 작동하기 위해서는 하나를 만들기 위해 결합 된 다른 NSAttributedString이 모두 SAME 사전 (따라서 동일한 글꼴)을 사용해야합니다.
벤 휠러

1
이 솔루션은 "수축에 맞게"UILabel 범주에 사용하는 솔루션과 매우 유사합니다. 이것을 작동시키는 열쇠는 FLT_MAX 높이의 경계 사각형을 만드는 것이 었습니다. 그것 없이는 단 한 줄의 사각형을 얻는 것처럼 보입니다.
dre1138

모든 라운드 +1. 이것은 정말로 나를 얻었다. 그래서 그것을 해결 해줘서 감사합니다.
Wex

나는이 문제가 있었다. NSMutableAttributedString속성없이 공백과 줄 바꿈을 사용했는데 크기가 잘못되었습니다.
vbezhenar

28

오랜 조사 후의 최종 결정 :
- boundingRectWithSize함수는 중단되지 않은 일련의 문자에 대해서만 올바른 크기를 반환합니다! 문자열에 공백이나 다른 것이 포함되어있는 경우 (Apple "글리프 중 일부"라고 함) 텍스트를 표시하는 데 필요한 rect의 실제 크기를 얻는 것은 불가능합니다!
문자열의 공백을 문자로 바꾸고 즉시 올바른 결과를 얻었습니다.

애플은 여기에 말한다 : https://developer.apple.com/documentation/foundation/nsstring/1524729-boundingrectwithsize

"이 메서드는 문자열에서 글리프의 실제 경계를 반환합니다. 일부 글리프 (예 : 공백)는 전달 된 크기로 지정된 레이아웃 제약 조건과 겹칠 수 있으므로 일부 경우 크기 구성 요소의 너비 값은 반환 CGRect된 크기 매개 변수의 너비 값을 초과 할 수 있습니다. "

따라서 실제 rect를 계산하는 다른 방법을 찾아야합니다.


오랜 조사 끝에 해결책이 마침내 발견되었습니다 !!! 나는 그것이 관련된 모든 경우에 잘 작동하는지 확신 할 수 UITextView없지만 주요하고 중요한 것이 감지되었습니다!

boundingRectWithSize함수뿐만 아니라 CTFramesetterSuggestFrameSizeWithConstraints(및 다른 많은 방법)는 올바른 사각형을 사용할 때 크기와 텍스트 부분을 정확하게 계산합니다. 예를 들어 -has-및이 값 UITextViewtextView.bounds.size.width텍스트를 그릴 때 시스템에서 사용되는 실제 사각형이 아닙니다 UITextView.

매우 흥미로운 매개 변수를 발견하고 코드에서 간단한 계산을 수행했습니다.

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

그리고 마술 작품-내 모든 텍스트가 올바르게 계산되었습니다! 즐겨!


1
그렇다, 나는 너비에 대한 제약을 유지하지 않고 항상 더 커진다는 것을 알았다. 그것은 정말로 시원하지 않으며, 그들은 작업 방법을 더 이상 사용하지 않으며 이제 우리는이 쓰레기를 처리해야합니다.
Boris Gafurov

1
당신은 내 새로운 영웅입니다! 이것은 나를 미치게했다. textContainers 삽입물을 설정하고 있으므로 textView.bounds.size.witdh 대신 textView.textContainer.size.width를 사용해야했습니다.
GCBenson

나는 이것을 충분히 투표 할 수 없었다. 경계 계산에서 공백이 고려되지 않는 것이 이상합니다.
체이스 홀랜드

1
공백을 "3"과 같은 더미 문자로
바꾸면

1
이것은 나의 경력과 QA 팀과의 관계를 구했습니다. 나는 당신에게 맥주 남자를 빚지고있다!!
lucaslt89

14

스위프트 4 버전

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를 사용하여 텍스트를 측정하면 정수 크기를 제공하고 이모티콘 및 기타 유니 코드 문자를 잘 처리하므로 가장 효과적입니다.


10

나는 이러한 제안들 중 어느 것도 운이 없었다. 내 문자열에는 유니 코드 글 머리 기호가 포함되어 계산에서 슬픔을 일으킨 것으로 보입니다. 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);

유니 코드 도트가 아니었을 수도 있고 문자열 끝에 공백이있을 수도 있습니다. 위의 답변을 참조하십시오 : stackoverflow.com/a/25941139/337934 .
SAMB

9

꼬리를 잘라서 경계 상자를 얻으려면 이 질문 이 도움 될 수 있습니다.

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

9

boundingRectWithSize가 실제로 작동하려면 NSAttributedString의 모든 부분에 최소한 NSFontAttributeName 및 NSForegroundColorAttributeName이 설정된 사전 세트가 있어야합니다.

나는 어디에도 문서화되어 있지 않다.


덕분에,이 내가 만 NSFontAttributeName는 NSForegroundColorAttributeName 필요하지 않았다 발견 제외하고, 나를위한 솔루션이었다
Marmoy

7

@warrenm framesetter 방법이 저에게 효과적이지 않다고 말해서 죄송합니다.

이 함수는 주어진 너비에 대해 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


모든 기기 (iPhone 4 및 5)에서 작동하지 않습니다. iOS7.1.2를 사용하는 기기와 iOS8.3을 사용하는 4s Simulator 모두 :(
sanjana

수입이 필요하십니까?
jose920405

@KaranAlangat yes#import <CoreText/CoreText.h>
jose920405

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;

내 경우에는 백그라운드 스레드에서 계산을 수행해야하며 UI 요소의 사용은 허용되지 않습니다.
Lubbo

4

이 기술을 사용하여 정확한 크기를 얻지 못하는 것과 동일한 문제가 있었고 작동하도록 접근 방식을 변경했습니다.

스크롤 뷰에 맞추려고 노력한 긴 문자열이 잘려서 제대로 표시되지 않습니다. 텍스트를 안정적으로 작동 시키려면 높이를 전혀 제약 조건으로 설정하지 않고 본질적인 크기가 대신되도록했습니다. 이제 텍스트가 잘리지 않고 올바르게 표시되며 높이를 계산할 필요가 없습니다.

높이를 안정적으로 가져와야하는 경우 숨겨진 뷰와 이러한 구속 조건을 만들고 구속 조건이 적용되면 프레임의 높이를 가져옵니다.


2
이것을 보여주기 위해 코드 샘플을 추가 할 수 있습니까? 고마워.
Nathan Buggia 2018

3

나는 게임에 조금 늦었지만-Finder에서 파일을 편집하는 것처럼 초점이 울리는 문자열을 묶을 경계 상자를 찾는 방법을 알아 내려고 노력했습니다. 문자열 끝에 공백이 있거나 문자열 안에 여러 공백이 있으면 시도한 모든 것이 실패했습니다. boundingRectWithSize이뿐 만 아니라 비참하게 실패CTFramesetterCreateWithAttributedString .

NSLayoutManager다음 코드를 사용하면 지금까지 찾은 모든 경우에 트릭을 수행하고 문자열을 완벽하게 묶는 rect를 반환합니다. 보너스 : 텍스트를 선택하면 선택의 가장자리가 반환 된 rect의 경계까지 올라갑니다. 아래 코드는의 layoutManager를 사용합니다 NSTextView.

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

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

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

모든 글꼴에서 완벽하게 작동합니다!


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

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에 대한 사례가 하나 있습니다. 실제로 label에 ValueedText를 설정하면 문제가 해결되었습니다.


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를 추가하여 잘림을 피할 수있는 충분한 공간을 제공하십시오.


선 높이는 너비에 어떤 영향을 줍니까?
Roi Mulia

@RoiMulia 줄 높이는 너비에 영향을 미치지 않습니다. 이것이 어떻게 버그를 수정했는지에 대한 더 많은 컨텍스트를 제공하기 위해 답변을 업데이트했습니다.
odyth

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을 추가하지 않으면이 방법은 작동하지 않습니다! 이것이 당신을 도울 수 있기를 바랍니다! 구운.


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

내 경우에는 백그라운드 스레드에서 계산을 수행해야하며 UI 요소의 사용은 허용되지 않습니다.
Lubbo

0

정확히 같은 문제가 있었으므로 생각을 추가하고 싶습니다.

나는 UITextView텍스트 정렬이 더 좋았 기 때문에 사용 하고 있었지만 (당시에는 사용할 수 없었던 정당화 UILabel), 비 대화 형 비 스크롤 가능을 "시뮬레이션"하기 위해 UILabel완전히 스크롤링, 수신 거부 및 사용자 상호 작용을 완전히 해제했습니다. .

물론 문제는 텍스트가 동적이며 너비는 고정되어 있지만 새 텍스트 값을 설정할 때마다 높이를 다시 계산해야한다는 것이 었습니다.

boundingRectWithSize내가 볼 수 있듯이, 나에게 전혀 효과가 없었습니다. UITextView마진을 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 );
}

* 위의 코드는 내 소스에서 직접 복사되지 않았 으므로이 기사에 필요하지 않은 다른 것들로부터 조정 / 삭제해야했습니다. 복사하여 붙여 넣기 및 작업 코드로 작성하지 마십시오.

명백한 단점은 각 호출에 대해 할당 및 해제가 있다는 것입니다.

그러나 boundingRectWithSize가 텍스트를 그리는 방법과 텍스트 그리기의 크기와 구현을 계산하는 방법 사이의 호환성에 의존하지 않는 장점이 있습니다 UITextView(또는 UILabel대신 대체로 사용할 수 UITextView있음 UILabel). 애플이 가질 수있는 "버그"는 이런 식으로 피할 수 있습니다.

추신 : 당신은이 "임시"가 필요하지 않을 것 같고 목표에서 직접 UITextView요청할 sizeThatFits수는 있지만 그것은 효과가 없었습니다. 논리는 작동해야한다고 말하고 임시 할당 / 해제는 UITextView필요하지 않지만 그렇지 않았습니다. 그러나이 솔루션은 내가 설정 한 모든 텍스트에 대해 완벽하게 작동했습니다.


내 경우에는 백그라운드 스레드에서 계산을 수행해야하며 UI 요소의 사용은 허용되지 않습니다.
Lubbo

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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.