簡體   English   中英

替換已棄用的 sizeWithFont: 在 iOS 7 中?

[英]Replacement for deprecated sizeWithFont: in iOS 7?

在 iOS 7 中, sizeWithFont:現已棄用。 我現在如何將 UIFont 對象傳遞到替換方法sizeWithAttributes:

使用sizeWithAttributes:代替,它現在需要一個NSDictionary UITextAttributeFont帶有鍵UITextAttributeFont和您的字體對象的對,如下所示:

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;

我相信該函數已被棄用,因為該系列NSString+UIKit函數( sizewithFont:...等)基於UIStringDrawing庫,該庫不是線程安全的。 如果您嘗試不在主線程上運行它們(像任何其他UIKit功能一樣),您將獲得不可預測的行為。 特別是,如果您同時在多個線程上運行該函數,它可能會使您的應用程序崩潰。 這就是為什么在 iOS 6 中,他們為NSAttributedString引入了boundingRectWithSize:...方法。 這是建立在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);

正如您在 Apple 開發者網站上看到的sizeWithFont它已被棄用,因此我們需要使用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]}];
}

我創建了一個類別來處理這個問題,這里是:

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

這樣您只需使用sizeWithMyFont:查找/替換sizeWithFont:就可以了。

在 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

使用動態高度的多行標簽可能需要額外的信息來正確設置大小。 您可以將 sizeWithAttributes 與 UIFont 和 NSParagraphStyle 一起使用來指定字體和換行模式。

您將定義段落樣式並使用這樣的 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

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

創建一個接受 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;

替代解決方案-

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

建立在@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;
}

我只使用結果幀的大小。

您仍然可以使用sizeWithFont 但是,在 iOS >= 7.0 方法中,如果字符串包含前導和尾隨空格或結束行\\n會導致崩潰。

使用前修剪文本

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

這也可能適用於sizeWithAttributes[label sizeToFit]

此外,每當您將nsstringdrawingtextstorage message sent to deallocated instance iOS 7.0 設備中的已nsstringdrawingtextstorage message sent to deallocated instance ,它都會處理此問題。

更好地使用自動尺寸(Swift):

  tableView.estimatedRowHeight = 68.0
  tableView.rowHeight = UITableViewAutomaticDimension

注意: 1. UITableViewCell 原型應該正確設計(例如不要忘記設置 UILabel.numberOfLines = 0 等) 2. 刪除 HeightForRowAtIndexPath 方法

在此處輸入圖片說明

視頻: https : //youtu.be/Sz3XfCsSb6k

boundingRectWithSize:options:attributes:context:

Xamarin 中接受的答案是(使用 sizeWithAttributes 和 UITextAttributeFont):

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

正如@Ayush 的回答:

正如您在 Apple 開發者網站上看到的sizeWithFont它已被棄用,因此我們需要使用sizeWithAttributes

好吧,假設在 2019 年以后,您可能正在使用SwiftString而不是 Objective-c 和NSString ,以下是使用預定義字體獲取String大小的正確方法:

let stringSize = NSString(string: label.text!).size(withAttributes: [.font : UIFont(name: "OpenSans-Regular", size: 15)!])
- (CGSize) sizeWithMyFont:(UIFont *)fontToUse
{
    if ([self respondsToSelector:@selector(sizeWithAttributes:)])
    {
        NSDictionary* attribs = @{NSFontAttributeName:fontToUse};
        return ([self sizeWithAttributes:attribs]);
    }
    return ([self sizeWithFont:fontToUse]);
}

如果有人需要,這是單點觸控等效項:

/// <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);
}
CGSize maximumLabelSize = CGSizeMake(label.frame.size.width, FLT_MAX);
CGSize expectedLabelSize = [label sizeThatFits:maximumLabelSize];
float heightUse = expectedLabelSize.height;

試試這個語法:

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

在 ios 7 中這些都不適合我。這就是我最終要做的。 我把它放在我的自定義單元類中,並在我的 heightForCellAtIndexPath 方法中調用該方法。

在應用商店中查看應用時,我的單元格看起來與描述單元格相似。

首先在情節提要中,將標簽設置為“attributedText”,將行數設置為 0(這將自動調整標簽大小(僅適用於 ios 6+))並將其設置為自動換行。

然后我只是在我的自定義單元格類中添加單元格內容的所有高度。 在我的情況下,我在頂部有一個標簽,總是顯示“描述”(_descriptionHeadingLabel),一個較小的標簽,其大小可變,包含實際描述(_descriptionLabel)從單元格頂部到標題的約束(_descriptionHeadingLabelTopConstraint) . 我還添加了 3 以將底部隔開一點(大約與 Apple 在字幕類型單元格上放置的數量相同。)

- (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 語句更改為“更智能”一點,並實際從某種數據源中獲取單元格標識符。 在我的情況下,單元格將被硬編碼,因為它們將以特定順序固定數量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM