326

iOS 7 では、sizeWithFont:非推奨になりました。UIFont オブジェクトを置換メソッドに渡すにはどうすればよいsizeWithAttributes:ですか?

4

20 に答える 20

527

sizeWithAttributes:代わりに使用してくださいNSDictionaryUITextAttributeFont次のように、キーとフォント オブジェクトのペアを渡します。

CGRect rawRect = {};
rawRect.size = [string sizeWithAttributes: @{
    NSFontAttributeName: [UIFont systemFontOfSize:17.0f],
}];

// Values are fractional -- you should take the ceil to get equivalent values
CGSize adjustedSize = CGRectIntegral(rawRect).size;
于 2013-09-19T14:47:10.620 に答える
173

その一連のNSString+UIKit関数 (など) は、スレッドセーフではないライブラリにsizewithFont:...基づいていたため、この関数は非推奨になったと思います。UIStringDrawing(他のUIKit機能と同様に) メイン スレッド以外でそれらを実行しようとすると、予期しない動作が発生します。特に、関数を複数のスレッドで同時に実行すると、アプリがクラッシュする可能性があります。これが、iOS 6 で のboundingRectWithSize:...メソッドを導入した理由ですNSAttributedString。これはライブラリの上に構築されており、NSStringDrawingスレッドセーフです。

新しいNSString boundingRectWithSize:...関数を見ると、 と同じ方法で属性配列を要求しますNSAttributeString。推測するに、iOS 7 のこの新しいNSString関数は、iOS 6 の関数の単なるラッパーですNSAttributeString

その点で、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);
于 2013-09-23T03:30:16.913 に答える
17

この問題を処理するためのカテゴリを作成しました。これは次のとおりです。

#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:です。

于 2013-09-25T12:45:30.150 に答える
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
于 2013-12-26T02:13:52.263 に答える
7

動的な高さを使用する複数行のラベルでは、サイズを適切に設定するために追加情報が必要になる場合があります。UIFont と NSParagraphStyle で sizeWithAttributes を使用して、フォントと改行モードの両方を指定できます。

Paragraph Style を定義し、次のように 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

于 2015-08-12T21:13:04.550 に答える
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));
于 2016-06-28T11:52:09.243 に答える
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;
于 2013-09-20T07:29:07.817 に答える
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;
}

結果のフレームのサイズを使用するだけです。

于 2015-10-05T21:45:19.210 に答える
2

引き続きご利用いただけますsizeWithFont。ただし、iOS >= 7.0 メソッドでは、文字列の先頭と末尾にスペースまたは終了行が含まれていると、クラッシュが発生します\n

テキストを使用する前にトリミングする

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

sizeWithAttributesそれはとにも当てはまるかもしれません[label sizeToFit]

nsstringdrawingtextstorage message sent to deallocated instanceまた、 iOS 7.0 デバイスを使用しているときはいつでも、これを処理します。

于 2013-12-10T09:55:14.697 に答える
1

Xamarin で受け入れられる答えは次のとおりです (sizeWithAttributes と UITextAttributeFont を使用):

        UIStringAttributes attributes = new UIStringAttributes
        { 
            Font = UIFont.SystemFontOfSize(17) 
        }; 
        var size = text.GetSizeUsingAttributes(attributes);
于 2014-06-25T04:13:25.960 に答える
1
boundingRectWithSize:options:attributes:context:
于 2014-04-02T02:52:37.967 に答える
0
CGSize maximumLabelSize = CGSizeMake(label.frame.size.width, FLT_MAX);
CGSize expectedLabelSize = [label sizeThatFits:maximumLabelSize];
float heightUse = expectedLabelSize.height;
于 2015-07-03T06:41:20.170 に答える
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);
}
于 2014-11-12T12:44:54.240 に答える
-1

これはどれもios 7ではうまくいきませんでした。これが私がやったことです。これをカスタム セル クラスに入れ、heightForCellAtIndexPath メソッドでメソッドを呼び出します。

アプリ ストアでアプリを表示すると、私のセルは説明セルに似ています。

最初にストーリーボードで、ラベルを「attributedText」に設定し、行数を 0 に設定して (ラベルのサイズが自動的に変更されます (ios 6+ のみ))、ワードラップに設定します。

次に、カスタム セル クラスのセルのコンテンツのすべての高さを合計します。私の場合、常に「説明」(_descriptionHeadingLabel) と表示されるラベルが上部にあり、実際の説明 (_descriptionLabel) を含むサイズが可変の小さなラベル、セルの上部から見出しまでの制約 (_descriptionHeadingLabelTopConstraint) があります。 . また、下部に少しスペースを空けるために 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;
}

そして私のTable Viewデリゲートでは:

- (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 ステートメントを少し「賢く」変更して、実際にある種のデータ ソースからセル識別子を取得することができます。私の場合、特定の順序で一定量のセルがあるため、セルはハードコーディングされます。

于 2013-12-20T05:40:33.220 に答える