Как мне настроить размер UITextView в соответствии с его содержимым?

StackOverflow https://stackoverflow.com/questions/50467

Вопрос

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

"Hello world"

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

"Goodbye world"

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

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

Это было полезно?

Решение

Это работает как для 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 к a UITableViewCell и растяните его по бокам
  • Установите UITextView's scrollEnabled собственность на NO.При включенной прокрутке рамка UITextView не зависит от размера содержимого, но при отключенной прокрутке между ними существует взаимосвязь.
  • Если ваша таблица использует исходную высоту строки по умолчанию, равную 44, то она автоматически рассчитает высоту строк, но если вы изменили высоту строки по умолчанию на что-то другое, возможно, вам потребуется вручную включить автоматическое вычисление высоты строк в viewDidLoad:

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

Для динамического определения размера только для чтения UITextViewс., вот и все.Если вы разрешаете пользователям редактировать текст в вашем 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 для тех, кто не хочет читать весь этот текст: Изменяемый текстовый вид

Это работает с iOS7 (и я действительно верю, что это будет работать с iOS8) и с автозапуском.Вам не нужны магические числа, отключите разметку и тому подобное. Короткое и элегантное решение.

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

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

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

Итак, теперь мы знаем реальный размер контента независимо от того, где мы находимся:до или после 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];

Теперь наш класс выглядит так:

Изменяемый текстовый вид.m

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

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

Но подождите! НИКАКОЙ АНИМАЦИИ!

Вы можете легко анимировать вносимые изменения 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] ?

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

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

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

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

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

Если у вас нет UITextView удобно (например, при определении размера ячеек табличного представления), вам нужно будет рассчитать размер путем измерения строки, а затем учесть 8 пт отступов с каждой стороны строки. 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 просто служит очень большим максимальным размером.

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

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

  1. Просто не забудьте установить включена прокрутка Для НЕТ для вашего 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 в storyboard.

И это было сделано для того, чтобы показать динамический контент из сервисов.

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

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

  1. В UITextView должна быть отключена прокрутка, что вы можете сделать программно или через interface builder.Он не изменит размер, если включена прокрутка, потому что прокрутка позволяет просматривать содержимое большего размера.
  2. В viewDidLoad для UITableViewController вы должны установить значение для estimatedRowHeight, а затем установить rowHeight Для 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

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

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

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

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

добавление констант

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

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

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

Видишь этот вопрос.

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

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

если кто-либо другой доберется сюда, это решение сработает для меня, 1 "Ронни Лью" + 4 "пользователь63934" (мой текст поступает из веб-службы):обратите внимание на 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;

И это так...Ваше здоровье

Лучший способ, который я нашел, изменить размер высоты 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 с автозапуском:

    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]

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top