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
작업을 할 때 NSString와 UILabel(경우에, 항상은 아니지만 종종 너무) 등 중복 코드 / 방지하기 위해, 당신은 또한 대체 할 수있는 [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.