В 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:...
функцию, она запрашивает массив атрибутов так же, как и 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 мне нужно было, чтобы логика возвращала правильную высоту для метода tableview: heightForRowAtIndexPath, но sizeWithAttributes всегда возвращает одну и ту же высоту независимо от длины строки, потому что не знает, что она будет помещена в ячейку таблицы фиксированной ширины. , Я нашел, что это прекрасно работает для меня и вычисляет правильную высоту, принимая во внимание ширину ячейки таблицы! Это основано на ответе г-на Т. выше.
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 'AdjustSize' или 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
NB: 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
вот правильный способ получить размер a 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]);
}
Вот эквивалент monotouch, если кому-то это нужно:
/// <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.
Моя ячейка похожа на ячейку описания при просмотре приложения в магазине приложений.
Сначала в раскадровке установите свой ярлык на «attributeText», установите количество строк равным 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;
}
И в моем представлении 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, чтобы он стал немного «умнее» и фактически получил идентификатор ячейки из какого-либо источника данных. В моем случае ячейки будут жестко закодированы, поскольку их будет определенное количество в определенном порядке.
boundingRectWithSize
в ios 9.2 присутствуют проблемы, отличающиеся результатами от ios <9.2. Вы нашли или знаете любой другой лучший способ сделать это.
NSString
иUILabel
(не ВСЕГДА, но часто так), чтобы предотвратить дублирование кода и т. д., вы также можете заменить[UIFont systemFontOfSize:17.0f]
наlabel.font
- помогает обслуживание кода, ссылаясь на существующие данные, а не вводя их несколько раз, или ссылаясь на константы по всей место и т. д.