Как определить размер UITextView для его содержимого?

есть ли хороший способ настроить размер UITextView соответствовать своему содержанию? Скажем, например, у меня есть UITextView, который содержит одну строку текста:

"Hello world"

затем я добавляю еще одну строку текста:

"Goodbye world"

есть ли хороший способ в Cocoa Touch, чтобы получить rect это будет содержать все строки в текстовом представлении, чтобы я мог соответствующим образом настроить родительское представление?

в качестве другого примера, посмотрите на поле notes для событий в календаре применение-обратите внимание, как ячейка (и UITextView Он содержит) расширяется, чтобы удерживать все строки текста в строке notes.

30 ответов


это работает как для iOS 6.1, так и для iOS 7:

- (void)textViewDidChange:(UITextView *)textView
{
    CGFloat fixedWidth = textView.frame.size.width;
    CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
    CGRect newFrame = textView.frame;
    newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
    textView.frame = newFrame;
}

или в Swift (работает с Swift 4.1 в iOS 11)

let fixedWidth = textView.frame.size.width
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
textView.frame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)

Если вы хотите поддержку iOS 6.1, то вы также должны:

textview.scrollEnabled = NO;

это больше не работает на iOS 7 или выше

на самом деле есть очень простой способ сделать изменение размера UITextView к своей правильной высоте содержания. Это можно сделать с помощью UITextView contentSize.

CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;

одна вещь, чтобы отметить, что правильно contentSize доступно только после на UITextView был добавлен в представление с addSubview. До этого он равен frame.size

это не будет работать, если включен автоматический макет. С авто макет, общий подход заключается в использовании sizeThatFits метод и обновить constant значение ограничения высоты.

CGSize sizeThatShouldFitTheContent = [_textView sizeThatFits:_textView.frame.size];
heightConstraint.constant = sizeThatShouldFitTheContent.height;

heightConstraint - это ограничение макета, которое обычно настраивается с помощью IBOutlet, связывая свойство с ограничением высоты, созданным в раскадровке.


просто чтобы добавить к этому удивительному ответу, 2014, Если вы:

[self.textView sizeToFit];

есть разница в поведении с iPhone6 покрывает+ только:

enter image description here

только с 6+ (не 5s или 6) он добавляет "еще одну пустую строку" в UITextView. "Решение RL" исправляет это отлично:

CGRect _f = self.mainPostText.frame;
_f.size.height = self.mainPostText.contentSize.height;
self.mainPostText.frame = _f;

он исправляет проблему "дополнительной строки" на 6+.


чтобы сделать динамический размер UITextView внутри UITableViewCell, Я нашел следующую комбинацию работает в Xcode 6 с iOS 8 SDK:

  • добавить UITextView до UITableViewCell и ограничьте его в стороны
  • установить UITextView ' s scrollEnabled свойство NO. При включенной прокрутке рамка UITextView не зависит от размера содержимого, но при отключенной прокрутке между ними существует связь.
  • если ваша таблица используя исходную высоту строки по умолчанию 44, он автоматически вычислит высоту строки, но если вы изменили высоту строки по умолчанию на что-то другое, вам может потребоваться вручную включить автоматический расчет высоты строки в viewDidLoad:

    tableView.estimatedRowHeight = 150;
    tableView.rowHeight = UITableViewAutomaticDimension;
    

для динамического размера только для чтения UITextViews, Вот и все. Если вы разрешаете пользователям редактировать текст в вашем UITextView, вы также нужно:

  • реализовать textViewDidChange: метод UITextViewDelegate протокол, и сказать tableView перерисовывать себя каждый раз при редактировании текста:

    - (void)textViewDidChange:(UITextView *)textView;
    {
        [tableView beginUpdates];
        [tableView endUpdates];
    }
    
  • и не забудьте установить UITextView делегировать куда-нибудь, либо в Storyboard или tableView:cellForRowAtIndexPath:


Свифт :

textView.sizeToFit()

просто набор

Код

textView.scrollEnabled = false

Раскадровке

enter image description here

Не нужно ничего делать, кроме этого.


в моем (ограниченном) опыте,

- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode

не уважает символы новой строки, так что вы можете в конечном итоге с гораздо меньше CGSize чем на самом деле требуется.

- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size

похоже, уважает новые строки.

кроме того, текст фактически не отображается в верхней части UITextView. В моем коде я установил новую высоту UITextView быть на 24 пикселя больше высоты, возвращаемой sizeOfFont методы.


в iOS6, вы можете проверить contentSize свойство UITextView сразу после установки текста. В iOS7, это больше не будет работать. Если вы хотите восстановить это поведение для iOS7, поместите следующий код в подкласс UITextView.

- (void)setText:(NSString *)text
{
    [super setText:text];

    if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {
        CGRect rect = [self.textContainer.layoutManager usedRectForTextContainer:self.textContainer];
        UIEdgeInsets inset = self.textContainerInset;
        self.contentSize = UIEdgeInsetsInsetRect(rect, inset).size;
    }
}

я опубликую правильное решение в нижней части страницы, если кто-то смелый (или отчаявшийся), чтобы прочитать до этого момента.

вот GitHub РЕПО для тех, кто не хочет читать весь этот текст: resizableTextView

это работает с iOs7 (и я верю, что он будет работать с iOs8) и с autolayout. Вам не нужны магические числа, отключить макет и тому подобное. короткое и элегантное решение.

I подумайте, что весь код, связанный с ограничениями, должен перейти в updateConstraints метод. Итак, давайте сделаем наш собственный ResizableTextView.

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

CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];

Итак, теперь мы знаем реальный contentSize независимо от того, где мы находимся: до или после viewDidLoad. Теперь добавьте ограничение высоты на textView (через раскадровку или код, независимо от того, как). Мы скорректируем это значение с помощью нашего contentSize.height:

[self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
    if (constraint.firstAttribute == NSLayoutAttributeHeight) {
        constraint.constant = contentSize.height;
        *stop = YES;
    }
}];

последнее, что нужно сделать, это сказать суперклассом updateConstraints.

[super updateConstraints];
наш класс выглядит так:

ResizableTextView.м

- (void) updateConstraints {
    CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];

    [self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
        if (constraint.firstAttribute == NSLayoutAttributeHeight) {
            constraint.constant = contentSize.height;
            *stop = YES;
        }
    }];

    [super updateConstraints];
}

красивая и чистая, верно? И вам не нужно иметь дело с этим кодом в вашем контроллеры!

Но подождите! Y НЕТ Анимация!

вы можете легко анимировать изменения textView растянуть гладко. Вот пример:

    [self.view layoutIfNeeded];
    // do your own text change here.
    self.infoTextView.text = [NSString stringWithFormat:@"%@, %@", self.infoTextView.text, self.infoTextView.text];
    [self.infoTextView setNeedsUpdateConstraints];
    [self.infoTextView updateConstraintsIfNeeded];
    [UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionLayoutSubviews animations:^{
        [self.view layoutIfNeeded];
    } completion:nil];

ты [textView sizeThatFits:textView.bounds] ?

Edit: sizeThatFits возвращает размер, но фактически не изменяет размер компонента. Я не уверен, что это то, что вы хотите, или если [textView sizeToFit] больше то, что вы искали. В любом случае, я не знаю, будет ли он идеально соответствовать содержанию, Как вы хотите, но это первое, что нужно попробовать.


другой метод-найти размер, который будет занимать конкретная строка с помощью NSString способ:

-(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size

Это возвращает размер прямоугольника, который соответствует данной строке с заданным шрифтом. Пройдите в размер с нужной шириной и максимальной высотой, а затем вы можете посмотреть на высоту, возвращенную для подгонки текста. Существует версия, которая позволяет также указать режим разрыва строки.

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


если у вас нет UITextView удобно (например, Вы размер ячейки таблицы), вам придется рассчитать размер, измеряя строку, а затем учет 8 pt заполнения с каждой стороны UITextView. Например, если вы знаете желаемую ширину вашего текстового представления и хотите выяснить соответствующую высоту:

NSString * string = ...;
CGFloat textViewWidth = ...;
UIFont * font = ...;

CGSize size = CGSizeMake(textViewWidth - 8 - 8, 100000);
size.height = [string sizeWithFont:font constrainedToSize:size].height + 8 + 8;

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

In практика, вы можете добавить дополнительный font.leading к высоте; это добавляет пустую строку под вашим текстом, которая может выглядеть лучше, если есть визуально тяжелые элементы управления непосредственно под видом текста.


достаточно следующих вещей:

  1. только не забудьте установить прокрутка to нет для UITextView:

enter image description here

  1. правильно установить ограничения автоматической компоновки.

вы даже можете использовать UITableViewAutomaticDimension.


мы можем сделать это с помощью ограничений .

  1. установить ограничения по высоте для UITextView. enter image description here

2.Создайте IBOutlet для этого ограничения высоты.

 @property (weak, nonatomic) IBOutlet NSLayoutConstraint *txtheightconstraints;

3.не забудьте установить делегат для вашего textview.

4.

-(void)textViewDidChange:(UITextView *)textView
{
    CGFloat fixedWidth = textView.frame.size.width;
    CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
    CGRect newFrame = textView.frame;
    newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
    NSLog(@"this is updating height%@",NSStringFromCGSize(newFrame.size));
    [UIView animateWithDuration:0.2 animations:^{
                  _txtheightconstraints.constant=newFrame.size.height;
    }];

}

затем обновите свое ограничение следующим образом:)


в сочетании с ответом Майка Макмастера вы можете сделать что-то вроде:

[myTextView setDelegate: self];

...

- (void)textViewDidChange:(UITextView *)textView {
  if (myTextView == textView) {
     // it changed.  Do resizing here.
  }
}

Я нашел способ изменить высоту текстового поля в соответствии с текстом внутри него, а также расположить метку под ним на основе высоты текстового поля! Вот код.

UITextView *_textView = [[UITextView alloc] initWithFrame:CGRectMake(10, 10, 300, 10)];
NSString *str = @"This is a test text view to check the auto increment of height of a text view. This is only a test. The real data is something different.";
_textView.text = str;

[self.view addSubview:_textView];
CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;

UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(10, 5 + frame.origin.y + frame.size.height, 300, 20)];
lbl.text = @"Hello!";
[self.view addSubview:lbl];

ребята, использующие autolayout, и ваш sizetofit не работает, затем проверьте ограничение ширины один раз. Если вы пропустили ограничение ширины, то высота будет точно.

нет необходимости использовать любой другой API. только одна строка исправит все проблемы.

[_textView sizeToFit];

здесь я занимался только высотой, сохраняя фиксированную ширину и пропустил ограничение ширины моего TextView в раскадровке.

и это должно было показать динамическое содержимое из сервисы.

надеюсь, это может помочь..


начиная с iOS 8, можно использовать функции автоматической компоновки UITableView для автоматического изменения размера UITextView без пользовательского кода вообще. Я поставил проект в github это демонстрирует это в действии, но вот ключ:

  1. в UITextView должна быть отключена прокрутка, что можно сделать программно или через построитель интерфейса. Он не будет изменять размер, если прокрутка включена, потому что прокрутка позволяет просматривать больше содержание.
  2. в viewDidLoad для UITableViewController вы должны установить значение для estimatedRowHeight, а затем установить rowHeight to UITableViewAutomaticDimension.

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.estimatedRowHeight = self.tableView.rowHeight;
    self.tableView.rowHeight = UITableViewAutomaticDimension;
}
  1. целью развертывания проекта должна быть iOS 8 или выше.

это сработало хорошо, когда мне нужно было сделать текст в UITextView установите определенную область:

// The text must already be added to the subview, or contentviewsize will be wrong.

- (void) reduceFontToFit: (UITextView *)tv {
    UIFont *font = tv.font;
    double pointSize = font.pointSize;

    while (tv.contentSize.height > tv.frame.size.height && pointSize > 7.0) {
        pointSize -= 1.0;
        UIFont *newFont = [UIFont fontWithName:font.fontName size:pointSize];
        tv.font = newFont;
    }
    if (pointSize != font.pointSize)
        NSLog(@"font down to %.1f from %.1f", pointSize, tv.font.pointSize);
}

вот быстрая версия @jhibberd

    let cell:MsgTableViewCell! = self.tableView.dequeueReusableCellWithIdentifier("MsgTableViewCell", forIndexPath: indexPath) as? MsgTableViewCell
    cell.msgText.text = self.items[indexPath.row]
    var fixedWidth:CGFloat = cell.msgText.frame.size.width
    var size:CGSize = CGSize(width: fixedWidth,height: CGFloat.max)
    var newSize:CGSize = cell.msgText.sizeThatFits(size)
    var newFrame:CGRect = cell.msgText.frame;
    newFrame.size = CGSizeMake(CGFloat(fmaxf(Float(newSize.width), Float(fixedWidth))), newSize.height);
    cell.msgText.frame = newFrame
    cell.msgText.frame.size = newSize        
    return cell

для iOS 7.0, вместо frame.size.height до contentSize.height (который в настоящее время ничего не делает) использовать [textView sizeToFit].

посмотреть этот вопрос.


я рассмотрел все ответы, и все они сохраняют фиксированную ширину и регулируют только высоту. Если вы хотите отрегулировать и ширину вы можете очень легко использовать этот метод:

поэтому при настройке текстового представления установите scroll disabled

textView.isScrollEnabled = false

а затем в методе делегата func textViewDidChange(_ textView: UITextView) добавить этот код:

func textViewDidChange(_ textView: UITextView) {
    let newSize = textView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))
    textView.frame = CGRect(origin: textView.frame.origin, size: newSize)
}

выходы:

enter image description here

enter image description here


отключить прокрутку

добавить constaints

и добавьте свой текст

[yourTextView setText:@"your text"];
[yourTextView layoutIfNeeded];

Если вы используете UIScrollView вы должны добавить это:

[yourScrollView layoutIfNeeded];

-(void)viewDidAppear:(BOOL)animated{
    CGRect contentRect = CGRectZero;

    for (UIView *view in self.yourScrollView.subviews) {
         contentRect = CGRectUnion(contentRect, view.frame);
    }
    self.yourScrollView.contentSize = contentRect.size;
}

надеюсь, это поможет:

- (void)textViewDidChange:(UITextView *)textView {
  CGSize textSize = textview.contentSize;
  if (textSize != textView.frame.size)
      textView.frame.size = textSize;
}

если какой-либо другой здесь, это решение работает для меня, 1 "Ronnie Liew" +4 "user63934" (мой текст поступает из веб-службы): обратите внимание на 1000 (ничто не может быть настолько большой "в моем случае")

UIFont *fontNormal = [UIFont fontWithName:FONTNAME size:FONTSIZE];

NSString *dealDescription = [client objectForKey:@"description"];

//4
CGSize textSize = [dealDescription sizeWithFont:fontNormal constrainedToSize:CGSizeMake(containerUIView.frame.size.width, 1000)];

CGRect dealDescRect = CGRectMake(10, 300, containerUIView.frame.size.width, textSize.height);

UITextView *dealDesc = [[[UITextView alloc] initWithFrame:dealDescRect] autorelease];

dealDesc.text = dealDescription;
//add the subview to the container
[containerUIView addSubview:dealDesc];

//1) after adding the view
CGRect frame = dealDesc.frame;
frame.size.height = dealDesc.contentSize.height;
dealDesc.frame = frame;

и это... Ура!--2-->


лучший способ, который я узнал, чтобы изменить размер высоты UITextView в соответствии с размером текста.

CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0]
                       constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX)];

или вы можете использовать

CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0]
                       constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX) lineBreakMode:NSLineBreakByTruncatingTail];

для тех, кто хочет textview на самом деле двигаться вверх и поддерживать позицию нижней строки

CGRect frame = textView.frame;
frame.size.height = textView.contentSize.height;

if(frame.size.height > textView.frame.size.height){
    CGFloat diff = frame.size.height - textView.frame.size.height;
    textView.frame = CGRectMake(0, textView.frame.origin.y - diff, textView.frame.size.width, frame.size.height);
}
else if(frame.size.height < textView.frame.size.height){
    CGFloat diff = textView.frame.size.height - frame.size.height;
    textView.frame = CGRectMake(0, textView.frame.origin.y + diff, textView.frame.size.width, frame.size.height);
}

единственный код, который будет работать, - это тот, который использует "SizeToFit", как в ответе jhibberd выше, но на самом деле он не будет подниматься, если вы не вызовете его ViewDidAppear или подключите его к событию изменения текста UITextView.


основываясь на ответе Никиты, я пришел к следующему решению в Swift, которое работает на iOS 8 с autolayout:

    descriptionTxt.scrollEnabled = false
    descriptionTxt.text = yourText

    var contentSize = descriptionTxt.sizeThatFits(CGSizeMake(descriptionTxt.frame.size.width, CGFloat.max))
    for c in descriptionTxt.constraints() {
        if c.isKindOfClass(NSLayoutConstraint) {
            var constraint = c as! NSLayoutConstraint
            if constraint.firstAttribute == NSLayoutAttribute.Height {
                constraint.constant = contentSize.height
                break
            }
        }
    }

быстрым ответом: Следующий код вычисляет высоту вашего textView.

                let maximumLabelSize = CGSize(width: Double(textView.frame.size.width-100.0), height: DBL_MAX)
                let options = NSStringDrawingOptions.TruncatesLastVisibleLine | NSStringDrawingOptions.UsesLineFragmentOrigin
                let attribute = [NSFontAttributeName: textView.font!]
                let str = NSString(string: message)
                let labelBounds = str.boundingRectWithSize(maximumLabelSize,
                    options: NSStringDrawingOptions.UsesLineFragmentOrigin,
                    attributes: attribute,
                    context: nil)
                let myTextHeight = CGFloat(ceilf(Float(labelBounds.height)))

теперь вы можете установить высоту вашего textView в myTextHeight


вот вам и ответ, Если вам нужно изменить размер textView и tableViewCell динамически в staticTableView

[https://stackoverflow.com/a/43137182/5360675][1]