No iOS 7, sizeWithFont:
agora está obsoleto. Como agora passo o objeto UIFont para o método de substituição sizeWithAttributes:
?
No iOS 7, sizeWithFont:
agora está obsoleto. Como agora passo o objeto UIFont para o método de substituição sizeWithAttributes:
?
Respostas:
Use em sizeWithAttributes:
vez disso, que agora leva um NSDictionary
. Passe o par com a chave UITextAttributeFont
e seu objeto de fonte assim:
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:
, passando CGSizeMake(250.0f, CGFLOAT_MAX)
na maioria dos casos.
Acredito que a função foi descontinuada porque essa série de NSString+UIKit
funções ( sizewithFont:...
, etc) se baseava na UIStringDrawing
biblioteca, o que não era seguro para threads. Se você tentou executá-los não no segmento principal (como qualquer outra UIKit
funcionalidade), obterá comportamentos imprevisíveis. Em particular, se você executou a função em vários segmentos simultaneamente, provavelmente o aplicativo falhará. É por isso que no iOS 6, eles introduziram o boundingRectWithSize:...
método para NSAttributedString
. Isso foi criado no topo das NSStringDrawing
bibliotecas e é seguro para threads.
Se você observar a nova NSString
boundingRectWithSize:...
função, ela solicitará uma matriz de atributos da mesma maneira que a NSAttributeString
. Se eu tivesse que adivinhar, essa nova NSString
função no iOS 7 é apenas um invólucro para a NSAttributeString
função do iOS 6.
Nessa nota, se você estivesse suportando apenas o iOS 6 e o iOS 7, eu definitivamente mudaria todo o seu NSString
sizeWithFont:...
para o NSAttributeString
boundingRectWithSize
. Isso poupará muita dor de cabeça se você tiver uma caixa de esquina multi-threading estranha! Aqui está como eu converti NSString
sizeWithFont:constrainedToSize:
:
O que costumava ser:
NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font
constrainedToSize:(CGSize){width, CGFLOAT_MAX}];
Pode ser substituído por:
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;
Observe a documentação mencionada:
No iOS 7 e posterior, esse método retorna tamanhos fracionários (no componente de tamanho dos retornados
CGRect
); Para usar um tamanho retornado para visualizações de tamanho, você deve aumentar seu valor para o número inteiro mais alto mais próximo usando a função ceil.
Portanto, para extrair a altura ou largura calculada a ser usada para as vistas de dimensionamento, eu usaria:
CGFloat height = ceilf(size.height);
CGFloat width = ceilf(size.width);
Como você pode ver sizeWithFont
no site da Apple Developer, ele está obsoleto, por isso precisamos usá-lo 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:]
método como aqui: stackoverflow.com/a/3863039/1226304
Eu criei uma categoria para lidar com esse problema, aqui está:
#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]);
}
Desta forma, você só tem que encontrar / substituir sizeWithFont:
com sizeWithMyFont:
e você está pronto para ir.
No iOS7, eu precisava da lógica para retornar a altura correta para o método tableview: heightForRowAtIndexPath, mas o sizeWithAttributes sempre retorna a mesma altura, independentemente do comprimento da string, porque ele não sabe que será colocado em uma célula da tabela de largura fixa . Achei isso ótimo para mim e calcula a altura correta, levando em consideração a largura da célula da tabela! Isso se baseia na resposta do Sr. T acima.
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
Etiquetas com várias linhas que usam altura dinâmica podem exigir informações adicionais para definir o tamanho corretamente. Você pode usar sizeWithAttributes com UIFont e NSParagraphStyle para especificar a fonte e o modo de quebra de linha.
Você definiria o estilo de parágrafo e usaria um NSDictionary como este:
// 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];
Você pode usar a propriedade CGSize 'ajustadoSize' ou CGRect como ret.size.height se estiver procurando a altura.
Mais informações sobre o NSParagraphStyle aqui: 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));
Crie uma função que utilize uma instância UILabel. e retorna 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
Solução alternativa
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];
}
Com base no @bitsand, este é um novo método que acabei de adicionar à minha categoria 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;
}
Eu apenas uso o tamanho do quadro resultante.
Você ainda pode usar sizeWithFont
. mas, no iOS> = 7.0, o método causa falha se a string contiver espaços à esquerda e à direita ou linhas finais \n
.
Aparar texto antes de usá-lo
label.text = [label.text stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
Isso também pode ser aplicado a sizeWithAttributes
e [label sizeToFit]
.
Além disso, sempre que você tiver um nsstringdrawingtextstorage message sent to deallocated instance
dispositivo iOS 7.0, ele lida com isso.
Melhor usar as dimensões automáticas (Swift):
tableView.estimatedRowHeight = 68.0
tableView.rowHeight = UITableViewAutomaticDimension
NB: 1. O protótipo UITableViewCell deve ser projetado corretamente (para a instância, não esqueça de definir UILabel.numberOfLines = 0 etc) 2. Remova o método HeightForRowAtIndexPath
VÍDEO: https://youtu.be/Sz3XfCsSb6k
A resposta aceita no Xamarin seria (use sizeWithAttributes e UITextAttributeFont):
UIStringAttributes attributes = new UIStringAttributes
{
Font = UIFont.SystemFontOfSize(17)
};
var size = text.GetSizeUsingAttributes(attributes);
Como resposta da @Ayush:
Como você pode ver
sizeWithFont
no site da Apple Developer, ele está obsoleto, por isso precisamos usá-losizeWithAttributes
.
Bem, supondo que em 2019+ você provavelmente esteja usando Swift e, em String
vez de Objective-c NSString
, e aqui está a maneira correta de obter o tamanho de a String
com fonte predefinida:
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]);
}
Aqui está o equivalente ao monotouch, se alguém precisar:
/// <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;
}
que pode ser usado assim:
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;
Experimente esta sintaxe:
NSAttributedString *attributedText =
[[NSAttributedString alloc] initWithString:text
attributes:@{NSFontAttributeName: font}];
Nada disso funcionou para mim no iOS 7. Aqui está o que eu acabei fazendo. Coloquei isso na minha classe de célula personalizada e chamo o método no meu método heightForCellAtIndexPath.
Meu celular é semelhante à célula de descrição ao visualizar um aplicativo na loja de aplicativos.
Primeiro no storyboard, defina seu rótulo como 'attributeText', defina o número de linhas como 0 (que redimensionará o rótulo automaticamente (apenas no iOS 6 ou superior)) e defina-o como quebra de linha.
Depois, adiciono todas as alturas do conteúdo da célula na minha Classe de célula personalizada. No meu caso, eu tenho um Label na parte superior que sempre diz "Description" (_descriptionHeadingLabel), um rótulo menor de tamanho variável que contém a descrição real (_descriptionLabel), uma restrição da parte superior da célula ao cabeçalho (_descriptionHeadingLabelTopConstraint) . Também adicionei 3 ao espaço um pouco mais abaixo (aproximadamente a mesma quantidade que a maçã coloca na célula do tipo de legenda).
- (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;
}
E no meu delegado 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;
}
Você pode alterar a instrução if para ser um pouco mais inteligente e obter o identificador da célula de algum tipo de fonte de dados. No meu caso, as células serão codificadas, uma vez que haverá uma quantidade fixa delas em uma ordem específica.
boundingRectWithSize
no ios 9.2 apresenta problemas, resultados diferentes são para ios <9.2. Você encontrou ou conhece outra maneira melhor de fazer isso.
NSString
e umUILabel
(não SEMPRE o caso, mas muitas vezes sim), para evitar código duplicado / etc, você também pode substituir[UIFont systemFontOfSize:17.0f]
porlabel.font
- ajuda na manutenção do código fazendo referência a dados existentes, digitando-o várias vezes ou fazendo referência a constantes em todo o local, etc