ràng buộcRectWithSize cho NSAttributionString trả lại kích thước sai


151

Tôi đang cố gắng để chỉnh lưu cho một chuỗi được gán, nhưng lệnh gọi ràng buộcRectWithSize không tôn trọng kích thước tôi truyền vào và đang trả về một chỉnh lưu có chiều cao một dòng so với chiều cao lớn (đó là một chuỗi dài). Tôi đã thử nghiệm bằng cách chuyển một giá trị rất lớn cho chiều cao và 0 như trong mã bên dưới, nhưng chỉnh lưu trả về luôn giống nhau.

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

Cái này có bị hỏng không, hay tôi cần phải làm gì khác để nó trả lại một chỉnh lưu cho văn bản được bọc?


5
Bạn có tình cờ có một kiểu đoạn văn với cắt / cắt lineBreakMode?
danyowdee

1
nếu bạn đang đọc điều này bởi vì đo / gói UILabel theo chiều rộng không chính xác, hãy xem stackoverflow.com/questions/46200027/ . cụ thể, đặt NS ALLowsDefaultLineBreakStrargety thành false khi khởi chạy ứng dụng.
eric

Câu trả lời:


312

Có vẻ như bạn không cung cấp các tùy chọn chính xác. Đối với nhãn bao bì, cung cấp ít nhất:

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

Lưu ý: nếu chiều rộng văn bản gốc dưới 300.f sẽ không có đường bao quanh, vì vậy hãy đảm bảo kích thước ràng buộc là chính xác, nếu không bạn vẫn sẽ nhận được kết quả sai.


25
Mọi người cần nhìn vào câu trả lời này, bởi vì nó hoạt động. Có lẽ tài liệu rõ ràng hơn là cần thiết cho phương pháp này và các chuỗi quy định nói chung; Không rõ ràng nơi bạn cần tìm.
macserv

31
Chú ý! Nó không phải lúc nào cũng hoạt động! Đôi khi chiều rộng được trả về lớn hơn chiều rộng của tham số kích thước. Ngay cả tài liệu phương thức Táo cũng nêu: "Các ràng buộc bạn chỉ định trong tham số kích thước là một hướng dẫn cho trình kết xuất về cách định kích thước chuỗi. Tuy nhiên, hình chữ nhật giới hạn thực được trả về bởi phương thức này có thể lớn hơn các ràng buộc nếu cần thêm không gian để kết xuất toàn bộ chuỗi. "
Klaas

75
API cho NSAttributionString và ràng buộcRectWithSize hoàn toàn gây sốc.
malhal

27
Một vấn đề khác là chiều cao (và có lẽ là chiều rộng) được trả về trong đoạnRect gần như luôn luôn là một giá trị phân số. Vì vậy, nó có thể đi ra nói 141.3 là chiều cao. Bạn cần sử dụng kết quả từ ceilf(paragraphRect.size.height)đó để làm tròn lên. Tôi quên điều này mọi lúc và tự hỏi tại sao nhãn của tôi vẫn bị cắt.
Jamone

39
Tôi luôn bao bọc các boundingRectWithSize:tính toán của mình trong CGRectIntegral () CGRectIntegral rounds the rectangle’s origin downward and its size upward to the nearest whole integers, trong trường hợp này sẽ làm tròn chiều cao và chiều rộng để đảm bảo không xảy ra hiện tượng cắt nếu chiều cao hoặc chiều rộng của một giá trị phân số.
runmad

47

Vì một số lý do, ràng buộcRectWithSize luôn trả về kích thước sai. Tôi đã tìm ra một giải pháp. Có một phương thức cho UItextView -sizeThatFits trả về kích thước phù hợp cho bộ văn bản. Vì vậy, thay vì sử dụng ràng buộcRectWithSize, hãy tạo một UITextView, với một khung ngẫu nhiên và gọi sizeThatFits của nó với chiều rộng và chiều cao CGFLOAT_MAX tương ứng. Nó trả về kích thước sẽ có chiều cao phù hợp.

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

Nếu bạn đang tính toán kích thước trong một vòng lặp while, đừng quên thêm nó vào nhóm tự động phát hành, vì sẽ có n số UITextView được tạo, bộ nhớ thời gian chạy của ứng dụng sẽ tăng nếu chúng ta không sử dụng autoreleasepool.


1
Những công việc này. Những cách khác tôi đã cố gắng tôi không bao giờ có thể làm việc. Tôi nghĩ vấn đề của tôi bắt nguồn từ sự phức tạp của chuỗi được gán mà tôi đã gán. Nó đến từ một tệp RTF và sử dụng nhiều phông chữ, khoảng cách dòng, thậm chí bóng và mặc dù sử dụng UsesLineFragmentOrigin và UsesFontLead tôi không bao giờ có thể có được kết quả đủ cao và vấn đề tồi tệ nhất là chuỗi được quy kết dài hơn. Tôi đoán là đối với các chuỗi tương đối đơn giản, phương thức ràng buộcRectWithSize có thể hoạt động. Họ thực sự cần một phương pháp tốt hơn để làm việc với điều này, imo.
John Bushnell

Bạn có nghĩ rằng nó là quá mức cần thiết để tạo ra UITextViewnhiều lần như heightForRowAtIndexPathphương thức được gọi không? phải mất thời gian
János

Tôi đồng ý với bạn @ János, nhưng đây là giải pháp duy nhất hiệu quả với tôi.
shoan

btw Tôi đã yêu cầu giải pháp thích hợp: stackoverflow.com/questions/32495744/,
János

đây là giải pháp duy nhất hiệu quả Vấn đề này đã có 9 năm và Apple dường như không muốn giải quyết vấn đề này hoặc các kỹ sư của họ yếu đi để tìm ra giải pháp cho vấn đề này. Chúng ta đang nói ở đây về iOS 11, vẫn mang cùng một lỗi.
Vịt

31

Ed McManus chắc chắn đã cung cấp một chìa khóa để làm cho điều này hoạt động. Tôi tìm thấy một trường hợp không hoạt động

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

trực tràng sẽ không có chiều cao chính xác. Lưu ý rằng AnotherString (được gắn vào chuỗi ) đã được khởi tạo mà không có từ điển thuộc tính. Đây là một trình khởi tạo hợp pháp cho AnotherString nhưng ràng buộcRectWithSize : không đưa ra kích thước chính xác trong trường hợp này.


33
Cảm ơn bạn! Hóa ra MỌI phần của NSAttributionString phải có một bộ từ điển với ít nhất NSFontAttributionName và NSForegroundColorAttributionName, nếu bạn muốn ràng buộcRectWithSize thực sự hoạt động! Tôi không thấy tài liệu đó ở bất cứ đâu.
Ben Wheeler

3
Lưu ý rằng có vẻ như NSAttributionStrings khác nhau được kết hợp để tạo một cái duy nhất đều phải sử dụng từ điển SAME (và do đó cùng một phông chữ) để ràng buộcRectWithSize hoạt động chính xác!
Ben Wheeler

1
Giải pháp này rất giống với giải pháp tôi sử dụng cho danh mục UILabel của mình để "thu nhỏ cho vừa". Chìa khóa để tôi làm việc này là tạo hình chữ nhật giới hạn với chiều cao FLT_MAX. Nếu không có điều đó, tôi dường như sẽ có được một hình chữ nhật cho chỉ một dòng.
dre1138

+ 1s tất cả các vòng. Điều này thực sự có tôi, vì vậy cảm ơn vì đã làm việc ra các chàng trai.
Wex

Tôi đã có vấn đề này. Tôi đã sử dụng khoảng trắng và dòng mới trong NSMutableAttributedStringkhông có thuộc tính và tôi đã nhận được kích thước sai.
vbeanchar

28

Quyết định cuối cùng của tôi sau khi điều tra dài:
- boundingRectWithSizehàm trả về kích thước chính xác cho chuỗi ký tự không bị gián đoạn! Trong trường hợp chuỗi chứa khoảng trắng hoặc thứ gì khác (được Apple gọi là "Một số glyphs") - không thể có được kích thước thực của chỉnh lưu cần thiết để hiển thị văn bản!
Tôi đã thay thế khoảng trắng trong chuỗi của mình bằng các chữ cái và ngay lập tức có kết quả chính xác.

Apple nói ở đây: https://developer.apple.com/documentation/foundation/nsopes/1524729-boundingrectwithsize

"Phương thức này trả về giới hạn thực tế của glyphs trong chuỗi. Một số glyph (ví dụ khoảng trắng) được phép chồng lấp các ràng buộc bố cục được chỉ định bởi kích thước được truyền vào, do đó, trong một số trường hợp, giá trị độ rộng của thành phần kích thước của CGRectgiá trị trả về có thể vượt quá giá trị chiều rộng của tham số kích thước. "

Vì vậy, cần phải tìm một số cách khác để tính trực tiếp thực tế ...


Sau quá trình điều tra quá trình dài cuối cùng cũng tìm thấy !!! Tôi không chắc nó sẽ hoạt động tốt cho tất cả các trường hợp liên quan đến UITextView, nhưng điều chính và quan trọng đã được phát hiện!

boundingRectWithSizehàm cũng như CTFramesetterSuggestFrameSizeWithConstraints(và nhiều phương thức khác) sẽ tính toán kích thước và phần văn bản chính xác khi sử dụng đúng hình chữ nhật. Ví dụ - UITextViewhas textView.bounds.size.width- và giá trị này không phải là hình chữ nhật thực tế được sử dụng bởi hệ thống khi vẽ văn bản trên UITextView.

Tôi tìm thấy tham số rất thú vị và thực hiện phép tính đơn giản trong mã:

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

Và phép thuật hoạt động - tất cả các văn bản của tôi tính toán chính xác ngay bây giờ! Thưởng thức!


1
yeap, tôi nhận thấy rằng nó cũng không giữ các ràng buộc về chiều rộng, nó luôn luôn lớn hơn. Điều đó thực sự không hay, họ không tán thành phương pháp làm việc và bây giờ chúng tôi phải đối phó với chuyện tào lao này.
Boris Gafurov

1
Thưa ngài, là anh hùng mới của tôi! Điều này đã khiến tôi phát điên. Tôi đang thiết lập các bộ chèn textContainers, vì vậy phải sử dụng textView.textContainer.size. Thong thay vì textView.bound.size.witdh.
GCBenson

Tôi không thể bỏ phiếu này đủ. Thật kỳ lạ khi không gian không được xem xét trong các tính toán giới hạn.
Đuổi theo Hà Lan

1
Thay thế khoảng trắng bằng một số ký tự giả như "3" trả về chiều cao chính xác
Abuzar Amin

1
điều này đã cứu sự nghiệp của tôi và mối quan hệ của tôi với đội QA. Tôi nợ bạn một người đàn ông bia !!
lucaslt89

14

Swift bốn phiên bản

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

Đo văn bản với CTFramesetter hoạt động tốt nhất vì nó cung cấp kích thước số nguyên và xử lý tốt các biểu tượng cảm xúc và các ký tự unicode khác.


10

Tôi đã không gặp may mắn với bất kỳ lời đề nghị nào trong số này. Chuỗi của tôi chứa các điểm đạn unicode và tôi nghi ngờ chúng gây ra sự đau buồn trong tính toán. Tôi nhận thấy UITextView đang xử lý bản vẽ tốt, vì vậy tôi đã xem xét điều đó để tận dụng tính toán của nó. Tôi đã làm như sau, có lẽ không tối ưu như các phương pháp vẽ NSString, nhưng ít nhất nó chính xác. Nó cũng tối ưu hơn một chút so với khởi tạo UITextView chỉ để gọi -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);

Nó có thể không phải là dấu chấm unicode, nó có thể là khoảng trắng ở cuối chuỗi của bạn. Xem câu trả lời ở trên: stackoverflow.com/a/25941139/337934 .
SamB

9

Trong trường hợp bạn muốn lấy hộp giới hạn bằng cách cắt đuôi, câu hỏi này có thể giúp bạn giải quyết.

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

Hóa ra MỌI phần của NSAttributionString phải có một bộ từ điển với ít nhất NSFontAttributionName và NSForegroundColorAttributionName, nếu bạn muốn ràng buộcRectWithSize thực sự hoạt động!

Tôi không thấy tài liệu đó ở bất cứ đâu.


Cảm ơn, đây là giải pháp cho tôi, ngoại trừ tôi thấy rằng chỉ NSFontAttributionName là cần thiết, không phải NSForegroundColorAttributionName
Marmoy

7

@warrenm Rất tiếc phải nói rằng phương pháp framesetter không hiệu quả với tôi.

Tôi đã nhận được điều này. Chức năng này có thể giúp chúng tôi xác định kích thước khung hình cần thiết cho phạm vi chuỗi của NSAttributionString trong iphone / Ipad SDK cho Độ rộng nhất định:

Nó có thể được sử dụng cho chiều cao động của các ô 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));
}

Cảm ơn HADDAD ISSA >>> http://haddadissa.blogspot.in/2010/09/compute-needed-heigh-for-fixed- thong-of.html


Không hoạt động với tôi trên mọi thiết bị (iPhone 4 và 5). Cả trên thiết bị có Trình mô phỏng iOS7.1.2 và 4s với iOS8.3 :(
sanjana

Cái này cần nhập gì?
jose920405

@KaranAlangat có#import <CoreText/CoreText.h>
jose920405

7

Tôi thấy rằng giải pháp ưa thích không xử lý ngắt dòng.

Tôi đã tìm thấy phương pháp này hoạt động trong mọi trường hợp:

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;

Trong trường hợp của tôi, tôi nên thực hiện phép tính trên luồng nền và không được phép sử dụng các thành phần UI
Lubbo

4

Tôi đã có cùng một vấn đề với việc không có được kích thước chính xác bằng các kỹ thuật này và tôi đã thay đổi cách tiếp cận của mình để làm cho nó hoạt động.

Tôi có một chuỗi được gán dài mà tôi đã cố gắng khớp với chế độ xem cuộn để nó hiển thị đúng mà không bị cắt ngắn. Những gì tôi đã làm để làm cho văn bản hoạt động đáng tin cậy là không đặt chiều cao ở mức giới hạn và thay vào đó cho phép kích thước nội tại chiếm lấy. Bây giờ văn bản được hiển thị chính xác mà không bị cắt ngắn và tôi không phải tính chiều cao.

Tôi cho rằng nếu tôi cần phải có chiều cao một cách đáng tin cậy thì tôi sẽ tạo một chế độ xem bị ẩn và các ràng buộc này và lấy chiều cao của khung sau khi các ràng buộc được áp dụng.


2
Bạn có thể thêm một mẫu mã để chứng minh điều này? Cám ơn.
Nathan Buggia

3

Tôi hơi trễ trò chơi - nhưng tôi đã cố gắng tìm ra cách hoạt động để tìm hộp giới hạn phù hợp với chuỗi được gán để tạo vòng lấy nét như chỉnh sửa tệp trong Finder. mọi thứ tôi đã thử đều thất bại khi có khoảng trắng ở cuối chuỗi hoặc nhiều khoảng trắng bên trong chuỗi. boundingRectWithSizethất bại thảm hại cho điều này cũng như CTFramesetterCreateWithAttributedString.

Sử dụng một NSLayoutManagerđoạn mã sau đây dường như thực hiện thủ thuật trong tất cả các trường hợp tôi đã tìm thấy cho đến nay và trả về một chỉnh lưu hoàn toàn giới hạn chuỗi. Phần thưởng: nếu bạn chọn văn bản, các cạnh của vùng chọn sẽ đi thẳng đến giới hạn của trực tràng được trả về. Mã dưới đây sử dụng layoutManager từ 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));

Hoạt động trên tất cả các phông chữ hoàn hảo!


1

Tôi đã có cùng một vấn đề, nhưng tôi nhận ra rằng hạn chế chiều cao đã được đặt chính xác. Vì vậy, tôi đã làm như sau:

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

Tôi đã thử mọi thứ trên trang này và vẫn có một trường hợp cho một UILabel không định dạng chính xác. Trên thực tế, việc thiết lập các thuộc tính trên nhãn cuối cùng đã khắc phục vấn đề.


1

Một điều tôi nhận thấy là bộ chỉnh lưu sẽ quay trở lại (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)contextsẽ có chiều rộng lớn hơn so với những gì tôi truyền vào. Khi điều này xảy ra, chuỗi của tôi sẽ bị cắt ngắn. Tôi đã giải quyết nó như thế này:

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;

Đối với một số bối cảnh hơn; Tôi đã có văn bản nhiều dòng và tôi đã cố gắng tìm chiều cao phù hợp để hiển thị nó. Ràng buộc với đôi khi trả về chiều rộng lớn hơn chiều rộng tôi sẽ chỉ định, do đó, khi tôi sử dụng chiều rộng và chiều cao tính toán để hiển thị văn bản của mình, nó sẽ cắt ngắn. Từ việc kiểm tra khi ràng buộcRectWithSize đã sử dụng sai chiều rộng, số lượng nó sẽ làm cho chiều cao bị rút ngắn là 1 dòng. Vì vậy, tôi sẽ kiểm tra xem chiều rộng có lớn hơn không và nếu vậy hãy thêm dòng của phông chữ để cung cấp đủ không gian để tránh bị cắt bớt.


Làm thế nào là chiều cao dòng hiệu ứng với chiều rộng?
Roi Mulia

Chiều cao dòng @RoiMulia không ảnh hưởng đến chiều rộng. Tôi đã cập nhật câu trả lời của mình để cung cấp thêm ngữ cảnh về cách khắc phục lỗi này.
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;

Nếu khung của nhãn không thêm 10 thì phương thức này sẽ không bao giờ hoạt động! Hy vọng điều này có thể giúp bạn! goog may mắn.


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

Trong trường hợp của tôi, tôi nên thực hiện phép tính trên luồng nền và không được phép sử dụng các thành phần UI
Lubbo

0

Tôi muốn thêm suy nghĩ của mình vì tôi có cùng một vấn đề.

Tôi đã sử dụng UITextViewvì nó có căn chỉnh văn bản đẹp hơn (biện minh, vào thời điểm đó không có sẵn UILabel), nhưng để "mô phỏng" không tương tác-không thể cuộnUILabel , tôi sẽ tắt hoàn toàn cuộn, nảy và tương tác người dùng .

Tất nhiên, vấn đề là văn bản đó là động và trong khi chiều rộng sẽ được cố định, chiều cao sẽ được tính toán lại mỗi khi tôi đặt giá trị văn bản mới.

boundingRectWithSizeTôi hoàn toàn không làm việc tốt với tôi, từ những gì tôi có thể thấy, UITextViewđã thêm một số lề trên đầu mà boundingRectWithSizekhông thể đếm được, do đó, chiều cao được lấy từboundingRectWithSize nhỏ hơn mức cần thiết.

Vì văn bản không được cập nhật nhanh chóng, nên nó chỉ được sử dụng cho một số thông tin có thể cập nhật sau mỗi 2-3 giây nhiều nhất, tôi đã quyết định phương pháp sau:

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

* Mã trên không được sao chép trực tiếp từ nguồn của tôi, tôi đã phải điều chỉnh / xóa nó khỏi một loạt các thứ khác không cần thiết cho bài viết này. Đừng lấy nó để sao chép-dán-và-nó-sẽ-làm việc-mã.

Bất lợi rõ ràng là nó có phân bổ và phát hành, cho mỗi cuộc gọi.

Nhưng, ưu điểm là bạn tránh được tùy thuộc vào khả năng tương thích giữa cách ràng buộcRectWithSize vẽ văn bản và tính toán kích thước của nó và triển khai bản vẽ văn bản trong UITextView(hoặc UILabelbạn cũng có thể sử dụng thay thế UITextViewbằngUILabel ). Bất kỳ "lỗi" nào mà Apple có thể có đều tránh được.

Tái bút: Có vẻ như bạn không cần "temp" này UITextViewvà chỉ có thể hỏi sizeThatFitstrực tiếp từ mục tiêu, tuy nhiên điều đó không hiệu quả với tôi. Mặc dù logic sẽ nói rằng nó nên hoạt động và phân bổ / giải phóng tạm thời UITextViewlà không cần thiết, nhưng không. Nhưng giải pháp này hoạt động hoàn hảo cho bất kỳ văn bản nào tôi sẽ đặt.


Trong trường hợp của tôi, tôi nên thực hiện phép tính trên luồng nền và không được phép sử dụng các thành phần UI
Lubbo

0

Ok vì vậy tôi đã dành rất nhiều thời gian để gỡ lỗi này. Tôi phát hiện ra rằng chiều cao văn bản tối đa như được xác định bằng cách boundingRectWithSizecho phép hiển thị văn bản của tôi UITextViewthấp hơn kích thước khung hình.

Trong trường hợp của tôi, khung hình nhiều nhất là 140pt nhưng UITextView chấp nhận các văn bản nhiều nhất là 131pt.

Tôi đã phải tìm ra điều đó bằng tay và mã hóa chiều cao tối đa "thực".

Đây là giải pháp của tôi:

- (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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.