Replacement for deprecated sizeWithFont: in iOS 7?

后端 未结 20 930
难免孤独
难免孤独 2020-11-22 08:49

In iOS 7, sizeWithFont: is now deprecated. How do I now pass in the UIFont object into the replacement method sizeWithAttributes:?

相关标签:
20条回答
  • 2020-11-22 08:58
    - (CGSize) sizeWithMyFont:(UIFont *)fontToUse
    {
        if ([self respondsToSelector:@selector(sizeWithAttributes:)])
        {
            NSDictionary* attribs = @{NSFontAttributeName:fontToUse};
            return ([self sizeWithAttributes:attribs]);
        }
        return ([self sizeWithFont:fontToUse]);
    }
    
    0 讨论(0)
  • 2020-11-22 09:01

    As you can see sizeWithFont at Apple Developer site it is deprecated so we need to use 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]}];
    }
    
    0 讨论(0)
  • 2020-11-22 09:02

    Create a function that takes a UILabel instance. and returns 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;
    
    0 讨论(0)
  • 2020-11-22 09:06

    I believe the function was deprecated because that series of NSString+UIKit functions (sizewithFont:..., etc) were based on the UIStringDrawing library, which wasn't thread safe. If you tried to run them not on the main thread (like any other UIKit functionality), you'll get unpredictable behaviors. In particular, if you ran the function on multiple threads simultaneously, it'll probably crash your app. This is why in iOS 6, they introduced a the boundingRectWithSize:... method for NSAttributedString. This was built on top of the NSStringDrawing libraries and is thread safe.

    If you look at the new NSString boundingRectWithSize:... function, it asks for an attributes array in the same manner as a NSAttributeString. If I had to guess, this new NSString function in iOS 7 is merely a wrapper for the NSAttributeString function from iOS 6.

    On that note, if you were only supporting iOS 6 and iOS 7, then I would definitely change all of your NSString sizeWithFont:... to the NSAttributeString boundingRectWithSize. It'll save you a lot of headache if you happen to have a weird multi-threading corner case! Here's how I converted NSString sizeWithFont:constrainedToSize::

    What used to be:

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

    Can be replaced with:

    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;
    

    Please note the documentation mentions:

    In iOS 7 and later, this method returns fractional sizes (in the size component of the returned CGRect); to use a returned size to size views, you must use raise its value to the nearest higher integer using the ceil function.

    So to pull out the calculated height or width to be used for sizing views, I would use:

    CGFloat height = ceilf(size.height);
    CGFloat width  = ceilf(size.width);
    
    0 讨论(0)
  • 2020-11-22 09:06

    As the @Ayush answer:

    As you can see sizeWithFont at Apple Developer site it is deprecated so we need to use sizeWithAttributes.

    Well, supposing that in 2019+ you are probably using Swift and String instead of Objective-c and NSString, here's the correct way do get the size of a String with predefined font:

    let stringSize = NSString(string: label.text!).size(withAttributes: [.font : UIFont(name: "OpenSans-Regular", size: 15)!])
    
    0 讨论(0)
  • 2020-11-22 09:06

    None of this worked for me in ios 7. Here is what I ended up doing. I put this in my custom cell class and call the method in my heightForCellAtIndexPath method.

    My cell looks similar to the description cell when viewing an app in the app store.

    First in the storyboard, set your label to 'attributedText', set the number of lines to 0 (which will resize the label automatically (ios 6+ only)) and set it to word wrap.

    Then i just add up all the heights of the content of the cell in my custom Cell Class. In my case I have a Label at the top that always says "Description" (_descriptionHeadingLabel), a smaller label that is variable in size that contains the actual description (_descriptionLabel) a constraint from the top of the cell to the heading (_descriptionHeadingLabelTopConstraint). I also added 3 to space out the bottom a little bit (about the same amount apple places on the subtitle type cell.)

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

    And in my Table View delegate:

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

    You can change the if statement to be a little 'smarter' and actually get the cell identifier from some sort of data source. In my case the cells are going to be hard coded since there will be fixed amount of them in a specific order.

    0 讨论(0)
提交回复
热议问题