sizeWithFont устарел. boundingRectWithSize возвращает неожиданное значение


82

В iOS7 sizeWithFontне рекомендуется, поэтому я использую boundingRectWithSize(который возвращает значение CGRect). Мой код:

 UIFont *fontText = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
                    // you can use your font.

 CGSize maximumLabelSize = CGSizeMake(310, 9999);

 CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                             options:NSStringDrawingUsesLineFragmentOrigin
                             attributes:@{NSFontAttributeName:fontText}
                             context:nil];

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

В textRectя получаю размер больше моего maximumLabelSize, другой размер, чем при использовании sizeWithFont. Как я могу решить эту проблему?


Я получаю эту проблему со всеми шрифтами, а не только с системным шрифтом или Helvetica.
Nirav Jain

ты хоть представляешь, как это сделать?
Nirav Jain

Может быть полезен конкретный пример названия шрифта, текста и несовпадающих размеров.
Eiko

Раньше я использовал CTFramesetterSuggestFrameSizeWithConstraints в iOS6 для вычисления высоты attributedString, которая всегда возвращает правильную высоту. В iOS7 и CTFramesetterSuggestFrameSizeWithConstraints, и boundingRectWithSize дают неправильный результат высоты. Бьюсь об заклад, это ошибка, появившаяся в iOS7, и, похоже, пока нет решения.
Арнольд Тан

Я тоже столкнулся с той же проблемой, лучше использовать tttattributedlabel
Шри ..

Ответы:


151

Как насчет создания нового ярлыка и использования sizeThatFit:(CGSize)size??

UILabel *gettingSizeLabel = [[UILabel alloc] init];
gettingSizeLabel.font = [UIFont fontWithName:@"YOUR FONT's NAME" size:16];
gettingSizeLabel.text = @"YOUR LABEL's TEXT";
gettingSizeLabel.numberOfLines = 0;
gettingSizeLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(310, CGFLOAT_MAX);

CGSize expectSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];

Изменить: этот верхний код не подходит для ios 7 и выше, поэтому используйте ниже:

CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                         options:NSStringDrawingUsesLineFragmentOrigin| NSStringDrawingUsesFontLeading
                         attributes:@{NSFontAttributeName:fontText}
                         context:nil];

этот метод не работает, когда я добавляю объекты HTML, такие как (<OL>, <LI>) в строку.
Nirav Jain

пожалуйста, проверьте мой ответ еще раз! Я пропустил свойство numberOfLines! извиняюсь!
Quang Hà

1
После нескольких часов поиска, экспериментов и тупиков, это единственное решение, которое работает для iOS7 и Xamarin / Monotouch
Майкл Родригес,

26
Создание метки для расчета размера шрифта? Это так расточительно!
Ossir 02

13
@ Оссир, у тебя есть идея получше?
Люда

36

Возможно, вам нужно добавить дополнительную опцию к методу, предложенному в этом ответе:

CGSize maximumLabelSize = CGSizeMake(310, CGFLOAT_MAX);
CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                                         options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                      attributes:@{NSFontAttributeName: fontText}
                                         context:nil];

3
Похоже, boundingRectWithSizeон сломан. Я тестировал iOS 7, 7.1.1, и он не дает правильных результатов.
RaffAl

Это не сработало для меня, однако использование boundingRectWithSize в NSAttributedString и добавление моего атрибута шрифта в строку вместо этого сработало.
Sheepdogsheep

12
Ребята, не забывайте про утверждение Apple: в iOS 7 и новее этот метод возвращает дробные размеры (в компоненте размера возвращаемого CGRect); чтобы использовать возвращаемый размер для размера представлений, вы должны увеличить его значение до ближайшего большего целого числа с помощью функции ceil.
SoftDesigner 01

2
ceil мне было недостаточно, но я обнаружил, что использование ceil, а также добавление 0,5 сделали трюк
dwery

15

Вот мой рабочий фрагмент кода:

NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:attributeDict];

NSString *headline  = [dict objectForKey:@"title"];  
UIFont *font        = [UIFont boldSystemFontOfSize:18];  
CGRect  rect        = [headline boundingRectWithSize:CGSizeMake(300, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];

CGFloat height      = roundf(rect.size.height +4)

Я добавил 4 пикселя к расчетной высоте, потому что без этих 4 пикселей не хватает одной строки.

Я использую этот фрагмент кода в tableView и добавляю «высоту» к массиву NSNumbers, и я получаю правильную высоту ячейки для textLabel по умолчанию.

Добавьте еще 4 пикселя, если вам нужно больше места под текстом в textLabel.

**** ОБНОВИТЬ ****

Я не согласен с «ошибкой ширины 40 пикселей», я кричу, что это 4 пикселя отсутствующей высоты, потому что 4 пикселя - это высота по умолчанию для промежутка между буквой и границей одной строки. Вы можете проверить это с помощью UILabel, для размера шрифта 16 вам понадобится высота UILabel 20.

Но если в вашей последней строке нет буквы «g» или чего-то еще, измерение может не соответствовать высоте в 4 пикселя.

Я перепроверил это небольшим методом, я получил точную высоту 20,40 или 60 для моей метки и правильную ширину менее 300 пикселей.

Для поддержки iOS6 и iOS7 вы можете использовать мой метод:

- (CGFloat)heightFromString:(NSString*)text withFont:(UIFont*)font constraintToWidth:(CGFloat)width
{
    CGRect rect;

    float iosVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
    if (iosVersion >= 7.0) {
        rect = [text boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];
    }
    else {
        CGSize size = [text sizeWithFont:font constrainedToSize:CGSizeMake(width, 1000) lineBreakMode:NSLineBreakByWordWrapping];
        rect = CGRectMake(0, 0, size.width, size.height);
    }
    NSLog(@"%@: W: %.f, H: %.f", self, rect.size.width, rect.size.height);
    return rect.size.height;
}

**** ОБНОВИТЬ ****

Благодаря вашим комментариям я обновил свою функцию следующим образом. Поскольку sizeWithFont устарел и вы получите предупреждение в XCode, я добавил диагностический-прагма-код, чтобы удалить предупреждение для этого конкретного вызова функции / блока кода.

- (CGFloat)heightFromStringWithFont:(UIFont*)font constraintToWidth:(CGFloat)width
{
    CGRect rect;

    if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
        rect = [self boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];
    }
    else {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
        CGSize size = [self sizeWithFont:font constrainedToSize:CGSizeMake(width, 1000) lineBreakMode:NSLineBreakByWordWrapping];
        rect = CGRectMake(0, 0, size.width, size.height);
#pragma GCC diagnostic pop
    }
    return ceil(rect.size.height);
}

В дополнение к теме 4px: в зависимости от того, какой шрифт и вес шрифта вы используете, расчет возвращает разные значения высоты. В моем случае: HelveticaNeue-Medium с размером шрифта 16,0 возвращает высоту строки 20,0 для одной строки, но 39,0 для двух строк, 78 пикселей для 4 строк -> 1 пиксель отсутствует для каждой строки - начиная со строки 2 - но вы хотите чтобы иметь размер шрифта + 4px для каждой строки, вы должны получить результат по высоте.
Помните об этом при написании кода!
У меня еще нет функции для этой "проблемы", но я обновлю этот пост, когда закончу.


1
Вероятно, вам следует использовать [text RespondsToSelector: @selector (boundingRectWithSize: options: attributes: context :)] вместо проверки значения с плавающей запятой.
Samah

1
Лучше использовать функцию ceil вместо + 4pt, посмотрите этот ответ stackoverflow.com/a/23563152/667483
surfrider

2

Если я правильно понимаю, вы используете boundingRectWithSize: просто как способ получить размер, который вы получили бы с sizeWithFont (что означает, что вы хотите напрямую CGSize, а не CGRect)?

Это похоже на то, что вы ищете:

Замена устаревшего sizeWithFont: в iOS 7?

Они используют sizeWithAttributes: для получения размера в качестве замены sizeWithFont.

Вы все еще получаете неправильный размер, используя что-то вроде этого:

UIFont *fontText = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
                    // you can use your font.

expectedLabelSize = [myString sizeWithAttributes:@{NSFontAttributeName:fontText}];

но как я могу использовать CGSize maximumLabelSize = CGSizeMake (310, 9999)? Мне нужна правильная высота и ширина.
Nirav Jain

1
Есть ли какие-либо атрибуты, которые говорят sizeWithAttributes: ограничивать его ширину / высоту?
Nirav Jain

Извините, но я не понимаю, в чем ваша проблема. Вы хотите установить размер метки в соответствии с размером шрифта, но не больше максимальной высоты, если я правильно понимаю. Вы говорите, что можете сделать это с помощью sizeWithFont, но теперь вам нужна альтернатива, поскольку этот метод устарел, верно? Вы должны иметь возможность подключить sizeWithAttribues: так же, как вы использовали sizeWithFont:. Как вы ограничивали размер метки при использовании sizeWithFont? Можете ли вы опубликовать код, который работал для вас, используя sizeWithFont?
vinaut

2
Он использовал sizeWithFont: constrainedToSize: lineBreakMode: и нет способа передать значение constrainedToSize в sizeWithAttributes.
ж.

2

Комментарий @ SoftDesigner сработал для меня

CGRect descriptionRect = [description boundingRectWithSize:CGSizeMake(width, 0)
                                                       options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                                    attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:12]}
                                                       context:nil];
result = ceil(descriptionRect.size.height);

1

для определения размера метки времени выполнения sizewithfont устарел для iOS 7.0, вместо этого вам нужно использовать -boundingRectWithSize: options: attributes: context: method

вы можете использовать его, как показано ниже

CGSize constraint = CGSizeMake(MAXIMUM_WIDHT, TEMP_HEIGHT);
NSRange range = NSMakeRange(0, [[self.message body] length]);

NSDictionary *attributes = [YOUR_LABEL.attributedText attributesAtIndex:0 effectiveRange:&range];
CGSize boundingBox = [myString boundingRectWithSize:constraint options:NSStringDrawingUsesFontLeading attributes:attributes context:nil].size;
int numberOfLine = ceil((boundingBox.width) / YOUR_LABEL.frame.size.width);
CGSize descSize = CGSizeMake(ceil(boundingBox.width), ceil(self.lblMessageDetail.frame.size.height*numberOfLine));

CGRect frame=YOUR_LABEL.frame;
frame.size.height=descSize.height;
YOUR_LABEL.frame=frame;

здесь вы должны указать ширину до максимальной длины, чтобы найти высоту или ширину.

попробуйте, это работает для меня.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.