метод 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
Sri ..

Відповіді:


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
Створення мітки для розрахунку розміру шрифту? Це так марнотратно!
Оссір,

13
@Ossir, ти маєш кращу ідею?
Люда

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

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)

Я додав 4px до розрахункової висоти, тому що без цих 4px не вистачає одного рядка.

Я використовую цей фрагмент коду в tableView і додаю "висоту" до масиву NSNumbers, і я отримую правильну висоту комірки за замовчуванням textLabel.

Додайте ще 4 пікселі, якщо потрібно більше місця під текстом у ярлику textLabel.

**** ОНОВИТИ ****

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

Але якщо у вашому останньому рядку немає "g" або що-небудь інше, вимірювання може бути відсутнє у 4px висоти.

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

Для підтримки 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, я додав код діагностики-pragma, щоб видалити попередження для цього конкретного виклику функції / блоку коду.

- (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 :)], а не перевіряти плаваюче значення.
Самах

1
Це краще використовувати CEIL функцію замість + 4PT, подивитися на цей відповідь stackoverflow.com/a/23563152/667483
серфінгіст

2

Якщо я правильно розумію, ви використовуєте boundingRectWithSize: так само, як спосіб отримати розмір, який ви отримаєте за допомогою sizeWithFont (тобто ви хочете безпосередньо CGSize, а не CGRect)?

Це схоже на те, що ви шукаєте:

Заміна застарілого розміруWithFont: в 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?
вине

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.