У iOS 7 sizeWithFont:
тепер застаріла. Як я тепер переходжу в об'єкт UIFont в метод заміни sizeWithAttributes:
?
У iOS 7 sizeWithFont:
тепер застаріла. Як я тепер переходжу в об'єкт UIFont в метод заміни sizeWithAttributes:
?
Відповіді:
Використовуйте sizeWithAttributes:
натомість, який зараз займає NSDictionary
. Введіть пару з ключем UITextAttributeFont
та об'єктом шрифту так:
CGSize size = [string sizeWithAttributes:
@{NSFontAttributeName: [UIFont systemFontOfSize:17.0f]}];
// Values are fractional -- you should take the ceilf to get equivalent values
CGSize adjustedSize = CGSizeMake(ceilf(size.width), ceilf(size.height));
boundingRectWithSize:options:attributes:context:
натомість, пропускаючи CGSizeMake(250.0f, CGFLOAT_MAX)
в більшості випадків.
Я вважаю, що функція була застарілою, оскільки серія NSString+UIKit
функцій ( sizewithFont:...
тощо) базувалася на UIStringDrawing
бібліотеці, яка не була безпечною для потоків. Якщо ви спробували запустити їх не на основній темі (як і будь-який інший UIKit
функціонал), ви отримаєте непередбачувані поведінки. Зокрема, якщо функцію запустити одночасно на декількох потоках, вона, ймовірно, завершить роботу вашого додатка. Ось чому в iOS 6 вони ввели boundingRectWithSize:...
метод для NSAttributedString
. Це було створено на вершині NSStringDrawing
бібліотек і є безпечним для потоків.
Якщо ви подивитеся на нову NSString
boundingRectWithSize:...
функцію, вона запитує масив атрибутів так само, як і a NSAttributeString
. Якби мені довелося здогадатися, ця нова NSString
функція в iOS 7 є лише обгорткою для NSAttributeString
функції від iOS 6.
На цій ноті, якби ви тільки підтримку 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);
Як ви можете бачити sizeWithFont
на сайті Apple Developer, він застарілий, тому нам потрібно користуватися 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]}];
}
[NSObject respondsToSelector:]
метод , як тут: stackoverflow.com/a/3863039/1226304
Я створив категорію для вирішення цієї проблеми, ось вона:
#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:
і ви добре йти.
У iOS7 мені була потрібна логіка, щоб повернути правильну висоту для перегляду таблиці: heightForRowAtIndexPath, але розмірWithAttributes завжди повертає ту саму висоту незалежно від довжини рядка, оскільки він не знає, що він буде розміщений у комірці таблиці фіксованої ширини . Я виявив, що це для мене чудово працює і обчислює правильну висоту, враховуючи ширину комірки таблиці! Це ґрунтується на відповіді пана Т. вище.
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 'customSize' або 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;
tableView.estimatedRowHeight = 68.0 tableView.rowHeight = UITableViewAutomaticDimension
Альтернативне рішення-
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, він займається цим.
Краще використовувати автоматичні розміри (Swift):
tableView.estimatedRowHeight = 68.0
tableView.rowHeight = UITableViewAutomaticDimension
Примітка: 1. Прототип UITableViewCell повинен бути належним чином розроблений (наприклад, не забудьте встановити UILabel.numberOfLines = 0 і т.д.) 2. Видаліть метод HeightForRowAtIndexPath
ВІДЕО: https://youtu.be/Sz3XfCsSb6k
Відповідь у Xamarin буде прийнята (використовуйте sizeWithAttributes та UITextAttributeFont):
UIStringAttributes attributes = new UIStringAttributes
{
Font = UIFont.SystemFontOfSize(17)
};
var size = text.GetSizeUsingAttributes(attributes);
Як відповідь @Ayush:
Як ви можете бачити
sizeWithFont
на сайті Apple Developer, він застарілий, тому нам потрібно користуватисяsizeWithAttributes
.
Ну, якщо припустити, що в 2019 році ви, ймовірно, використовуєте Swift, а String
не 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. Ось, що я закінчив робити. Я поміщую це у свій власний клас комірок і називаю метод в моєму висотіForCellAtIndexPath метод.
Під час перегляду програми в магазині додатків моя клітинка виглядає схожою на комірку для опису.
Спочатку в дошці розкадровки встановіть мітку на "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;
}
І в моєму представнику табличного перегляду:
- (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 на трохи розумніший і фактично отримати ідентифікатор комірки з якогось джерела даних. У моєму випадку комірки будуть жорстко закодовані, оскільки буде визначено їх кількість у певному порядку.
boundingRectWithSize
в ios 9.2 присутні проблеми, відрізняється від результатів до ios <9.2. Ви знайшли чи знаєте будь-який інший найкращий спосіб зробити це.
NSString
іUILabel
(не завжди, але це часто так), щоб запобігти дублюванню коду / тощо, ви також можете замінити[UIFont systemFontOfSize:17.0f]
наlabel.font
- допомагає технічному обслуговуванню коду шляхом посилання на наявні дані порівняно з тим, що ви вводите їх кілька разів або посилаєтесь на константи по всьому місце тощо