Расхождение между sizeWithFont: constrainedToSize: lineBreakMode: и textView.contentSize.height - PullRequest
4 голосов
/ 31 августа 2010

Я использую метод [string sizeWithFont:constrainedToSize:lineBreakMode:], чтобы оценить высоту textView, который я изменяю.Тем не менее, он, похоже, последовательно возвращает неправильный размер.Для отладки я написал следующий код:

self.textView.font = [UIFont systemFontOfSize:14.0]; // It was this before, anyways
NSLog(@"Real width: %lf %lf", self.textView.contentSize.width, self.textView.frame.size.width);
NSLog(@"Real height: %lf", self.textView.contentSize.height);
NSLog(@"Estimated width: %lf", kOTMessageCellTextWidth);
NSLog(@"Estimated height: %lf", ([message.message sizeWithFont:[UIFont systemFontOfSize:14.0]
                                             constrainedToSize:CGSizeMake(kOTMessageCellTextWidth, CGFLOAT_MAX)
                                                 lineBreakMode:UILineBreakModeWordWrap].height));

Однако приведенный выше код показывает, что я получаю противоречивые результаты:

Реальная ширина: 223.000000 223.000000Реальная высота: 52.000000Расчетная ширина: 223.000000Расчетная высота: 36.000000Реальная ширина: 223,000000 223,000000Реальная высота: 142.000000Расчетная ширина: 223.000000Расчетная высота: 126.000000Реальная ширина: 223,000000 223,000000Реальная высота: 142.000000Расчетная ширина: 223.000000Расчетная высота: 126.000000

Я заметил в этот похожий вопрос , что (очевидно) textView имеет некоторый отступ, который ограничивает его фактическую ширину.Рекомендацией было уменьшение ширины до sizeWithFont: на некоторое число.Рекомендованное число было 11.

Мой вопрос: есть ли способ на самом деле получить это значение программно, или есть какая-то документация, которую я пропустил, указав это число?Кажется, что этот номер должен быть доступен и не должен быть угадан и проверен, но я не могу найти надежный способ его идентифицировать.

Заранее спасибо.

Ответы [ 6 ]

6 голосов
/ 08 октября 2011

ОК, после небольшого (пере) поиска я пришел к этому.

UITextView имеет 8px отступов с каждой стороны. Но и высота строки не совпадает с UILabel (и результатом методов sizeWithFont)

в моем случае шрифт был Arial, а его размер был 16pt, а высота строки textview на 4.5 пункта больше, чем высота строки uilabel. Так,

  • Я получаю результат ( cSize ) из метода sizeWithFont с уменьшением ширины на 16 пикселей
  • Я рассчитал lineCount по cSize.height / font.lineHeight
  • и использовал cSize.height + (lineCount * 4.5) + 16.0 в качестве конечной высоты для просмотра текста

код (не точный код):

CGSize constraintSize = CGSizeMake(250.0 - 16.0, MAXFLOAT);
CGSize labelSize = [message.text sizeWithFont:[UIFont fontWithName:@"Arial" size:16.0] constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
CGFloat lineCount = labelSize.height / [UIFont fontWithName:@"Arial" size:16.0].lineHeight;
CGFloat additional = lineCount * 4.5;       // for 16.0 pt Arial for now
return labelSize.height + additional + 16.0;    // TextView fix

У меня все еще есть небольшие проблемы, и мне не нравится, как я их решил. Но, кажется, хорошо для этой проблемы. И было бы здорово, если бы кто-то придумал разумное решение для этого.

4 голосов
/ 21 июня 2012

Исправление простое, поскольку UITextView имеет 8px отступов с каждой стороны, поэтому, когда вы вычисляете истинный размер текста, вы должны сначала минус этот 16px отступ (8px на двойных сторонах), тогда результат будет правильным.Пожалуйста, посмотрите следующий фрагмент кода:

// self.descView is an UITextView
// UITEXTVIEW_TEXT_PADDING is 8.0
CGSize constrainedSize = CGSizeMake(self.descView.contentSize.width-UITEXTVIEW_TEXT_PADDING*2, MAXFLOAT);
CGSize trueSize = [self.descView.text sizeWithFont:self.descView.font 
                                 constrainedToSize:constrainedSize 
                                     lineBreakMode:UILineBreakModeWordWrap];

CGSize contentSize = self.descView.contentSize;
contentSize.height = trueSize.height;
self.descView.contentSize = contentSize;

frame = self.descView.frame;
frame.size.height = contentSize.height ;
self.descView.frame = frame;

Результат должен быть правильным.

3 голосов
/ 20 января 2013

NSString sizeWithFont вычисляется с использованием Core Text. UITextView использует Webview (внутренне) для отображения его содержимого.

Это несоответствие приводит к всевозможным головным болям. Например, если вы хотите разбивать строки в разных местах - вы заметите списки, разделенные запятыми, и некоторые строки математических выражений будут разбиваться на разных символах между Core Text и UITextView. Это часто приводит к ошибкам построчно при измерении места для ваших строк.

А если вам нужна международная поддержка символов, вы можете забыть о высоте строки Core Text, соответствующей UITextView (независимо от того, сколько комбинаций стиля абзаца и высоты строки вы пытаетесь!).

Я обнаружил, что единственный способ надежно оценить размер для UITextView при заданной NSString - это ... фактически построить UITextView и прочитать его подогнанный размер (минус 8px padding ).

Вот класс UIKitLineMetrics, который делает именно это.

Содержит два "фиктивных" просмотра текста. Вы обновляете экземпляр, используя нужный шрифт и ширину макета, и можете читать из него однострочный и многострочный размеры.

UIKitLineMetrics.h

#import <UIKit/UIKit.h>

@interface UIKitLineMetrics : NSObject

@property (nonatomic, strong) NSMutableAttributedString *attributedString;

- (CGSize) UIKitLineSizeForText:(NSString*)text;
- (CGSize) UIKitSingleLineSizeForText:(NSString*)text;

- (void) updateWithFont:(UIFont*)font andWidth:(CGFloat)width;

@end

UIKitLineMetrics.m

#import "UIKitLineMetrics.h"

@interface UIKitLineMetrics ()

@property (nonatomic, strong) UITextView *measuringTextView;
@property (nonatomic, strong) UITextView *measuringSingleTextView;

@end

@implementation UIKitLineMetrics

@synthesize measuringTextView;
@synthesize measuringSingleTextView;
@synthesize attributedString;

- (id) init
{
    self = [super init];

    if( self )
    {
        attributedString = [[NSMutableAttributedString alloc] init];
        measuringTextView = [[UITextView alloc] initWithFrame:CGRectZero];
        measuringSingleTextView = [[UITextView alloc] initWithFrame:CGRectZero];
    }

    return self;
}

- (CGSize) UIKitLineSizeForText:(NSString*)text
{
    measuringTextView.text = [text stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];

    CGSize sz = [measuringTextView sizeThatFits:CGSizeMake(measuringTextView.frame.size.width, CGFLOAT_MAX)];

    return CGSizeMake(sz.width - 16, sz.height - 16);
}

- (CGSize) UIKitSingleLineSizeForText:(NSString*)text
{
    measuringSingleTextView.text = [text stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];

    CGSize sz = [measuringSingleTextView sizeThatFits:CGSizeMake(measuringSingleTextView.frame.size.width, CGFLOAT_MAX)];

    return CGSizeMake(sz.width - 16, sz.height - 16);
}

- (void) updateWithFont:(UIFont*)font andWidth:(CGFloat)width
{
    measuringTextView.font = font;    
    measuringSingleTextView.font = font;

    measuringTextView.frame = CGRectMake(0, 0, width, 500);
    measuringSingleTextView.frame = CGRectMake(0, 0, 50000, 500);
}

@end
0 голосов
/ 15 сентября 2010

Я тоже боролся с проблемой.Я обычно получаю, передав метод sizeWithFont размер, который меньше, чем фактический размер textView.Даже при добавлении вставок содержимого textview к размеру это не работает.Возвращаемый размер всегда меньше.

  • Чарли
0 голосов
/ 01 сентября 2010

Я использую следующую функцию без особых проблем:

+(float) calculateHeightOfTextFromWidth:(NSString*) text: (UIFont*)withFont: (float)width :(UILineBreakMode)lineBreakMode

{
    [text retain];
    [withFont retain];
    CGSize suggestedSize = [text sizeWithFont:withFont constrainedToSize:CGSizeMake(width, FLT_MAX) lineBreakMode:lineBreakMode];

[text release];
[withFont release];

return suggestedSize.height;
}
0 голосов
/ 01 сентября 2010

Вы можете попробовать проверить значение contentInset (свойство UIScrollView).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...