boundingRectWithSize untuk NSAttributedString mengembalikan ukuran yang salah


151

Saya mencoba untuk mendapatkan kotak untuk sebuah string yang dikaitkan, tetapi panggilan boundingRectWithSize tidak menghormati ukuran yang saya lewati dan mengembalikan kotak dengan tinggi baris tunggal sebagai lawan dari tinggi besar (itu adalah string panjang). Saya telah bereksperimen dengan mengirimkan nilai yang sangat besar untuk ketinggian dan juga 0 seperti pada kode di bawah ini, tetapi rect yang dikembalikan selalu sama.

CGRect paragraphRect = [attributedText boundingRectWithSize:CGSizeMake(300,0.0)
  options:NSStringDrawingUsesDeviceMetrics
  context:nil];

Apakah ini rusak, atau apakah saya perlu melakukan sesuatu yang lain untuk mengembalikannya dalam bentuk teks?


5
Apakah Anda memiliki gaya paragraf dengan truncating / kliping lineBreakMode?
danyowdee

1
jika Anda membaca ini karena UILabel mengukur / membungkus ke lebar yang tidak benar, lihat stackoverflow.com/questions/46200027/… . khususnya, mengatur NSAllowsDefaultLineBreakStrategy menjadi false pada saat peluncuran aplikasi.
eric

Jawaban:


312

Sepertinya Anda tidak memberikan opsi yang benar. Untuk label pembungkus, berikan setidaknya:

CGRect paragraphRect =
  [attributedText boundingRectWithSize:CGSizeMake(300.f, CGFLOAT_MAX)
  options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
  context:nil];

Catatan: jika lebar teks asli di bawah 300.f jika tidak akan ada pembungkus baris, jadi pastikan ukuran terikat sudah benar, jika tidak Anda akan tetap mendapatkan hasil yang salah.


25
Semua orang perlu melihat jawaban ini, karena itu berfungsi. Mungkin dokumentasi yang lebih jelas diperlukan untuk metode ini dan menghubungkan string secara umum; tidak jelas di mana Anda perlu melihat.
macserv

31
Perhatian! Itu tidak selalu berhasil! Terkadang lebar yang dikembalikan lebih besar dari lebar parameter ukuran. Dokumentasi metode Bahkan Apel menyatakan: "Batasan yang Anda tentukan dalam parameter ukuran adalah panduan bagi penyaji untuk cara mengukur string. Namun, persegi panjang pembatas aktual yang dikembalikan oleh metode ini bisa lebih besar dari kendala jika diperlukan ruang tambahan untuk render seluruh string. "
Klaas

75
API untuk NSAttributedString dan boundingRectWithSize benar-benar mengejutkan.
malhal

27
Gotcha lain adalah bahwa tinggi (dan mungkin lebarnya) yang dikembalikan dalam paragrafRect hampir selalu merupakan nilai fraksional. Jadi mungkin keluar mengatakan 141,3 sebagai ketinggian. Anda perlu menggunakan hasil dari ceilf(paragraphRect.size.height)sehingga itu berhasil. Saya lupa ini sepanjang waktu dan bertanya-tanya mengapa label saya masih terpotong.
jamone

39
Saya selalu membungkus boundingRectWithSize:perhitungan saya dalam CGRectIntegral () yang akan CGRectIntegral rounds the rectangle’s origin downward and its size upward to the nearest whole integers, dalam hal ini mengumpulkan tinggi dan lebar untuk memastikan tidak ada kliping terjadi jika tinggi atau lebar nilai fraksional.
runmad

47

Untuk beberapa alasan, boundingRectWithSize selalu mengembalikan ukuran yang salah. Saya menemukan solusi. Ada metode untuk UItextView -sizeThatFits yang mengembalikan ukuran yang tepat untuk set teks. Jadi alih-alih menggunakan boundingRectWithSize, buat UITextView, dengan bingkai acak, dan panggil sizeThatFits dengan lebar masing-masing dan tinggi CGFLOAT_MAX. Ini mengembalikan ukuran yang akan memiliki ketinggian yang tepat.

   UITextView *view=[[UITextView alloc] initWithFrame:CGRectMake(0, 0, width, 10)];   
   view.text=text;
   CGSize size=[view sizeThatFits:CGSizeMake(width, CGFLOAT_MAX)];
   height=size.height; 

Jika Anda menghitung ukuran dalam loop sementara, jangan lupa untuk menambahkannya dalam kumpulan autorelease, karena akan ada n jumlah UITextView yang dibuat, memori run time dari aplikasi akan meningkat jika kita tidak menggunakan autoreleasepool.


1
Ini bekerja. Cara lain yang saya coba saya tidak pernah bisa mulai bekerja. Saya pikir masalah saya berasal dari kompleksitas string yang dikaitkan saya ditugaskan. Itu berasal dari file RTF dan menggunakan berbagai font, spasi baris, bahkan bayangan, dan meskipun menggunakan UsesLineFragmentOrigin dan UsesFontLeading, saya tidak pernah bisa mendapatkan hasil yang cukup tinggi, dan masalahnya adalah semakin lama semakin lama string yang dikaitkan. Dugaan saya adalah bahwa untuk string yang relatif sederhana metode boundingRectWithSize dapat berfungsi. Mereka benar-benar membutuhkan metode yang lebih baik untuk bekerja dengan ini, imo.
John Bushnell

tidakkah Anda pikir itu berlebihan untuk menciptakan UITextViewwaktu sebanyak heightForRowAtIndexPathmetode dipanggil? butuh waktu
János

Saya setuju dengan Anda @ János, tetapi ini adalah satu-satunya solusi yang bekerja untuk saya.
Shooan

btw saya meminta solusi yang tepat: stackoverflow.com/questions/32495744/...
János

ini adalah satu-satunya solusi yang berfungsi. Masalah ini telah 9 tahun dan Apple tampaknya tidak ingin menyelesaikan ini atau insinyur mereka lemah untuk mencari solusi untuk ini. Kami berbicara di sini tentang iOS 11, masih membawa bug yang sama.
Bebek

31

Ed McManus tentu saja telah memberikan kunci agar ini berhasil. Saya menemukan sebuah kasus yang tidak berfungsi

UIFont *font = ...
UIColor *color = ...
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                                     font, NSFontAttributeName,
                                     color, NSForegroundColorAttributeName,
                                     nil];

NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString: someString attributes:attributesDictionary];

[string appendAttributedString: [[NSAttributedString alloc] initWithString: anotherString];

CGRect rect = [string boundingRectWithSize:constraint options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) context:nil];

rect tidak akan memiliki tinggi yang benar. Perhatikan bahwa anotherString (yang ditambahkan ke string ) diinisialisasi tanpa kamus atribut. Ini adalah penginisialisasi yang sah untuk anotherString tetapi boundingRectWithSize: tidak memberikan ukuran yang akurat dalam kasus ini.


33
Terima kasih! Ternyata SETIAP bagian dari NSAttributedString harus memiliki set kamus dengan setidaknya NSFontAttributeName dan set NSForegroundColorAttributeName, jika Anda ingin boundRectWithSize untuk benar-benar berfungsi! Saya tidak melihat itu didokumentasikan di mana pun.
Ben Wheeler

3
Perhatikan bahwa juga muncul bahwa NSAttributedStrings berbeda yang digabungkan untuk membuat satu tunggal semua harus menggunakan kamus SAMA (dan dengan demikian font yang sama) agar boundingRectWithSize berfungsi dengan benar!
Ben Wheeler

1
Solusi ini sangat mirip dengan yang saya gunakan untuk kategori UILabel saya untuk "shrink to fit". Kunci bagi saya untuk mendapatkan ini berfungsi adalah membuat persegi panjang pembatas dengan tinggi FLT_MAX. Tanpa itu, saya sepertinya akan mendapatkan persegi panjang hanya untuk satu baris.
dre1138

+1 semua bulat. Ini benar-benar membuat saya, jadi terima kasih sudah bekerja kawan.
Wex

Saya punya masalah ini. Saya menggunakan spasi dan baris baru NSMutableAttributedStringtanpa atribut dan saya mendapatkan ukuran yang salah.
vbezhenar

28

Keputusan akhir saya setelah penyelidikan panjang:
- boundingRectWithSizefungsi mengembalikan ukuran yang benar hanya untuk urutan karakter tanpa gangguan! Dalam hal string berisi spasi atau sesuatu yang lain (disebut oleh Apple "Some of the glyphs") - tidak mungkin untuk mendapatkan ukuran aktual aktual yang diperlukan untuk menampilkan teks!
Saya telah mengganti spasi di string saya dengan surat dan segera mendapatkan hasil yang benar.

Apple mengatakan di sini: https://developer.apple.com/documentation/foundation/nsstring/1524729-boundingrectwithsize

"Metode ini mengembalikan batas sebenarnya dari mesin terbang dalam string. Beberapa mesin terbang (spasi, misalnya) diizinkan untuk tumpang tindih batasan tata letak yang ditentukan oleh ukuran yang dilewati, sehingga dalam beberapa kasus nilai lebar dari komponen ukuran dari yang dikembalikan CGRect dapat melebihi nilai lebar dari parameter ukuran. "

Jadi perlu untuk menemukan beberapa cara lain untuk menghitung ...


Setelah solusi proses penyelidikan yang lama akhirnya ditemukan !!! Saya tidak yakin ini akan bekerja dengan baik untuk semua kasus yang terkait UITextView, tetapi hal utama dan penting terdeteksi!

boundingRectWithSizefungsi serta CTFramesetterSuggestFrameSizeWithConstraints(dan banyak metode lain) akan menghitung ukuran dan porsi teks yang benar ketika persegi panjang yang benar digunakan. Sebagai contoh - UITextViewmemiliki textView.bounds.size.width- dan nilai ini bukan persegi panjang sebenarnya yang digunakan oleh sistem ketika teks menggambar UITextView.

Saya menemukan parameter yang sangat menarik dan melakukan perhitungan sederhana dalam kode:

CGFloat padding = textView.textContainer.lineFragmentPadding;  
CGFloat  actualPageWidth = textView.bounds.size.width - padding * 2;

Dan sulap - semua teks saya dihitung benar sekarang! Nikmati!


1
yeap, saya perhatikan itu juga, itu tidak menjaga batasan untuk lebar, selalu keluar lebih besar. Itu benar-benar tidak keren, mereka menolak metode kerja dan sekarang kita harus berurusan dengan omong kosong ini.
Boris Gafurov

1
Anda Tuan, adalah pahlawan baru saya! Ini membuatku gila. Saya sedang mengatur insets textContainers, jadi harus menggunakan textView.textContainer.size.width daripada textView.bounds.size.witdh.
GCBenson

Saya tidak bisa cukup memilih ini. Sangat aneh sehingga spasi tidak dipertimbangkan dalam perhitungan batas.
Chase Holland

1
Mengganti spasi dengan beberapa karakter dummy seperti "3" mengembalikan ketinggian yang tepat
Abuzar Amin

1
ini menyelamatkan karier saya dan hubungan saya dengan tim QA. Aku berhutang budi padamu !!
lucaslt89

14

Cepat versi empat

let string = "A great test string."
let font = UIFont.systemFont(ofSize: 14)
let attributes: [NSAttributedStringKey: Any] = [.font: font]
let attributedString = NSAttributedString(string: string, attributes: attributes)
let largestSize = CGSize(width: bounds.width, height: .greatestFiniteMagnitude)

//Option one (best option)
let framesetter = CTFramesetterCreateWithAttributedString(attributedString)
let textSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRange(), nil, largestSize, nil)

//Option two
let textSize = (string as NSString).boundingRect(with: largestSize, options: [.usesLineFragmentOrigin , .usesFontLeading], attributes: attributes, context: nil).size

//Option three
let textSize = attributedString.boundingRect(with: largestSize, options: [.usesLineFragmentOrigin , .usesFontLeading], context: nil).size

Mengukur teks dengan CTFramesetter berfungsi paling baik karena memberikan ukuran integer dan menangani emoji dan karakter unicode lainnya dengan baik.


10

Saya tidak beruntung dengan semua saran ini. Tali saya berisi poin-poin unicode dan saya curiga mereka menyebabkan kesedihan dalam perhitungan. Saya perhatikan UITextView menangani gambar dengan baik, jadi saya melihat itu untuk meningkatkan perhitungannya. Saya melakukan hal berikut, yang mungkin tidak seoptimal metode menggambar NSString, tetapi setidaknya itu akurat. Ini juga sedikit lebih optimal daripada menginisialisasi UITextView hanya untuk menelepon -sizeThatFits:.

NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(width, CGFLOAT_MAX)];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[layoutManager addTextContainer:textContainer];

NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:formattedString];
[textStorage addLayoutManager:layoutManager];

const CGFloat formattedStringHeight = ceilf([layoutManager usedRectForTextContainer:textContainer].size.height);

Ini mungkin bukan titik unicode, mungkin spasi di akhir string Anda. Lihat jawaban di atas: stackoverflow.com/a/25941139/337934 .
SamB

9

Jika Anda ingin mendapatkan kotak berlari dengan memotong ekornya, pertanyaan ini dapat membantu Anda.

CGFloat maxTitleWidth = 200;

NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
paragraph.lineBreakMode = NSLineBreakByTruncatingTail;

NSDictionary *attributes = @{NSFontAttributeName : self.textLabel.font,
                             NSParagraphStyleAttributeName: paragraph};

CGRect box = [self.textLabel.text
              boundingRectWithSize:CGSizeMake(maxTitleWidth, CGFLOAT_MAX)
              options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
              attributes:attributes context:nil];

9

Ternyata SETIAP bagian dari NSAttributedString harus memiliki set kamus dengan setidaknya NSFontAttributeName dan set NSForegroundColorAttributeName, jika Anda ingin boundRectWithSize untuk benar-benar berfungsi!

Saya tidak melihat itu didokumentasikan di mana pun.


Terima kasih, ini adalah solusi untuk saya, kecuali saya menemukan bahwa hanya NSFontAttributeName yang diperlukan, bukan NSForegroundColorAttributeName
Marmoy

7

@warrenm Maaf untuk mengatakan bahwa metode framesetter tidak bekerja untuk saya.

Saya mendapatkan ini. Fungsi ini dapat membantu kita menentukan ukuran bingkai yang dibutuhkan untuk rentang string NSAttributedString di iphone / Ipad SDK untuk Lebar yang diberikan:

Ini dapat digunakan untuk ketinggian dinamis Sel UITableView

- (CGSize)frameSizeForAttributedString:(NSAttributedString *)attributedString
{
    CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedString((CFAttributedStringRef)attributedString);
    CGFloat width = YOUR_FIXED_WIDTH;

    CFIndex offset = 0, length;
    CGFloat y = 0;
    do {
        length = CTTypesetterSuggestLineBreak(typesetter, offset, width);
        CTLineRef line = CTTypesetterCreateLine(typesetter, CFRangeMake(offset, length));

        CGFloat ascent, descent, leading;
        CTLineGetTypographicBounds(line, &ascent, &descent, &leading);

        CFRelease(line);

        offset += length;
        y += ascent + descent + leading;
    } while (offset < [attributedString length]);

    CFRelease(typesetter);

    return CGSizeMake(width, ceil(y));
}

Terima kasih kepada HADDAD ISSA >>> http://haddadissa.blogspot.in/2010/09/compute-needed-heigh-for-fixed-width-of.html


Tidak berfungsi untuk saya di perangkat apa pun (iPhone 4 dan 5). Baik pada perangkat dengan iOS7.1.2 dan 4s Simulator dengan iOS8.3 :(
sanjana

Ini perlu impor?
jose920405

@KaranAlangat yes#import <CoreText/CoreText.h>
jose920405

7

Saya telah menemukan bahwa solusi yang disukai tidak menangani jeda baris.

Saya menemukan bahwa pendekatan ini berfungsi dalam semua kasus:

UILabel* dummyLabel = [UILabel new];
[dummyLabel setFrame:CGRectMake(0, 0, desiredWidth, CGFLOAT_MAX)];
dummyLabel.numberOfLines = 0;
[dummyLabel setLineBreakMode:NSLineBreakByWordWrapping];
dummyLabel.attributedText = myString;
[dummyLabel sizeToFit];
CGSize requiredSize = dummyLabel.frame.size;

Dalam kasus saya, saya harus melakukan perhitungan pada utas latar belakang, dan penggunaan elemen UI tidak diperbolehkan
Lubbo

4

Saya memiliki masalah yang sama dengan tidak mendapatkan ukuran yang akurat menggunakan teknik ini dan saya telah mengubah pendekatan saya untuk membuatnya bekerja.

Saya memiliki string yang dikaitkan panjang yang saya coba untuk masuk ke tampilan gulir sehingga ditampilkan dengan benar tanpa terpotong. Apa yang saya lakukan untuk membuat teks bekerja dengan andal adalah tidak mengatur ketinggian sama sekali sebagai kendala dan sebaliknya membiarkan ukuran intrinsik untuk mengambil alih. Sekarang teks ditampilkan dengan benar tanpa terpotong dan saya tidak perlu menghitung tinggi.

Saya kira jika saya memang perlu mendapatkan ketinggian dengan andal saya akan membuat tampilan yang tersembunyi dan kendala ini dan mendapatkan ketinggian bingkai setelah kendala diterapkan.


2
Bisakah Anda menambahkan contoh kode untuk menunjukkan ini? Terima kasih.
Nathan Buggia

3

Saya sedikit terlambat dalam permainan - tetapi saya telah mencoba mencari cara yang berfungsi untuk menemukan kotak pembatas yang akan cocok dengan string yang dikaitkan untuk membuat cincin fokus seperti mengedit file di Finder. semua yang saya coba gagal ketika ada spasi di akhir string atau beberapa spasi di dalam string. boundingRectWithSizegagal total untuk ini juga CTFramesetterCreateWithAttributedString.

Menggunakan NSLayoutManagerkode berikut tampaknya melakukan trik dalam semua kasus yang saya temukan sejauh ini dan mengembalikan sebuah kotak yang sempurna mengikat string. Bonus: jika Anda memilih teks, ujung seleksi langsung ke batas rect yang dikembalikan. Kode di bawah ini menggunakan layoutManager dari a NSTextView.

NSLayoutManager* layout = [self layoutManager];
NSTextContainer* container = [self textContainer];

CGRect focusRingFrame = [layout boundingRectForGlyphRange:NSMakeRange(0, [[self textStorage] length]) inTextContainer:container];

2
textView.textContainerInset = UIEdgeInsetsZero;
NSString *string = @"Some string";
NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:12.0f], NSForegroundColorAttributeName:[UIColor blackColor]};
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:string attributes:attributes];
[textView setAttributedText:attributedString];
CGRect textViewFrame = [textView.attributedText boundingRectWithSize:CGSizeMake(CGRectGetWidth(self.view.frame)-8.0f, 9999.0f) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) context:nil];
NSLog(@"%f", ceilf(textViewFrame.size.height));

Bekerja pada semua font dengan sempurna!


1

Saya memiliki masalah yang sama, tetapi saya menyadari bahwa ketinggian dibatasi telah ditetapkan dengan benar. Jadi saya melakukan yang berikut:

-(CGSize)MaxHeighForTextInRow:(NSString *)RowText width:(float)UITextviewWidth {

    CGSize constrainedSize = CGSizeMake(UITextviewWidth, CGFLOAT_MAX);

    NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                                          [UIFont fontWithName:@"HelveticaNeue" size:11.0], NSFontAttributeName,
                                          nil];

    NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:RowText attributes:attributesDictionary];

    CGRect requiredHeight = [string boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin context:nil];

    if (requiredHeight.size.width > UITextviewWidth) {
        requiredHeight = CGRectMake(0, 0, UITextviewWidth, requiredHeight.size.height);
    }

    return requiredHeight.size;
}

1
    NSDictionary *stringAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                      [UIFont systemFontOfSize:18], NSFontAttributeName,
                                      [UIColor blackColor], NSForegroundColorAttributeName,
                                      nil];

    NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:myLabel.text attributes:stringAttributes];
    myLabel.attributedText = attributedString; //this is the key!

    CGSize maximumLabelSize = CGSizeMake (screenRect.size.width - 40, CGFLOAT_MAX);

    CGRect newRect = [myLabel.text boundingRectWithSize:maximumLabelSize
                                                       options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                                    attributes:stringAttributes context:nil];

    self.myLabelHeightConstraint.constant = ceilf(newRect.size.height);

Saya mencoba semuanya pada halaman ini dan masih memiliki satu case untuk UILabel yang tidak diformat dengan benar. Sebenarnya pengaturan attributedText pada label akhirnya memperbaiki masalahnya.


1

Satu hal yang saya perhatikan adalah bahwa persegi yang akan kembali (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)contextakan memiliki lebar lebih besar dari apa yang saya lewati. Ketika ini terjadi, tali saya akan terpotong. Saya mengatasinya seperti ini:

NSString *aLongString = ...
NSInteger width = //some width;            
UIFont *font = //your font;
CGRect rect = [aLongString boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
                                        options:(NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin)
                                     attributes:@{ NSFontAttributeName : font,
                                                   NSForegroundColorAttributeName : [UIColor whiteColor]}
                                        context:nil];

if(rect.size.width > width)
{
    return rect.size.height + font.lineHeight;
}
return rect.size.height;

Untuk lebih banyak konteks; Saya memiliki teks multi-baris dan saya mencoba untuk menemukan ketinggian yang tepat untuk menampilkannya. akan terpotong. Dari pengujian ketika boundingRectWithSize menggunakan lebar yang salah jumlah itu akan membuat ketinggian pendek adalah 1 baris. Jadi saya akan memeriksa apakah lebarnya lebih besar dan jika demikian tambahkan font's lineHeight untuk menyediakan ruang yang cukup untuk menghindari pemotongan.


Bagaimana ketinggian garis memengaruhi Lebar?
Roi Mulia

Tinggi saluran @RoiMulia tidak memengaruhi lebar. Saya memperbarui jawaban saya untuk memberikan lebih banyak konteks tentang bagaimana ini memperbaiki bug saya.
odyth

0
    NSAttributedString *attributedText =[[[NSAttributedString alloc]
                                          initWithString:joyMeComment.content
                                          attributes:@{ NSFontAttributeName: [UIFont systemFontOfSize:TextFont]}] autorelease];

    CGRect paragraphRect =
    [attributedText boundingRectWithSize:CGSizeMake(kWith, CGFLOAT_MAX)
                                 options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                 context:nil];
    contentSize = paragraphRect.size;

    contentSize.size.height+=10;
    label.frame=contentSize;

jika bingkai label tidak menambahkan 10 metode ini tidak akan pernah berhasil! Semoga ini bisa membantu Anda! keberuntungan goog.


0
Add Following methods in ur code for getting correct size of attribute string 
1.
    - (CGFloat)findHeightForText:(NSAttributedString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font
 {
    UITextView *textView = [[UITextView alloc] init];
    [textView setAttributedText:text];
    [textView setFont:font];
    CGSize size = [textView sizeThatFits:CGSizeMake(widthValue, FLT_MAX)];
    return size.height;

}

2. Call on heightForRowAtIndexPath method
     int h = [self findHeightForText:attrString havingWidth:yourScreenWidth andFont:urFont];

Dalam kasus saya, saya harus melakukan perhitungan pada utas latar belakang, dan penggunaan elemen UI tidak diperbolehkan
Lubbo

0

Saya ingin menambahkan pemikiran saya karena saya memiliki masalah yang sama persis.

Saya menggunakan UITextViewkarena memiliki perataan teks yang lebih bagus (membenarkan, yang pada saat itu tidak tersedia UILabel), tetapi untuk "mensimulasikan" non-interaktif-non-digulir UILabel, saya akan mematikan sepenuhnya menggulir, memantul, dan interaksi pengguna .

Tentu saja, masalahnya adalah teks itu dinamis, dan sementara lebar akan diperbaiki, tinggi harus dihitung ulang setiap kali saya menetapkan nilai teks baru.

boundingRectWithSizeSama sekali tidak bekerja dengan baik bagi saya, dari apa yang bisa saya lihat, UITextViewmenambahkan beberapa margin di atas yang boundingRectWithSizetidak akan masuk hitungan, oleh karena itu, ketinggian yang diperoleh boundingRectWithSizelebih kecil dari yang seharusnya.

Karena teks tidak diperbarui dengan cepat, itu hanya digunakan untuk beberapa informasi yang paling sering diperbarui setiap 2-3 detik, saya telah memutuskan pendekatan berikut:

/* This f is nested in a custom UIView-inherited class that is built using xib file */
-(void) setTextAndAutoSize:(NSString*)text inTextView:(UITextView*)tv
{
    CGFloat msgWidth = tv.frame.size.width; // get target's width

    // Make "test" UITextView to calculate correct size
    UITextView *temp = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, msgWidth, 300)]; // we set some height, really doesn't matter, just put some value like this one.
    // Set all font and text related parameters to be exact as the ones in targeted text view
    [temp setFont:tv.font];
    [temp setTextAlignment:tv.textAlignment];
    [temp setTextColor:tv.textColor];
    [temp setText:text];

    // Ask for size that fits :P
    CGSize tv_size = [temp sizeThatFits:CGSizeMake(msgWidth, 300)];

    // kill this "test" UITextView, it's purpose is over
    [temp release];
    temp = nil;

    // apply calculated size. if calcualted width differs, I choose to ignore it anyway and use only height because I want to have width absolutely fixed to designed value
    tv.frame = CGRectMake(tv.frame.origin.x, tv.frame.origin.y, msgWidth, tv_size.height );
}

* Kode di atas tidak langsung disalin dari sumber saya, saya harus menyesuaikan / menghapusnya dari banyak hal lain yang tidak diperlukan untuk artikel ini. Jangan bawa untuk copy-paste-dan-itu-akan-bekerja-kode.

Kerugian yang jelas adalah bahwa ia telah mengalokasikan dan melepaskan, untuk setiap panggilan.

Tetapi, keuntungannya adalah Anda menghindari tergantung pada kompatibilitas antara bagaimana boundingRectWithSize menggambar teks dan menghitung ukuran serta implementasi menggambar teks di dalamnya UITextView(atau UILabelyang juga dapat Anda gunakan hanya ganti UITextViewdengan UILabel). "Bug" apa pun yang dimiliki Apple dapat dihindari.

PS Tampaknya Anda tidak perlu "temp" ini UITextView dan bisa sizeThatFitslangsung bertanya dari target, tetapi itu tidak berhasil untuk saya. Meskipun logika akan mengatakan itu harus bekerja dan mengalokasikan / melepaskan sementara UITextViewtidak diperlukan, itu tidak. Tetapi solusi ini bekerja dengan sempurna untuk teks apa pun yang akan saya atur.


Dalam kasus saya, saya harus melakukan perhitungan pada utas latar belakang, dan penggunaan elemen UI tidak diperbolehkan
Lubbo

0

Ok jadi saya menghabiskan banyak waktu men-debug ini. Saya menemukan bahwa ketinggian teks maksimum yang ditentukan oleh boundingRectWithSizediizinkan untuk menampilkan teks oleh saya UITextViewlebih rendah dari ukuran bingkai.

Dalam kasus saya, frame paling banyak 140pt tetapi UITextView mentolerir teks paling banyak 131pt.

Saya harus mencari tahu secara manual dan hardcode ketinggian maksimum "nyata".

Ini solusinya:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    NSString *proposedText = [textView.text stringByReplacingCharactersInRange:range withString:text];
    NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:proposedText];
    CGRect boundingRect;
    CGFloat maxFontSize = 100;
    CGFloat minFontSize = 30;
    CGFloat fontSize = maxFontSize + 1;
    BOOL fit;
    NSLog(@"Trying text: \"%@\"", proposedText);
    do {
        fontSize -= 1;
        //XXX Seems like trailing whitespaces count for 0. find a workaround
        [attributedText addAttribute:NSFontAttributeName value:[textView.font fontWithSize:fontSize] range:NSMakeRange(0, attributedText.length)];
        CGFloat padding = textView.textContainer.lineFragmentPadding;
        CGSize boundingSize = CGSizeMake(textView.frame.size.width - padding * 2, CGFLOAT_MAX);
        boundingRect = [attributedText boundingRectWithSize:boundingSize options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading context:nil];
        NSLog(@"bounding rect for font %f is %@; (max is %f %f). Padding: %f", fontSize, NSStringFromCGRect(boundingRect), textView.frame.size.width, 148.0, padding);
        fit =  boundingRect.size.height <= 131;
    } while (!fit && fontSize > minFontSize);
    if (fit) {
        self.textView.font = [self.textView.font fontWithSize:fontSize];
        NSLog(@"Fit!");
    } else {
        NSLog(@"No fit");
    }
    return fit;
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.