Kullanımdan kaldırılmış boyutun değiştirilmesiWithFont: iOS 7'de?


320

İOS 7'de sizeWithFont:artık kullanımdan kaldırıldı. Şimdi UIFont nesnesini değiştirme yöntemine sizeWithAttributes:nasıl geçiririm ?

Yanıtlar:


521

Kullan sizeWithAttributes:artık sürer yerine NSDictionary. Anahtarla UITextAttributeFontve yazı tipi nesnenizle çifti iletin :

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));

60
Bir ile çalışırken NSStringve UILabel(vaka değil her zaman çoğu zaman) vb çoğaltılamaz kodunu / önlemek için, ayrıca yerini alabilir [UIFont systemFontOfSize:17.0f]ile label.font- it birden çok kez yazarak size karşı var olan verilere başvurulması veya yerinden sabitlerini başvurarak kod bakım yardımcı olur yer, vb
toblerpwn

8
@toblerpwn etiketin olmaması mümkündür ve teorik bir etiket hesaplamaya çalışıyorsunuzdur.
botbot

5
Örneğin sabit genişliği 250 olan bir etiketle size .height değerini almak için bu örneği nasıl kullanırım? VEYA onun autolatyout cadı ile bir etiket genişliğinin bir yüzdesini alır ve ben landscapemode gidin.
Pedroinpeace

12
@Pedroinpeace Bunun boundingRectWithSize:options:attributes:context:yerine CGSizeMake(250.0f, CGFLOAT_MAX)çoğu durumda geçersiniz .
James Kuang

9
SizeWithAttributes: not edilecek başka bir şey% 100 eşdeğeri değil. sizeWithFont, boyutları tamsayı (piksel) değerlerine yuvarlamak için kullanılır. Ortaya çıkan yükseklik / genişlik için tavan kullanın ya da konumsal hesaplamalar için kullanırsanız bulanık artefaktlar (esp retina HW) alabilirsiniz.
Nick H247

172

Bu NSString+UIKitişlev ( sizewithFont:..., vb.) Bir dizi UIStringDrawingiş parçacığı güvenli olmayan kütüphane dayanıyordu çünkü işlevi kullanımdan kaldırıldığını düşünüyorum . Bunları ana iş parçacığında (diğer UIKitişlevler gibi ) çalıştırmaya çalıştıysanız , öngörülemeyen davranışlar elde edersiniz. Özellikle, işlevi aynı anda birden çok iş parçacığında çalıştırdıysanız, muhtemelen uygulamanızı kilitler. Bu yüzden iOS 6'da bir boundingRectWithSize:...yöntem sundular NSAttributedString. Bu NSStringDrawingkütüphanelerin üzerine inşa edilmiş ve iş parçacığı güvenlidir.

Yeni NSString boundingRectWithSize:...işleve bakarsanız, a ile aynı şekilde bir nitelik dizisi ister NSAttributeString. Tahmin etmek zorunda kalsaydım, NSStringiOS 7'deki bu yeni işlev yalnızca NSAttributeStringiOS 6'daki işlev için bir sarıcıdır .

Bu notta, yalnızca iOS 6 ve iOS 7'yi destekliyorsanız, kesinlikle tüm NSString sizeWithFont:...cihazınızı NSAttributeString boundingRectWithSize. Tuhaf bir çok iş parçacıklı köşe kasanız varsa, baş ağrısından tasarruf edersiniz! İşte nasıl dönüştürdüm NSString sizeWithFont:constrainedToSize::

Eskiden ne olurdu:

NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font 
               constrainedToSize:(CGSize){width, CGFLOAT_MAX}];

Şununla değiştirilebilir:

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;

Lütfen belgelere dikkat edin:

İOS 7 ve sonraki sürümlerde, bu yöntem kesirli boyutları döndürür (döndürülen öğenin boyut bileşeninde CGRect); görünümlere döndürülen bir boyutu kullanmak için, tavan işlevini kullanarak değerini en yakın daha yüksek tamsayıya yükseltmeniz gerekir.

Bu yüzden görünümleri boyutlandırmak için kullanılacak hesaplanan yüksekliği veya genişliği çıkarmak için şunu kullanırdım:

CGFloat height = ceilf(size.height);
CGFloat width  = ceilf(size.width);

boundingRectWithSize, iOS 6.0'da kullanımdan kaldırıldı.
Nirav

2
@Nirav Kullanımdan kaldırıldığına dair herhangi bir söz görmüyorum. Beni, kullanımdan kaldırıldığını söylediği yere yönlendirebilir misiniz? Teşekkürler! ( developer.apple.com/library/ios/documentation/uikit/reference/… )
Bay T

2
Belki de @Nirav , iOS 6'da NSString için kullanılamadığı anlamına geliyordu (cevapta dolaylı olarak bahsediliyor)?
newenglander

1
@VagueExplanation Sadece denedim ve boundingRectForSize hala NSAttributedString için kullanımdan kaldırılmadı. Ayrıca dokümantasyonda kullanımdan kaldırılmadığı da söylenemez.
Bay T

5
Ceilf () kullanarak bahsetmek için harika. Başka hiçbir yerde bundan bahsetmedi ve bedenim her zaman biraz fazla küçüktü. Teşekkürler!
Jonathan Brown

29

sizeWithFontApple Developer sitesinde görebileceğiniz gibi kullanımdan kaldırıldı, bu yüzden kullanmamız gerekiyor 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]}];
}

17
Bu durumda, [NSObject respondsToSelector:]burada olduğu gibi yöntemi kullanmak daha iyidir : stackoverflow.com/a/3863039/1226304
derpoliuk

16

Bu sorunu çözmek için bir kategori oluşturdum, işte burada:

#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]);
}

Yalnızca değiştirmek / bulmak zorunda Bu şekilde sizeWithFont:olan sizeWithMyFont:ve sen iyi gitmek.


1
ancak bu, sizeWithFont referansı için ios7 + 'da derleyici uyarısı veya sizeWithAttributes başvuru için <ios7'de bir derleme uyarısı / hatası üretecektir! Muhtemelen yanıt vermek yerine bir makro kullanmak en iyisidir. Ama artık Apple'a ioS6 SDK ile teslim edemediğiniz için ... muhtemelen değil!
Nick H247

#Pragma GCC teşhisini göz ardı etmek için bunu ekleyin "-Wdeprecated-declarations"
Ryan Heitner

10

İOS7'de tablo görünümü için doğru yüksekliği döndürmek için mantığa ihtiyacım vardı: heightForRowAtIndexPath yöntemi, ancak boyut genişliğinden bağımsız olarak sizeWithAttributes her zaman aynı yüksekliği döndürür, çünkü sabit genişlikli bir tablo hücresine yerleştirileceğini bilmez . Bunun benim için harika olduğunu gördüm ve tablo hücresinin genişliğini dikkate alarak doğru yüksekliği hesaplıyor! Bu, Bay T'nin yukarıdaki cevabına dayanmaktadır.

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

7

Dinamik yükseklik kullanan çok satırlı etiketler, boyutu uygun şekilde ayarlamak için ek bilgi gerektirebilir. UFont ve NSParagraphStyle ile sizeWithAttributes öğesini hem yazı tipini hem de satır sonu modunu belirtmek için kullanabilirsiniz.

Paragraf Stili'ni tanımlar ve aşağıdaki gibi bir NSDictionary kullanırsınız:

// 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];

Yüksekliği arıyorsanız CGSize 'adjustSize' veya CGRect'i rect.size.height özelliği olarak kullanabilirsiniz.

NSParagraphStyle hakkında daha fazla bilgi için: https://developer.apple.com/library/mac/documentation/cocoa/reference/applicationkit/classes/NSParagraphStyle_Class/Reference/Reference.html


1
AdjustSize'dan hemen sonra bir sözdizimi sorunu var gibi görünüyor.
Chris Prince

Sözdizimi sorununu yakaladığınız için teşekkürler, Chris
bitsand

6
// 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));

1
Bu bana saatler süren baş ağrılarını kurtardı, teşekkürler Kirit, CGRect bloğundan önce nitelikleri ve sözlükleri tanımlayan şey benim için yaptı ... okumak da çok daha kolaydı.
Azin Mehrnoosh

3

UILabel örneği alan bir işlev oluşturun. ve CGSize değerini döndürür

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;

Dinamik benim durumum Satır yüksekliği tamamen HeightForRow yöntemini kaldırdım ve UITableViewAutomaticDimension kullanılır. tableView.estimatedRowHeight = 68.0 tableView.rowHeight = UITableViewAutomaticDimension
Eugene Braginets

3

Alternatif çözüm

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];
}

1
Bu hem iOS6 hem de 7'de bir derleyici uyarısı üretecek ve her biri için oldukça farklı bir davranış olacak!
Nick H247

3

@Bitsand üzerine inşa etmek, bu NSString + Extras kategorime yeni eklediğim yeni bir yöntem:

- (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;
}

Sadece ortaya çıkan çerçevenin boyutunu kullanıyorum.


2

Yine de kullanabilirsiniz sizeWithFont. ancak, iOS> = 7.0'da dize önde gelen ve sondaki boşluklar veya bitiş çizgileri içeriyorsa çökmeye neden olur \n.

Metni kullanmadan önce kırpma

label.text = [label.text stringByTrimmingCharactersInSet:
             [NSCharacterSet whitespaceAndNewlineCharacterSet]];

Bu sizeWithAttributesve için de geçerli olabilir [label sizeToFit].

ayrıca, nsstringdrawingtextstorage message sent to deallocated instanceiOS 7.0 cihazınızda her zaman bununla ilgilenir.


2

Otomatik boyutları (Swift) daha iyi kullanın:

  tableView.estimatedRowHeight = 68.0
  tableView.rowHeight = UITableViewAutomaticDimension

Not: 1. UITableViewCell prototipi düzgün bir şekilde tasarlanmalıdır (örneğin UILabel.numberOfLines = 0 vb. Ayarlamayı unutmayın) 2. HeightForRowAtIndexPath yöntemini kaldırın

resim açıklamasını buraya girin

VİDEO: https://youtu.be/Sz3XfCsSb6k


Film şeridi prototip hücresinde tanımlanan statik hücre yüksekliğini alır
Kirit Vaghela

Bu iki satırı ekledi ve UILabel'ımın 0 satıra ayarlandığından emin olun. Reklamı olarak çalışmadı. Sadece bu iki kod satırıyla çalışmasını sağlamak için başka ne yaptınız?
Will

1
hm, ayrıca etiket kısıtlamalarınızı hücrenin üst ve alt kısmına
sabitlemelisiniz

1
Hayır, bu yeterli olmalı. Denetlemek üzere sabitlenmiş etiket için otomatik yerleşim kısıtlamalarınız var mı?
Eugene Braginets

1
boundingRectWithSize:options:attributes:context:

1

Xamarin'de kabul edilen cevap şu olacaktır (sizeWithAttributes ve UITextAttributeFont kullanın):

        UIStringAttributes attributes = new UIStringAttributes
        { 
            Font = UIFont.SystemFontOfSize(17) 
        }; 
        var size = text.GetSizeUsingAttributes(attributes);

1

@Ayush cevabı olarak:

sizeWithFontApple Developer sitesinde görebileceğiniz gibi kullanımdan kaldırıldı, bu yüzden kullanmamız gerekiyor sizeWithAttributes.

Eh, 2019+ içinde muhtemelen kullandığınız varsayarak Swift ve Stringyerine Objective-c ve NSStringburada boyutunu almak do doğru yoldur, Stringönceden tanımlanmış yazı ile:

let stringSize = NSString(string: label.text!).size(withAttributes: [.font : UIFont(name: "OpenSans-Regular", size: 15)!])

Yazı tipi boyutunu belirlemek için bunu nasıl kullanabilirsiniz?
Joseph Astrahan

@JosephAstrahan bu, yazı tipi boyutunu belirlemek için değil, belirli yazı tipine sahip bir dizenin boyutunu (CGSize) elde etmek içindir. Bir etiketin yazı tipi boyutunu almak istiyorsanız, label.font'u kolayca kullanabilirsiniz
Romulo BM

fikrinizi kullanarak, yazı tipi boyutunu daha fazla veya daha az ( stackoverflow.com/questions/61651614/… ), label.font, etiketlerle ilgili bazı karmaşık sorunlar nedeniyle, yazı tipim hakkında kesin bir yazı tipi okuyabileceğiniz biliniyor.
Joseph Astrahan

0
- (CGSize) sizeWithMyFont:(UIFont *)fontToUse
{
    if ([self respondsToSelector:@selector(sizeWithAttributes:)])
    {
        NSDictionary* attribs = @{NSFontAttributeName:fontToUse};
        return ([self sizeWithAttributes:attribs]);
    }
    return ([self sizeWithFont:fontToUse]);
}

0

İşte herhangi birinin ihtiyacı varsa monotok eşdeğeri:

/// <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;
}

Bu şekilde kullanılabilir:

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);
}

0
CGSize maximumLabelSize = CGSizeMake(label.frame.size.width, FLT_MAX);
CGSize expectedLabelSize = [label sizeThatFits:maximumLabelSize];
float heightUse = expectedLabelSize.height;

0

Bu sözdizimini deneyin:

NSAttributedString *attributedText =
    [[NSAttributedString alloc] initWithString:text 
                                    attributes:@{NSFontAttributeName: font}];

-1

Bunlardan hiçbiri benim için ios 7'de işe yaramadı. Bu benim özel hücre sınıfına koymak ve benim heightForCellAtIndexPath yönteminde yöntemi çağırır.

Uygulama mağazasında bir uygulamayı görüntülerken hücrem açıklama hücresine benziyor.

Film şeridinde ilk olarak, etiketinizi 'attributedText' olarak ayarlayın, satır sayısını 0 olarak ayarlayın (etiketi otomatik olarak yeniden boyutlandıracaktır (yalnızca ios 6+)) ve kelime kaydırmaya ayarlayın.

Sonra özel Hücre Sınıfımdaki hücrenin içeriğinin tüm yüksekliklerini topladım. Benim durumumda üstte her zaman "Açıklama" (_descriptionHeadingLabel), gerçek açıklama (_descriptionLabel) hücrenin üst kısmından başlık (_descriptionHeadingLabelTopConstraint) içeren bir boyutta değişken olan daha küçük bir etiket yazan bir Etiket var . Ben de biraz alttan biraz boşluk ekledim (altyazı tipi hücrede yaklaşık aynı miktarda elma yer.)

- (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;
}

Ve Tablo Görünümü temsilcimde:

- (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;
}

İf ifadesini biraz 'daha akıllı' olacak şekilde değiştirebilir ve hücre tanımlayıcısını bir tür veri kaynağından alabilirsiniz. Benim durumumda, hücreler belirli bir sırada sabit miktarda olacağından sabit kodlanacak.


boundingRectWithSizeios 9.2'de mevcut problemler, ios <9.2'den farklı sonuçlardır. Bunu yapmanın en iyi yolunu buldunuz veya biliyorsunuz.
jose920405
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.