programing

NSAttributedString의 boundingRectWithSize가 잘못된 크기를 반환함

cafebook 2023. 4. 13. 21:09
반응형

NSAttributedString의 boundingRectWithSize가 잘못된 크기를 반환함

속성 문자열의 직선을 가져오려고 하는데 boundingRectWithSize 콜이 전달한 크기를 고려하지 않고 큰 높이(긴 문자열)가 아닌 단일 회선 높이의 직선을 반환합니다.아래 코드와 같이 높이와 0을 매우 큰 값으로 전달하여 시험해 보았습니다만, 반환되는 직장은 항상 동일합니다.

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

이게 고장난 건가요?아니면 텍스트 랩에 대한 교정을 돌려받으려면 뭔가 다른 조치를 취해야 하나요?

올바른 선택지를 제시하지 못한 것 같군요.포장 라벨의 경우 최소한 다음을 제공해야 합니다.

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

주의: 원래 텍스트의 너비가 300 미만이면 줄 바꿈이 없으므로 바운드 크기가 올바른지 확인하십시오. 그렇지 않으면 잘못된 결과가 나타납니다.

어떤 이유로 boundingRectWithSize는 항상 잘못된 크기를 반환합니다.해결책을 찾아냈어요UItextView -size에 대한 메서드가 있습니다.ThatFits 텍스트 세트의 적절한 크기를 반환합니다.따라서 boundingRectWithSize를 사용하는 대신 랜덤 프레임을 사용하여 UITextView를 생성하여 크기를 호출합니다.이는 각각의 폭과 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 loop에서 크기를 계산할 경우 자동 리셋 풀에 UITextView가 n개 생성되므로 자동 리셋 풀을 사용하지 않으면 앱의 런타임 메모리가 증가한다는 것을 잊지 마십시오.

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

직장의 높이가 올바르지 않습니다.anotherString(문자열에 추가됨)이 속성 사전 없이 초기화되었습니다.이것은 anotherString의 정규 이니셜라이저이지만 boundingRectWithSize:는 이 경우 정확한 크기를 제공하지 않습니다.

「 」 「 」 、 「 」 、 「 」
- boundingRectWithSize함수는 중단되지 않는 문자 시퀀스에 대해서만 올바른 크기를 반환합니다.문자열에 공백이나 다른 것이 포함되어 있는 경우(Apple "Some of the gliphs"라고 함) 텍스트 표시에 필요한 실제 크기를 얻을 수 없습니다.
문자열의 공백을 문자로 대체하여 바로 올바른 결과를 얻었습니다.

애플은 다음과 같이 말합니다.https://developer.apple.com/documentation/foundation/nsstring/1524729-boundingrectwithsize

"이 메서드는 문자열에 있는 글리프의 실제 경계를 반환합니다.수의 폭 이 겹칠 수 있습니다.CGRect의 폭 할 수 있습니다.「 size 」 「 size 」 「 size 」는 「size 」로 설정되어 있습니다.

그래서 실제 직선을 계산할 다른 방법을 찾아야 해요


오랜 조사 끝에 드디어 해결책을 찾았습니다!!!이 모든 는 잘 모르겠습니다.UITextView하지만, 주요하고 중요한 것이 탐지되었습니다!

boundingRectWithSizeCTFramesetterSuggestFrameSizeWithConstraints올바른 직사각형을 사용하면 크기와 텍스트 부분이 올바르게 계산됩니다. ::UITextView 있다textView.bounds.size.width 이 때 . - value값 텍 、 이 、 used 、 used 、 used 、 used 、 used 、 used 、 - used - - - - 。UITextView.

매우 흥미로운 파라미터를 찾아 코드에서 간단한 계산을 수행했습니다.

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

그리고 마법이 통한다 - 내 모든 문자는 지금 정확히 계산되었다!맛있게 드세요!

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

나는 이 제안들 중 어떤 것도 운이 좋지 않았다.내 줄에는 유니코드 글머리 기호들이 들어있었고 내 생각엔 그게 계산에 슬픔을 야기시킨 것 같아.UITextView가 도면을 잘 처리하고 있는 것을 알고 있었기 때문에 그 계산을 활용하기 위해 그것을 검토했습니다.NSString 、 NSString 、 NSString 、 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);

실제로 boundingRectWithSize를 동작시키려면 NSAttributeString의 모든 부분에는 적어도 NSFontAttributeName 및 NSForegroundColorAttributeName이 설정된 사전 세트가 필요합니다.

어디에도 그런 기록이 없어요.

꼬리를 잘라 바운딩 박스를 얻고 싶은 경우는, 질문이 도움이 됩니다.

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

선호하는 솔루션은 줄 바꿈을 처리하지 않는다는 것을 알게 되었습니다.

이 접근방식은 모든 경우에 유효합니다.

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;

@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 덕분입니다.

이러한 기술을 사용하여 정확한 사이즈를 얻을 수 없는 것과 같은 문제를 겪었고, 이를 작동시키기 위해 접근 방식을 변경했습니다.

긴 속성 문자열이 있습니다.이 문자열은 잘리지 않고 올바르게 표시되도록 스크롤 보기에 맞추려고 합니다.텍스트가 안정적으로 작동하도록 한 것은 높이를 전혀 제약으로 설정하지 않고 본래의 크기를 그대로 두었습니다.이제 텍스트가 잘리지 않고 올바르게 표시되므로 높이를 계산할 필요가 없습니다.

높이를 확실히 취득할 필요가 있는 경우는, 숨겨진 뷰와 이러한 구속조건을 작성해, 일단 구속조건을 적용하면 프레임의 높이를 취득할 수 있습니다.

2022년 7월 갱신

시행착오를 거듭하고 다른 답변, 특히 NSString을 사용하도록 지적된 답변으로부터 피드백을 받은 후.DrawingOptions.usesDeviceMetrics, 이 옵션은 확실히 게임 체인저라는 것을 알게 되었습니다만, 그것만으로는 충분하지 않습니다.

「」를 사용합니다..deviceMetrics는 올바른 '알겠습니다'를 합니다.height a, 만, 것, 것, 것, 것, 것, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, a, a, ,UILabel 것도 아니다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

에 이렇게 하다, 하다, 하다, 를 넣으면 돼요.CATextLayer 모로 보나NSView/UIView.

MacOS

let view = NSView()
view.wantsLayer = true
view.layer?.addSublayer(textLayer)

iOS

let view = UIView()
view.layer.addSublayer(textLayer)

원답 2021년 2월

이 답변의 대부분은 훌륭합니다.David Rees는 옵션을 잘 정리하고 있습니다.

하지만 때때로 특수 문자나 여러 개의 공백이 있을 때 크기가 항상 잘못된 것처럼 보였습니다.

동작하지 않는 문자열의 예(내 경우):

"hello    .   .  world"

내가 알아낸 건 그 의 설정이야기가NSAttributedString로로 합니다.1이치노

다음과 같이 합니다.

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

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

모든 글꼴에 완벽하게 대응!

저도 같은 문제가 있었습니다만, 높이 제한이 올바르게 설정되어 있는 것을 알 수 있었습니다.그래서 저는 다음과 같이 했습니다.

-(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;
}
    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 케이스가 하나 있었습니다.실제 속성 설정라벨의 텍스트로 문제가 해결되었습니다.

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

은 '은 '직장'이 '직장'에서 이다.(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;

콘텍스트에 따라 여러 줄의 텍스트를 표시하기 위해 적절한 높이를 찾고 있었습니다.Bound With Size는 지정한 너비보다 큰 너비를 반환하는 경우가 있었습니다.따라서 과거 너비와 계산된 높이를 사용하여 텍스트를 표시하면 잘립니다.boundingRectWithSize가 잘못된 너비를 사용했을 때 테스트한 결과 높이가 1줄로 짧아졌습니다.그래서 나는 너비가 더 큰지 확인하고 만약 그렇다면 글꼴의 선을 추가하겠다.잘리지 않도록 충분한 공간을 제공하는 높이입니다.

    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을 추가하지 않으면 이 방법은 작동하지 않습니다!이게 도움이 되길 바래! 행운을 빌어.

저도 똑같은 문제가 있었기 때문에 제 생각을 덧붙이고 싶습니다.

는 용 i i용었 i i i i i 。UITextView얼라인먼트가 더 좋기 할 수 UILabel"displictive"는 "non-displictive-non-displictible"을 사용합니다.UILabel스크롤, 바운스 및 사용자 상호 작용을 완전히 끕니다.

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

boundingRectWithSize전혀 UITextView .boundingRectWithSize 「Count」에서 , 「Count」가 되지 않습니다.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, 「치환」을 도 있습니다.UITextViewUILabel이렇게 하면 애플이 가지고 있을 수 있는 버그는 피할 수 있습니다.

'는 없을 것 요.UITextViewsizeThatFits임시, 로직은 동작/해제할 수 있습니다.UITextView요없,,,,필필필필필그러나 이 솔루션은 어떤 텍스트에서도 완벽하게 작동했습니다.

을 많이 요.의 최대 는 '글의 최대 높이'가 '글의 최대 높이'인 것을 알 수.boundingRectWithSize 스스 my my 로 텍스트를 표시할 수 .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;
}

똑같은 문제가 발생했습니다.

이 문제는 TTTAttributed Label's에 의해 해결되었습니다.

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

정확한 결과를 얻을 수 있기 때문입니다.

높이 계산에 문제가 있었습니다.NSTextField어떤 방법을 사용하든 항상 너무 작은 값을 반환했습니다.
에게 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.NSTextField의 »attributedStringValue「Interface Builder」(인터페이스 빌더).속성 문자열을 프로그래밍 방식으로 설정하지 않으면 실제로는 속성이 전혀 포함되지 않습니다.이 모두요.을 사용하다

, 나는 동시, a a a a a a a a를 만들었다.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가장 기본적인 사용 사례를 넘어서면 안 되는 버그에 불과합니다.

때때로 바운딩 Rect, 특히 단락과 브레이크 라인으로 높이를 계산하는 데 문제가 있었습니다." " " .usesDeviceMetrics파라미터가 효과를 발휘했습니다.이제 모든 경우에 잘 작동하는 것 같습니다.

extension NSAttributedString {

    func heightWithWidth(_ width: CGFloat) -> CGFloat {

        let constraints = CGSize(width: width, height: .infinity)

        let bounding = self.boundingRect(with: constraints, options: [.usesLineFragmentOrigin, .usesFontLeading, .usesDeviceMetrics], context: nil)
        return bounding.height

    }
}
   

"lineBreakMode" "lineBreakMode" 입니다.는 ★★★★★★★★★★★★★★★★★★★★★★★★★.byTruncatingTail단, , , , , 가 필요합니다..byWordWrapping(미국의)

여기에 이미지 설명 입력

또한 키를 계산하는 다른 방법을 시도했을 때 두 가지 다른 방법을 발견했습니다.

첫번째

https://gist.github.com/krzyzanowskim/e92eaf31e0419820c0f8cbcf96ba1269#file-stringgetsizethatfits-swift

둘째

func sizeFittingWidth(_ w: CGFloat) -> CGSize {
    let textStorage = NSTextStorage(attributedString: self)
    let size = CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)
    let boundingRect = CGRect(origin: .zero, size: size)
    let textContainer = NSTextContainer(size: size)
    textContainer.lineFragmentPadding = 0
    let layoutManager = NSLayoutManager()
    layoutManager.addTextContainer(textContainer)
    textStorage.addLayoutManager(layoutManager)
    layoutManager.glyphRange(forBoundingRect: boundingRect, in: textContainer)
    let rect = layoutManager.usedRect(for: textContainer)
    return rect.integral.size
}

언급URL : https://stackoverflow.com/questions/13621084/boundingrectwithsize-for-nsattributedstring-returning-wrong-size

반응형