W iOS 7 sizeWithFont:
jest teraz przestarzały. Jak teraz przekazać obiekt UIFont do metody zamiany sizeWithAttributes:
?
W iOS 7 sizeWithFont:
jest teraz przestarzały. Jak teraz przekazać obiekt UIFont do metody zamiany sizeWithAttributes:
?
Odpowiedzi:
Użyj sizeWithAttributes:
zamiast tego, co teraz zajmuje NSDictionary
. Przekaż parę z kluczem UITextAttributeFont
i obiektem czcionki w następujący sposób:
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:
, przekazując CGSizeMake(250.0f, CGFLOAT_MAX)
w większości przypadków.
Myślę, że ta funkcja była przestarzała, ponieważ ta seria NSString+UIKit
funkcji ( sizewithFont:...
itp.) UIStringDrawing
Była oparta na bibliotece, co nie było bezpieczne dla wątków. Jeśli spróbujesz uruchomić je nie w głównym wątku (jak każda inna UIKit
funkcja), otrzymasz nieprzewidziane zachowania. W szczególności, jeśli uruchomiłeś funkcję na wielu wątkach jednocześnie, prawdopodobnie spowoduje to awarię aplikacji. Właśnie dlatego w iOS 6 wprowadzili boundingRectWithSize:...
metodę NSAttributedString
. Został on zbudowany na NSStringDrawing
bibliotekach i jest bezpieczny dla wątków.
Jeśli spojrzysz na nową NSString
boundingRectWithSize:...
funkcję, poprosi ona o tablicę atrybutów w taki sam sposób jak NSAttributeString
. Gdybym musiał zgadywać, ta nowa NSString
funkcja w iOS 7 jest jedynie opakowaniem NSAttributeString
funkcji z iOS 6.
W tej notatce, jeśli wspierasz tylko iOS 6 i iOS 7, zdecydowanie zmieniłbym wszystkie twoje NSString
sizeWithFont:...
na NSAttributeString
boundingRectWithSize
. Zaoszczędzi ci dużo bólu głowy, jeśli zdarzy ci się mieć dziwną, wielowątkową obudowę narożną! Oto jak przekonwertowałem NSString
sizeWithFont:constrainedToSize:
:
Co kiedyś:
NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font
constrainedToSize:(CGSize){width, CGFLOAT_MAX}];
Można zastąpić:
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;
Uwaga: w dokumentacji wspomniano:
W iOS 7 i nowszych ta metoda zwraca rozmiary ułamkowe (w składniku rozmiaru zwracanego
CGRect
); aby użyć zwróconego widoku rozmiar do rozmiaru, należy użyć podniesienia jego wartości do najbliższej wyższej liczby całkowitej za pomocą funkcji ceil.
Aby wyciągnąć obliczoną wysokość lub szerokość, która ma zostać użyta do zmiany rozmiaru widoków, użyłbym:
CGFloat height = ceilf(size.height);
CGFloat width = ceilf(size.width);
Jak widać sizeWithFont
na stronie Apple Developer, jest on przestarzały, więc musimy go użyć 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:]
metody takiej jak tutaj: stackoverflow.com/a/3863039/1226304
Utworzyłem kategorię, aby poradzić sobie z tym problemem, oto ona:
#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]);
}
W ten sposób można tylko trzeba znaleźć / zastąpić sizeWithFont:
z sizeWithMyFont:
i jesteś dobry, aby przejść.
W iOS7 potrzebowałem logiki, aby zwrócić poprawną wysokość dla widoku tabeli: heightForRowAtIndexPath, ale sizeWithAttributes zawsze zwraca tę samą wysokość niezależnie od długości łańcucha, ponieważ nie wie, że zostanie umieszczony w komórce tabeli o stałej szerokości . Uważam, że działa to dla mnie świetnie i oblicza prawidłową wysokość, biorąc pod uwagę szerokość komórki tabeli! Jest to oparte na powyższej odpowiedzi pana T.
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
Etykiety wieloliniowe wykorzystujące dynamiczną wysokość mogą wymagać dodatkowych informacji, aby prawidłowo ustawić rozmiar. Możesz użyć sizeWithAttributes z UIFont i NSParagraphStyle, aby określić zarówno czcionkę, jak i tryb podziału linii.
Zdefiniowałbyś styl akapitowy i używałeś NSDictionary w następujący sposób:
// 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];
Jeśli szukasz wysokości, możesz użyć CGSize 'AdjustSize' lub CGRect jako właściwości rect.size.height.
Więcej informacji na temat NSParagraphStyle tutaj: 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));
Utwórz funkcję, która pobiera instancję UILabel. i zwraca 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
Alternatywne rozwiązanie
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];
}
Opierając się na @bitsand, jest to nowa metoda, którą właśnie dodałem do mojej kategorii NSString + Dodatki:
- (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;
}
Po prostu używam rozmiaru wynikowej ramki.
Nadal możesz używać sizeWithFont
. ale w iOS> = 7.0 metoda powoduje zawieszanie się, jeśli ciąg znaków zawiera spacje początkowe i końcowe oraz linie końcowe \n
.
Przycinanie tekstu przed użyciem
label.text = [label.text stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
Dotyczy to również sizeWithAttributes
i [label sizeToFit]
.
również za każdym razem, gdy masz nsstringdrawingtextstorage message sent to deallocated instance
urządzenie z iOS 7.0, zajmuje się tym.
Lepsze wykorzystanie wymiarów automatycznych (Swift):
tableView.estimatedRowHeight = 68.0
tableView.rowHeight = UITableViewAutomaticDimension
Uwaga: 1. Prototyp UITableViewCell powinien być odpowiednio zaprojektowany (na przykład nie zapomnij ustawić UILabel.numberOfLines = 0 itd.) 2. Usuń metodę HeightForRowAtIndexPath
WIDEO: https://youtu.be/Sz3XfCsSb6k
Zaakceptowana odpowiedź w Xamarin będzie (użyj sizeWithAttributes i UITextAttributeFont):
UIStringAttributes attributes = new UIStringAttributes
{
Font = UIFont.SystemFontOfSize(17)
};
var size = text.GetSizeUsingAttributes(attributes);
Jako odpowiedź @Ayush:
Jak widać
sizeWithFont
na stronie Apple Developer, jest on przestarzały, więc musimy go użyćsizeWithAttributes
.
Załóżmy, że w 2019+ prawdopodobnie używasz Swift i String
zamiast Objective-c, a NSString
oto poprawny sposób uzyskania rozmiaru String
z predefiniowaną czcionką:
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]);
}
Oto odpowiednik monotouch, jeśli ktoś tego potrzebuje:
/// <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;
}
które mogą być użyte w ten sposób:
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;
Wypróbuj tę składnię:
NSAttributedString *attributedText =
[[NSAttributedString alloc] initWithString:text
attributes:@{NSFontAttributeName: font}];
W iOS 7 nic z tego nie działało. Oto, co ostatecznie zrobiłem. Umieszczam to w mojej niestandardowej klasie komórek i wywołuję metodę w metodzie heightForCellAtIndexPath.
Moja komórka wygląda podobnie do komórki opisu podczas przeglądania aplikacji w sklepie z aplikacjami.
Najpierw w serii ujęć ustaw etykietę na „atrybutowany tekst”, ustaw liczbę wierszy na 0 (która automatycznie zmieni rozmiar etykiety (tylko iOS 6+)) i ustaw zawijanie słów.
Następnie po prostu sumuję wszystkie wysokości zawartości komórki w mojej niestandardowej klasie komórek. W moim przypadku mam u góry etykietę, która zawsze mówi „Opis” (_descriptionHeadingLabel), mniejszą etykietę o zmiennej wielkości, która zawiera rzeczywisty opis (_descriptionLabel) ograniczenie od góry komórki do nagłówka (_descriptionHeadingLabelTopConstraint) . Dodałem również 3, aby nieco spuścić trochę na dole (mniej więcej tyle samo jabłek umieszcza w komórce typu napisów).
- (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;
}
I w moim widoku tabeli delegat:
- (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;
}
Możesz zmienić instrukcję if, aby była nieco „inteligentniejsza” i faktycznie pobierała identyfikator komórki z jakiegoś źródła danych. W moim przypadku komórki będą zakodowane na stałe, ponieważ będzie ich stała liczba w określonej kolejności.
boundingRectWithSize
w ios 9.2 obecne problemy, to wyniki inne niż ios <9.2. Znalazłeś lub znasz inny najlepszy sposób na zrobienie tego.
NSString
iUILabel
(nie zawsze tak jest, ale często tak), aby zapobiec powielony kod / etc, można również wymienić[UIFont systemFontOfSize:17.0f]
zlabel.font
- ułatwia utrzymanie kodu poprzez odniesienie istniejących danych w porównaniu z wami wpisanie go wielokrotnie lub odwołanie stałych całego miejsce itp.