iOS 7에서 더 이상 사용되지 않는 크기로 대체 :


320

iOS 7에서는 sizeWithFont:더 이상 사용되지 않습니다. UIFont 객체를 대체 방법으로 전달하려면 어떻게해야 sizeWithAttributes:합니까?

답변:


521

sizeWithAttributes:대신을 사용하십시오 NSDictionary. 키 UITextAttributeFont와 글꼴 객체 쌍을 다음과 같이 전달하십시오.

CGSize size = [string sizeWithAttributes:
    @{NSFontAttributeName: [UIFont systemFontOfSize:17.0f]}];

// Values are fractional -- you should take the ceilf to get equivalent values
CGSize adjustedSize = CGSizeMake(ceilf(size.width), ceilf(size.height));

60
작업을 할 때 NSStringUILabel(경우에, 항상은 아니지만 종종 너무) 등 중복 코드 / 방지하기 위해, 당신은 또한 대체 할 수있는 [UIFont systemFontOfSize:17.0f]과가 label.font- 그것을 여러 번 입력하면 대 기존 데이터를 참조하거나 이상 모든 상수를 참조하여 코드를 유지 보수하는 데 도움이 장소 등
toblerpwn

8
@toblerpwn 레이블이 존재하지 않을 수 있으며 이론적 레이블을 계산하려고합니다.
botbot

5
이 예제를 사용하여 size.height를 고정 너비가 250과 같은 레이블로 얻는 방법은 무엇입니까? 또는 autolatyout 마녀가있는 레이블이 너비의 백분율을 차지하고 가로 모드로 이동하면.
Pedroinpeace

12
@Pedroinpeace 대부분의 경우에 boundingRectWithSize:options:attributes:context:전달 하여 대신 사용 합니다 CGSizeMake(250.0f, CGFLOAT_MAX).
James Kuang

9
sizeWithAttributes :를 주목할만한 다른 것은 100 % 동일하지 않습니다. sizeWithFont는 크기를 정수 (픽셀) 값으로 반올림하는 데 사용됩니다. 결과 높이 / 너비에 ceilf를 사용하도록 제안하거나 위치 계산에 이것을 사용하면 흐릿한 인공물 (esp non retina HW)을 얻을 수 있습니다.
Nick H247

172

일련의 NSString+UIKit함수 ( sizewithFont:...등)가 UIStringDrawing라이브러리를 기반으로 했기 때문에 함수가 더 이상 사용되지 않는다고 생각합니다.이 라이브러리는 스레드 안전하지 않습니다. 메인 스레드에서 다른 UIKit기능 과 달리 실행하지 않으면 예기치 않은 동작이 발생합니다. 특히 여러 스레드에서 동시에 함수를 실행하면 앱이 중단 될 수 있습니다. 이것이 iOS 6에서에 대한 boundingRectWithSize:...방법을 도입 한 이유 입니다 NSAttributedString. 이것은 NSStringDrawing라이브러리 위에 구축되었으며 스레드로부터 안전합니다.

NSString boundingRectWithSize:...함수 를 보면 a와 같은 방식으로 속성 배열을 요청합니다 NSAttributeString. 내가 추측해야한다면, NSStringiOS 7의 새로운 NSAttributeString기능은 iOS 6 의 기능에 대한 래퍼 일뿐 입니다.

참고로 iOS 6 및 iOS 7 만 지원하는 경우 모든 것을로 변경 NSString sizeWithFont:...합니다 NSAttributeString boundingRectWithSize. 이상한 멀티 스레딩 코너 케이스가 발생하면 두통을 많이 피할 수 있습니다! 내가 변환 한 방법은 다음과 같습니다 NSString sizeWithFont:constrainedToSize:.

예전의 것 :

NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font 
               constrainedToSize:(CGSize){width, CGFLOAT_MAX}];

다음으로 대체 할 수 있습니다.

NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
NSAttributedString *attributedText =
    [[NSAttributedString alloc] initWithString:text 
                                    attributes:@{NSFontAttributeName: font}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX}
                                           options:NSStringDrawingUsesLineFragmentOrigin
                                           context:nil];
CGSize size = rect.size;

설명서에 언급 된 사항에 유의하십시오.

iOS 7 이상에서이 메소드는 소수 크기를 리턴합니다 (리턴 된 크기 구성 요소에서 CGRect). 리턴 된 크기를 사용하여 크기를보기 위해서는 ceil 함수를 사용하여 가장 큰 정수로 값을 올리십시오.

따라서 크기 조정 뷰에 사용할 계산 된 높이 또는 너비를 꺼내려면 다음을 사용합니다.

CGFloat height = ceilf(size.height);
CGFloat width  = ceilf(size.width);

boundingRectWithSize는 iOS 6.0에서 더 이상 사용되지 않습니다.
Nirav

2
@Nirav 저는 지원 중단에 대한 언급이 없습니다. 더 이상 사용되지 않는 위치를 알려 주시겠습니까? 감사! ( developer.apple.com/library/ios/documentation/uikit/reference/… )
Mr. T

2
어쩌면 @Nirav 는 iOS 6에서 NSString 을 사용할 수 없다는 것을 의미했을 것입니다 (답변에 간접적으로 언급되어 있음)?
newenglander

1
@VagueExplanation 방금 시도했지만 boundingRectForSize는 NSAttributedString에 대해 더 이상 사용되지 않습니다. 또한 문서에서 더 이상 사용되지 않는다고 말하지 않습니다.
Mr. T

5
ceilf () 사용에 대해 환상적입니다. 다른 곳에서는 언급하지 않았으며 내 크기는 항상 약간 작습니다. 감사!
Jonathan Brown

29

sizeWithFontApple 개발자 사이트에서 볼 수 있듯이 더 이상 사용되지 않으므로를 사용해야 sizeWithAttributes합니다.

#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)

NSString *text = @"Hello iOS 7.0";
if (SYSTEM_VERSION_LESS_THAN(@"7.0")) {
    // code here for iOS 5.0,6.0 and so on
    CGSize fontSize = [text sizeWithFont:[UIFont fontWithName:@"Helvetica" 
                                                         size:12]];
} else {
    // code here for iOS 7.0
   CGSize fontSize = [text sizeWithAttributes: 
                            @{NSFontAttributeName: 
                              [UIFont fontWithName:@"Helvetica" size:12]}];
}

17
이 경우 다음 [NSObject respondsToSelector:]과 같은 방법 을 사용 하는 것이 좋습니다 . stackoverflow.com/a/3863039/1226304
derpoliuk

16

이 문제를 처리하기 위해 카테고리를 만들었습니다.

#import "NSString+StringSizeWithFont.h"

@implementation NSString (StringSizeWithFont)

- (CGSize) sizeWithMyFont:(UIFont *)fontToUse
{
    if ([self respondsToSelector:@selector(sizeWithAttributes:)])
    {
        NSDictionary* attribs = @{NSFontAttributeName:fontToUse};
        return ([self sizeWithAttributes:attribs]);
    }
    return ([self sizeWithFont:fontToUse]);
}

이 방법으로 당신은 찾기 / 바꾸기 만하면 sizeWithFont:됩니다 sizeWithMyFont:.


1
sizeWithFont를 참조하기 위해 ios7 +에서 컴파일러 경고를 생성하거나 sizeWithAttributes를 참조하기 위해 <ios7에서 컴파일 경고 / 오류를 생성합니다! 필요한 경우 respondsToSelector를 확인하는 대신 매크로를 사용하는 것이 가장 좋습니다. 그러나 더 이상 ioS6 SDK를 사용하여 애플에 제공 할 수 없으므로 아마도 그렇지 않습니다!
Nick H247

supress 경고의 #pragma GCC에 진단 무시 "-Wdeprecated-선언 '이 추가
라이언 Heitner

10

iOS7에서는 tableview : heightForRowAtIndexPath 메서드에 올바른 높이를 반환하는 논리가 필요했지만 sizeWithAttributes는 고정 너비 테이블 셀에 넣을지 모르기 때문에 문자열 길이에 관계없이 항상 같은 높이를 반환합니다. . 나는 이것이 나를 위해 잘 작동하고 테이블 셀의 너비를 고려하여 올바른 높이를 계산한다는 것을 알았습니다! 위의 T 씨의 답변을 바탕으로합니다.

NSString *text = @"The text that I want to wrap in a table cell."

CGFloat width = tableView.frame.size.width - 15 - 30 - 15;  //tableView width - left border width - accessory indicator - right border width
UIFont *font = [UIFont systemFontOfSize:17];
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName: font}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX}
                                           options:NSStringDrawingUsesLineFragmentOrigin
                                           context:nil];
CGSize size = rect.size;
size.height = ceilf(size.height);
size.width  = ceilf(size.width);
return size.height + 15;  //Add a little more padding for big thumbs and the detailText label

7

동적 높이를 사용하는 여러 줄 레이블은 크기를 올바르게 설정하기 위해 추가 정보가 필요할 수 있습니다. UIFont 및 NSParagraphStyle과 함께 sizeWithAttributes를 사용하여 글꼴과 줄 바꿈 모드를 모두 지정할 수 있습니다.

단락 스타일을 정의하고 다음과 같이 NSDictionary를 사용합니다.

// set paragraph style
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setLineBreakMode:NSLineBreakByWordWrapping];
// make dictionary of attributes with paragraph style
NSDictionary *sizeAttributes        = @{NSFontAttributeName:myLabel.font, NSParagraphStyleAttributeName: style};
// get the CGSize
CGSize adjustedSize = CGSizeMake(label.frame.size.width, CGFLOAT_MAX);

// alternatively you can also get a CGRect to determine height
CGRect rect = [myLabel.text boundingRectWithSize:adjustedSize
                                                         options:NSStringDrawingUsesLineFragmentOrigin
                                                      attributes:sizeAttributes
                                                         context:nil];

높이를 찾고 있다면 CGSize 'adjustedSize'또는 CGRect를 rect.size.height 속성으로 사용할 수 있습니다.

NSParagraphStyle에 대한 자세한 내용은 여기 ( https://developer.apple.com/library/mac/documentation/cocoa/reference/applicationkit/classes/NSParagraphStyle_Class/Reference/Reference.html)를 참조 하십시오.


1
adjustSize 직후에 구문 문제가있는 것 같습니다.
Chris Prince

이 구문 문제를 찾아 주셔서 감사합니다. Chris
bits and

6
// max size constraint
CGSize maximumLabelSize = CGSizeMake(184, FLT_MAX)

// font
UIFont *font = [UIFont fontWithName:TRADE_GOTHIC_REGULAR size:20.0f];

// set paragraph style
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;

// dictionary of attributes
NSDictionary *attributes = @{NSFontAttributeName:font,
                             NSParagraphStyleAttributeName: paragraphStyle.copy};

CGRect textRect = [string boundingRectWithSize: maximumLabelSize
                                     options:NSStringDrawingUsesLineFragmentOrigin
                                  attributes:attributes
                                     context:nil];

CGSize expectedLabelSize = CGSizeMake(ceil(textRect.size.width), ceil(textRect.size.height));

1
Kirit 덕분에 CGRect 블록 이전에 속성과 사전을 정의함으로써 두통을 피할 수있었습니다.
Azin Mehrnoosh

3

UILabel 인스턴스를 취하는 함수를 작성하십시오. CGSize를 반환

CGSize constraint = CGSizeMake(label.frame.size.width , 2000.0);
// Adjust according to requirement

CGSize size;
if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0){

    NSRange range = NSMakeRange(0, [label.attributedText length]);

    NSDictionary *attributes = [label.attributedText attributesAtIndex:0 effectiveRange:&range];
    CGSize boundingBox = [label.text boundingRectWithSize:constraint options: NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;

    size = CGSizeMake(ceil(boundingBox.width), ceil(boundingBox.height));
}
else{
    size = [label.text sizeWithFont:label.font constrainedToSize:constraint lineBreakMode:label.lineBreakMode];
}

return size;

dynamicaly Row height의 경우 HeightForRow 메서드를 완전히 제거하고 UITableViewAutomaticDimension을 사용했습니다. tableView.estimatedRowHeight = 68.0 tableView.rowHeight = UITableViewAutomaticDimension
Eugene Braginets

3

대체 솔루션

CGSize expectedLabelSize;
if ([subTitle respondsToSelector:@selector(sizeWithAttributes:)])
{
    expectedLabelSize = [subTitle sizeWithAttributes:@{NSFontAttributeName:subTitleLabel.font}];
}else{
    expectedLabelSize = [subTitle sizeWithFont:subTitleLabel.font constrainedToSize:subTitleLabel.frame.size lineBreakMode:NSLineBreakByWordWrapping];
}

1
이것은 iOS6 및 7에서 컴파일러 경고를 생성하며 각각에 대해 매우 다른 동작을합니다!
Nick H247

3

@bitsand을 기반으로, 이것은 NSString + Extras 범주에 방금 추가 한 새로운 방법입니다.

- (CGRect) boundingRectWithFont:(UIFont *) font constrainedToSize:(CGSize) constraintSize lineBreakMode:(NSLineBreakMode) lineBreakMode;
{
    // set paragraph style
    NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    [style setLineBreakMode:lineBreakMode];

    // make dictionary of attributes with paragraph style
    NSDictionary *sizeAttributes = @{NSFontAttributeName:font, NSParagraphStyleAttributeName: style};

    CGRect frame = [self boundingRectWithSize:constraintSize options:NSStringDrawingUsesLineFragmentOrigin attributes:sizeAttributes context:nil];

    /*
    // OLD
    CGSize stringSize = [self sizeWithFont:font
                              constrainedToSize:constraintSize
                                  lineBreakMode:lineBreakMode];
    // OLD
    */

    return frame;
}

결과 프레임의 크기 만 사용합니다.


2

계속 사용할 수 있습니다 sizeWithFont. 그러나 iOS> = 7.0의 경우 문자열에 선행 및 후행 공백 또는 끝 줄이 포함되어 있으면 메소드가 중단됩니다 \n.

사용하기 전에 텍스트 자르기

label.text = [label.text stringByTrimmingCharactersInSet:
             [NSCharacterSet whitespaceAndNewlineCharacterSet]];

sizeWithAttributes그리고에 적용될 수도 있습니다 [label sizeToFit].

또한 nsstringdrawingtextstorage message sent to deallocated instanceiOS 7.0 기기에 있을 때마다 이를 처리합니다.


2

더 나은 자동 치수 사용 (Swift) :

  tableView.estimatedRowHeight = 68.0
  tableView.rowHeight = UITableViewAutomaticDimension

NB : 1. UITableViewCell 프로토 타입이 올바르게 설계되어야합니다 (예 : UILabel.numberOfLines = 0 등을 설정하는 것을 잊지 마십시오) 2. HeightForRowAtIndexPath 메소드 제거

여기에 이미지 설명을 입력하십시오

비디오 : https://youtu.be/Sz3XfCsSb6k


스토리 보드 프로토 타입 셀에서 정의 된 정적 셀 높이를 사용합니다
Kirit Vaghela

이 두 줄을 추가하고 UILabel이 0 줄로 설정되었는지 확인하십시오. 광고 한대로 작동하지 않았습니다. 이 두 줄의 코드로 작동하게하기 위해 또 무엇을 했습니까?

1
흠, 또한 셀의 상단과 하단에 라벨 제약 핀이
유진 Braginets

1
아니요, 이것으로 충분합니다. 슈퍼 뷰에 고정 된 라벨에 대한 자동 레이아웃 제약 조건이 있습니까?
Eugene Braginets

1
boundingRectWithSize:options:attributes:context:

1

Xamarin에서 허용되는 답변 은 다음과 같습니다 (sizeWithAttributes 및 UITextAttributeFont 사용).

        UIStringAttributes attributes = new UIStringAttributes
        { 
            Font = UIFont.SystemFontOfSize(17) 
        }; 
        var size = text.GetSizeUsingAttributes(attributes);

1

@Ayush 답변으로 :

sizeWithFontApple 개발자 사이트에서 볼 수 있듯이 더 이상 사용되지 않으므로를 사용해야 sizeWithAttributes합니다.

음, 2019+에 당신은 아마 사용하고 있다고 가정하면 스위프트String대신의 목표 - C와 NSString여기의 크기받을 수 있나요 올바른 방법, String미리 정의 된 폰트가 :

let stringSize = NSString(string: label.text!).size(withAttributes: [.font : UIFont(name: "OpenSans-Regular", size: 15)!])

이것을 사용하여 글꼴 크기를 결정할 수 있습니까?
조셉 아스트라한

@JosephAstrahan 글꼴 크기를 결정하기위한 것이 아니라 결정된 글꼴로 문자열의 크기 (CGSize)를 얻는 것입니다. 레이블의 글꼴 크기를 얻으려면 label.font
Romulo BM

귀하의 아이디어를 사용하여 글꼴 크기를 다소 늘리 거나 줄이는 방법을 만들었습니다 ( stackoverflow.com/questions/61651614/… ). 정확한 글꼴은 내 게시물에서 읽을 수 있다고 알려져 있습니다.
조셉 아스트라한

0
- (CGSize) sizeWithMyFont:(UIFont *)fontToUse
{
    if ([self respondsToSelector:@selector(sizeWithAttributes:)])
    {
        NSDictionary* attribs = @{NSFontAttributeName:fontToUse};
        return ([self sizeWithAttributes:attribs]);
    }
    return ([self sizeWithFont:fontToUse]);
}

0

누군가가 필요로하는 경우 모노 터치에 해당합니다.

/// <summary>
/// Measures the height of the string for the given width.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="width">The width.</param>
/// <param name="padding">The padding.</param>
/// <returns></returns>
public static float MeasureStringHeightForWidth(this string text, UIFont font, float width, float padding = 20)
{
    NSAttributedString attributedString = new NSAttributedString(text, new UIStringAttributes() { Font = font });
    RectangleF rect = attributedString.GetBoundingRect(new SizeF(width, float.MaxValue), NSStringDrawingOptions.UsesLineFragmentOrigin, null);
    return rect.Height + padding;
}

다음과 같이 사용할 수 있습니다.

public override float GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
    //Elements is a string array
    return Elements[indexPath.Row].MeasureStringHeightForWidth(UIFont.SystemFontOfSize(UIFont.LabelFontSize), tableView.Frame.Size.Width - 15 - 30 - 15);
}

0
CGSize maximumLabelSize = CGSizeMake(label.frame.size.width, FLT_MAX);
CGSize expectedLabelSize = [label sizeThatFits:maximumLabelSize];
float heightUse = expectedLabelSize.height;

0

이 구문을 사용해보십시오 :

NSAttributedString *attributedText =
    [[NSAttributedString alloc] initWithString:text 
                                    attributes:@{NSFontAttributeName: font}];

-1

이 중 어느 것도 iOS 7에서 저에게 효과적이지 않았습니다. 여기서 내가 한 일이 있습니다. 나는 이것을 커스텀 셀 클래스에 넣고 heightForCellAtIndexPath 메소드에서 메소드를 호출한다.

내 셀은 앱 스토어에서 앱을 볼 때 설명 셀과 비슷하게 보입니다.

스토리 보드에서 먼저 라벨을 'attributedText'로 설정하고 줄 수를 0 (레이블의 크기가 자동으로 조정 됨 (ios 6+ 만 해당))으로 설정 한 다음 줄 바꿈으로 설정합니다.

그런 다음 사용자 정의 셀 클래스에서 셀 내용의 모든 높이를 추가합니다. 필자의 경우 항상 상단에 "설명"(_descriptionHeadingLabel)이라고 표시된 레이블이 있습니다. 셀의 상단에서 제목 (_descriptionHeadingLabelTopConstraint)까지의 실제 설명 (_descriptionLabel)을 포함하는 크기가 가변적 인 작은 레이블 . 또한 3을 추가하여 바닥에 약간의 간격을 두었습니다 (자막 유형 셀에 대략 같은 양의 사과 장소).

- (CGFloat)calculateHeight
{
    CGFloat width = _descriptionLabel.frame.size.width;
    NSAttributedString *attributedText = _descriptionLabel.attributedText;
    CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX} options: NSStringDrawingUsesLineFragmentOrigin context:nil];

    return rect.size.height + _descriptionHeadingLabel.frame.size.height + _descriptionHeadingLabelTopConstraint.constant + 3;
}

그리고 내 테이블 뷰 위임에서 :

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
    if (indexPath.row == 0) {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"descriptionCell"];
        DescriptionCell *descriptionCell = (DescriptionCell *)cell;
        NSString *text = [_event objectForKey:@"description"];
        descriptionCell.descriptionLabel.text = text;

        return [descriptionCell calculateHeight];
    }

    return 44.0f;
}

if 문을 조금 더 똑똑하게 변경하고 실제로 일종의 데이터 소스에서 셀 식별자를 얻을 수 있습니다. 필자의 경우 특정 순서로 고정 된 양이 있으므로 셀이 하드 코딩됩니다.


boundingRectWithSizeios 9.2에서 현재 문제는 ios <9.2와 다른 결과입니다. 이것을 만드는 다른 가장 좋은 방법을 찾거나 알고 있습니다.
jose920405
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.