Есть ли хороший способ отрегулировать размер UITextView в соответствии с его содержимым? Скажем, например, у меня есть UITextView, который содержит одну строку текста:
"Hello world"
Затем я добавляю еще одну строку текста:
"Goodbye world"
Есть ли в Cocoa Touch хороший способ получить rect, который будет содержать все строки в текстовом представлении, чтобы я мог соответствующим образом настроить родительский вид?
В качестве другого примера посмотрите на поле заметок для событий в приложении «Календарь» - обратите внимание, как ячейка (и UITextView, который она содержит) расширяется, чтобы вместить все строки текста в строке заметок.
почему нет вопросов, как это сделать нединамически? Я даже не могу понять, как это сделать статично. И предоставленные решения, похоже, не отменяют «ограничений» в раскадровке.





[textView sizeThatFits:textView.bounds] пробовали?
Обновлено: sizeThatFits возвращает размер, но фактически не изменяет размер компонента. Я не уверен, что вы этого хотите, или [textView sizeToFit] - это то, что вам нужно. В любом случае я не знаю, подойдет ли он идеально к контенту, как вы хотите, но это первое, что нужно попробовать.
sizetofit спасает положение
Другой метод - найти размер, который займет конкретная строка, с помощью метода NSString:
-(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
Это возвращает размер прямоугольника, который соответствует заданной строке с заданным шрифтом. Передайте размер с желаемой шириной и максимальной высотой, а затем вы можете посмотреть на возвращенную высоту, чтобы она соответствовала тексту. Существует версия, которая также позволяет указывать режим разрыва строки.
Затем вы можете использовать возвращенный размер, чтобы изменить размер вашего представления, чтобы он соответствовал.
В сочетании с ответом Майка Макмастера вы можете сделать что-то вроде:
[myTextView setDelegate: self];
...
- (void)textViewDidChange:(UITextView *)textView {
if (myTextView == textView) {
// it changed. Do resizing here.
}
}
По моему (ограниченному) опыту,
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
не принимает во внимание символы новой строки, поэтому вы можете получить CGSize намного короче, чем требуется.
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
похоже, уважает новые строки.
Кроме того, текст на самом деле не отображается в верхней части UITextView. В моем коде я установил новую высоту UITextView на 24 пикселя больше, чем высота, возвращаемая методами sizeOfFont.
Он получает размер, как если бы он рисовал текст на UILabel. Если вы установите этот размер для фрейма uitextview, тогда у вас все равно будет необходимая прокрутка.
Надеюсь это поможет:
- (void)textViewDidChange:(UITextView *)textView {
CGSize textSize = textview.contentSize;
if (textSize != textView.frame.size)
textView.frame.size = textSize;
}
Это не работает! Это вызывает ошибку: "lvalue требуется как левый операнд присваивания"
Можно назначить только textView.frame.
На самом деле существует очень простой способ изменить размер UITextView до его правильной высоты содержимого. Это можно сделать с помощью UITextViewcontentSize.
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 +:

Только с 6+ (а не с 5 или 6) он добавляет «еще одну пустую строку» в UITextView. "Решение RL" это прекрасно исправляет:
CGRect _f = self.mainPostText.frame;
_f.size.height = self.mainPostText.contentSize.height;
self.mainPostText.frame = _f;
Исправлена проблема с "лишней строкой" на 6+.
Ты спас мне день. Я боролся с расширением функции класса selfCalculating, забывая об этом. Спасибо.
@Ronnie, спасибо за ваш код, я использую ваш код, но когда мое содержимое textview достигает строки 2000, этот код замедляет работу моего приложения, вы можете сказать мне, почему?
@Ronnie, где мы должны писать этот код. Я хотел бы сначала отобразить одну строку кадра, и по мере того, как типы пользователей в кадре должны увеличиваться, чтобы разместить текст без прокрутки вверх.
Любопытнее: когда я уменьшаю текст, так что contentSize имеет высоту всего 79, добавляя 100, я получаю только 1 строку. Мне нужно добавить 200 - установить высоту UITextView на 279 - чтобы отобразить 3 строки.
Ага! Я устанавливал высоту текстового представления, а затем регулировал высоту содержащего представления. Видимо, когда я это делал, высота текстового представления регулировалась. Установка высоты содержащего представления сначала заставляет все работать так, как ожидалось (или, что лучше, надеялись).
Использование [_textView sizeToFit] обновляет свойство contentSize, удаляя требование заранее добавлять его в scrollView.
Вы также можете добавить frame.size.height + = (_textView.contentInset.top + _textView.contentInset.bottom); Если вы изменили contentInset, чтобы не оставлять пустую рамку вокруг текста.
_textView.scrollEnabled = НЕТ; тоже нужен. В противном случае я заканчивал смещение содержимого после новой строки.
Теперь, когда вы это сказали, это так очевидно. Я пытался рассчитать высоту с помощью sizeWithFont:forWidth:lineBreakMode, спасибо!
Это отличное решение, но оно не работает при использовании автоматического раскладки. Есть ли у вас какие-нибудь идеи, как добиться этого с включенным автоопределением?
Если вы используете автоматическое размещение, вызовите layoutIfNeeded в супервизоре. Затем вы можете взять высоту из contentSize.
Если вы заставили его работать на iOS 7, помогите, пожалуйста, в этом вопросе: stackoverflow.com/questions/19049532/…
Однако речь идет об изменении размера внешнего контейнера. Это поведение изменилось в iOS 7. В связанном вопросе я показываю, где добавить sizeToFit и layoutIfNeeded.
@HenrikErlandsson, ваш комментарий сэкономил мне сейчас много работы :)
У меня это не работает в 2016 году. Возможно, устарело. Высота содержимого всегда равна высоте кадра, даже когда я добавил addSubView.
Я нашел способ изменить высоту текстового поля в соответствии с текстом внутри него, а также расположить метку под ним в зависимости от высоты текстового поля! Вот код.
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];
Здесь '5' в координате Y UILabel - это промежуток, который я хочу между textView и Label.
если сюда попадет какой-либо другой, это решение сработает для меня, 1 «Ронни Лью» +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;
И это ... Ура
Это отлично сработало, когда мне нужно было подогнать текст в 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);
}
Если у вас нет под рукой 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 - это просто очень большой максимальный размер.
На практике вы можете добавить к высоте дополнительный font.leading; это добавляет пустую строку под вашим текстом, что может выглядеть лучше, если есть визуально тяжелые элементы управления непосредственно под текстовым представлением.
отличный результат в iOS 8.1
Прокладка была для меня ключом
Лучший способ, который я обнаружил, изменить размер высоты 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];
В 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;
}
}
Где я могу прочитать об этом подробнее? Я совершенно не понимаю, как выглядит новое поведение в iOS 7 по этому поводу.
Что означает переменная CGSize size?
Я снял размер, его там не должно было быть.
Для iOS 7.0 вместо настройки frame.size.height на contentSize.height (который в настоящее время ничего не делает) используйте [textView sizeToFit].
См. этот вопрос.
Это работает как для 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 в UITableViewCell. Работает действительно здорово. Это единственный ответ, который, наконец, сработал для меня. Спасибо!
Мне был нужен textview.scrollEnabled = NO;, чтобы текст не обрезался даже в iOS 7.
Я рекомендую использовать макрос CGFLOAT_MAX вместо MAXFLOAT. Правильно на обеих 32/64 битных платформах.
это сработало для меня, но затем, когда я пытаюсь прокрутить родительский вид до textView, когда пользователь переходит на его редактирование, происхождение отключено ...
Пришлось отключить автоматический макет для моего файла пера, чтобы это работало правильно, иначе первый и второй символы новой строки искажали размер текстового представления.
Также вы можете использовать INFINITY вместо CGFLOAT_MAX и MAXFLOAT. Выглядит смешнее
Тот, кто сталкивается с небольшими колебаниями перед вводом в следующую строку, добавляет этот `NSRange bottom = NSMakeRange (textView.text.length -1, 1); [textView scrollRangeToVisible: внизу]; `
Сработало отлично !! ПРИМЕЧАНИЕ для использования Autolayout: мне пришлось сначала установить верхнее / нижнее пространство для ограничений супервизора, чтобы это работало.
Почему в версии Swift есть два отдельных вызова sizeThatFits (...)? Для чего первая строчка?
Если у кого-то есть проблема с изменением размера, поместите этот код выше, чтобы переопределить метод func layoutSubviews ().
Это прекрасно работает. Был сбит с толку на несколько минут, потому что у меня все еще было установлено ограничение автопложности высоты в IB для текстового представления, но после его удаления все в порядке.
в этом методе есть ошибка в ios 9. размер текстового представления достигает нормальной высоты при выборе текста из текстового представления
Просто не забудьте добавить это в viewDidLayoutSubviews, а не в viewWillAppear
Когда textview.scrollEnabled = NO; Мой курсор не виден, после ввода первого символа он становится видимым. Когда прокрутка включена, при вводе текста верхний текст прокручивается слишком сильно (чрезмерная прокрутка), после ввода первого символа прокрутка исправляется сама. Поэтому оставление прокрутки включенной и использование этой строки исправляет это для меня: NSRange bottom = NSMakeRange (textView.text.length -1, 1); [textView scrollRangeToVisible: внизу]; Как написал aiay_nasa.
Это отлично работает, просто не забудьте убедиться, что у вас не установлены ограничения по высоте для TextView в построителе интерфейса.
Размер отлично выглядит в отладчике пользовательского интерфейса, но текст не переносится - я поместил это в initWithFrame, может быть, в этом проблема?
В качестве альтернативы установите ограничение высоты textView равным расчетной высоте.
Что касается предложения @ DanielKuta, обратите внимание, что layoutSubviews () - это функция UIView, отлично подходит, если вы подклассифицируете текстовое представление или родительский объект. Если вы делаете это в контроллере представления, вам нужно viewWillLayoutSubviews ().
для дальнейшего использования. Если вы используете Autolayout, проверьте ответ Alok, это все, что вам нужно, так просто.
Я не думаю, что это может преодолеть ограничения. Как указать это изначально в ограничении раскадровки? У меня даже нет динамического текста; просто статично.
этот метод, кажется, работает для ios7
// Code from apple developer forum - @Steve Krulewitz, @Mark Marszal, @Eric Silverberg
- (CGFloat)measureHeight
{
if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)])
{
CGRect frame = internalTextView.bounds;
CGSize fudgeFactor;
// The padding added around the text on iOS6 and iOS7 is different.
fudgeFactor = CGSizeMake(10.0, 16.0);
frame.size.height -= fudgeFactor.height;
frame.size.width -= fudgeFactor.width;
NSMutableAttributedString* textToMeasure;
if (internalTextView.attributedText && internalTextView.attributedText.length > 0){
textToMeasure = [[NSMutableAttributedString alloc] initWithAttributedString:internalTextView.attributedText];
}
else{
textToMeasure = [[NSMutableAttributedString alloc] initWithString:internalTextView.text];
[textToMeasure addAttribute:NSFontAttributeName value:internalTextView.font range:NSMakeRange(0, textToMeasure.length)];
}
if ([textToMeasure.string hasSuffix:@"\n"])
{
[textToMeasure appendAttributedString:[[NSAttributedString alloc] initWithString:@"-" attributes:@{NSFontAttributeName: internalTextView.font}]];
}
// NSAttributedString class method: boundingRectWithSize:options:context is
// available only on ios7.0 sdk.
CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
return CGRectGetHeight(size) + fudgeFactor.height;
}
else
{
return self.internalTextView.contentSize.height;
}
}
Я опубликую правильное решение внизу страницы на тот случай, если кто-то осмелится (или достаточно отчаялся), чтобы дочитать до этого момента.
Вот репозиторий gitHub для тех, кто не хочет читать весь этот текст: resizableTextView
Это работает с 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];
Теперь наш класс выглядит так:
ResizableTextView.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];
Используйте CGFLOAT_MAX, а не FLT_MAX.
Хотел бы я дать вам больше одного голоса за это потрясающее решение !!
Чтобы сделать UITextView динамически изменяющимся размером внутри UITableViewCell, я обнаружил, что следующая комбинация работает в Xcode 6 с iOS 8 SDK:
UITextView к UITableViewCell и ограничьте его по бокамUITextViewscrollEnabled значение 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:.
Лучший ответ для меня. Работал отлично, и UITableViewAutomaticDimension был добавлен в iOS 5, поэтому он обратно совместим.
У меня не совсем сработало. Метод textViewDidChange заставляет мое представление таблицы подпрыгивать каждый раз, когда я набираю символ. Я предлагаю вместо использования этого метода в методе tableView: cellForRowAtIndexPath для строки с текстовым представлением на ней, если вы находитесь в режиме только для чтения, для параметра .scrollEnabled установлено значение NO, и если вы находитесь в режиме редактирования, установленном прокрутите до ДА. Таким образом, при простом отображении он всегда будет показывать полный текст, а при редактировании он будет начинаться с полного текста, и при добавлении следующего текста он останется того же размера, а предыдущий текст будет прокручиваться сверху.
кроме того, я добавил ограничение высоты> = в текстовое поле, так как пустое текстовое поле не имело высоты и его нельзя было нажать, чтобы начать редактирование.
Отличное решение. Для меня tableView.rowHeight = UITableViewAutomaticDimension был не нужен.
Еще раз спасибо, Бретт Дональд! Я забыл, как это сделать, и через год снова нашел ваш ответ ?.
Для всех, кто столкнется с этим ответом в будущем, главное, что вам нужно знать, это просто UITextView.scrollEnabled = @NO
Это заставляет экран подпрыгивать каждый раз при обновлении, как сказал @SimonTheDiver
Для тех, кто хочет, чтобы текстовое представление действительно двигалось вверх и сохраняло положение нижней строки
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);
}
Не уверен, почему люди всегда слишком усложняют: вот :
- (void)textViewDidChange:(UITextView *)textView{ CGRect frame = textView.frame;
CGFloat height = [self measureHeightOfUITextView:textView];
CGFloat insets = textView.textContainerInset.top + textView.textContainerInset.bottom;
height += insets;
frame.size.height = height;
if (frame.size.height > textView.frame.size.height){
CGFloat diff = frame.size.height - textView.frame.size.height;
textView.frame = CGRectMake(5, 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(5, textView.frame.origin.y + diff, textView.frame.size.width, frame.size.height);
}
[textView setNeedsDisplay];
}
Ребята, использующие автопрокладку, а ваш sizetofit не работает, тогда проверьте ограничение ширины один раз. Если вы пропустили ограничение ширины, высота будет точной.
Нет необходимости использовать какой-либо другой API. всего одна строчка решила бы всю проблему.
[_textView sizeToFit];
Здесь меня интересовала только высота, сохраняя фиксированную ширину, и я пропустил ограничение ширины моего TextView в раскадровке.
И это должно было показать динамический контент из сервисов.
Надеюсь, это поможет ..
вот быстрая версия @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
Вопрос действительно зависит от языка. Действительно ли необходимо возвращаться и писать быстрые порты для всех ответов на вопросы, связанные с UIKit? Похоже, это способствует шумному разговору.
проблема в том, что у большинства этих вопросов нет определенного языка программирования, поэтому вы найдете его в Google, даже если будете искать быстрый язык
Единственный код, который будет работать, - это тот, который использует 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.
Извините, что значит: let attribute = [NSFontAttributeName: textView.text.font!] Это действительно Swift-код без ошибок?) Вы имели в виду let attribute = [NSFontAttributeName: textView.font!]
Начиная с iOS 8, можно использовать функции автоматического макета UITableView для автоматического изменения размера UITextView без какого-либо специального кода. Я поместил в github проект, который демонстрирует это в действии, но вот ключ:
rowHeight на UITableViewAutomaticDimension.
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = self.tableView.rowHeight;
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
Подобные ответы не приветствуются. Вы должны разместить здесь соответствующий код.
Быстрый :
textView.sizeToFit()
Кроме того, я обнаружил, что мне нужно установить для параметра scrolling enabled значение false, чтобы это работало. textView.scrollEnabled = false
Не забудьте вызвать textView.layoutIfNeeded () после textView.sizeToFit ()
@tmarkiewicz Это работает, когда текст умещается на экране вашего устройства, но это будет проблемой, когда ваш текст больше, чем место на экране. Вы не сможете прокрутить его, чтобы увидеть остальной текст.
Это ответ !!! Нет необходимости в более сложных решениях !!! @FranciscoRomero Почему бы не поместить текстовое представление в ячейку таблицы или ячейку представления коллекций, тогда вы всегда можете прокрутить таблицу или представление коллекций ....
Самый простой способ спросить UITextView - это просто вызвать -sizeToFit, он должен работать и с scrollingEnabled = YES, после этого проверьте высоту и добавьте ограничение высоты в текстовом представлении с тем же значением.
Обратите внимание, что UITexView содержит вставки, это означает, что вы не можете спросить строковый объект, сколько места он хочет использовать, потому что это всего лишь ограничивающий прямоугольник текста.
Все люди, которые испытывают неправильный размер при использовании -sizeToFit, вероятно, из-за того, что текстовое представление еще не было размечено до размера интерфейса.
Это всегда происходит, когда вы используете классы размера и UITableView, при первом создании ячеек в - tableView:cellForRowAtIndexPath: вы получаете размер любой конфигурации, если вы вычислите свое значение только сейчас, текстовое представление будет иметь ширину, отличную от ожидаемый, и это будет винт всех размеров.
Чтобы решить эту проблему, я счел полезным переопределить метод ячейки -layoutSubviews для пересчета высоты текстового представления.
Если вы используете режим прокрутки и представление содержимого и хотите увеличить высоту в зависимости от высоты содержимого TextView, этот фрагмент кода вам поможет.
Надеюсь, это поможет, он отлично работал в iOS9.2.
ну и конечно же установить textview.scrollEnabled = NO;
-(void)adjustHeightOfTextView
{
//this pieces of code will helps to adjust the height of the uitextview View W.R.T content
//This block of code work will calculate the height of the textview text content height and calculate the height for the whole content of the view to be displayed.Height --> 400 is fixed,it will change if you change anything in the storybord.
CGSize textViewSize = [self.textview sizeThatFits:CGSizeMake(self.view.frame.size.width, self.view.frame.size.height)];//calulcate the content width and height
float textviewContentheight =textViewSize.height;
self.scrollview.contentSize = CGSizeMake(self.textview.frame.size.width,textviewContentheight + 400);//height value is passed
self.scrollview.frame =CGRectMake(self.scrollview.frame.origin.x, self.scrollview.frame.origin.y, self.scrollview.frame.size.width, textviewContentheight+400);
CGRect Frame = self.contentview.frame;
Frame.size.height = textviewContentheight + 400;
[self.contentview setFrame:Frame];
self.textview.frame =CGRectMake(self.textview.frame.origin.x, self.textview.frame.origin.y, self.textview.frame.size.width, textviewContentheight);
[ self.textview setContentSize:CGSizeMake( self.textview.frame.size.width,textviewContentheight)];
self.contenview_heightConstraint.constant =
self.scrollview.bounds.size.height;
NSLog(@"%f",self.contenview_heightConstraint.constant);
}
Мы можем сделать это с помощью ограничений.
2. Создайте IBOutlet для этого ограничения высоты.
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *txtheightconstraints;
3. не забудьте установить делегата для вашего текстового просмотра.
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;
}];
}
затем обновите свое ограничение следующим образом :)
это ФАНТАСТИЧЕСКИЙ ник!
За установкой константы должен следовать [textView layoutIfNeeded]; в блоке анимации. (Анимация автоматического раскладки делает это именно так.)
Очень простое рабочее решение, использующее как код, так и раскадровку.
По коду
textView.scrollEnabled = false
По раскадровке
Снимите флажок Прокрутка включить
Не нужно ничего делать, кроме этого.
Это правильный ответ. В StoryBoard у вас есть TextView AutoSize, как и в UILabel. Все, что нам нужно сделать, это установить scrollEnabled = false.
По сути, это правильно: если вы используете ограничения Autolayout и отключаете прокрутку, все работает.
Большое спасибо. Это было так просто, просто отключите прокрутку в раскадровке или коде, это будет как UILabel со строками 0.
@Mansuu .... Это не гарантированное решение, так как есть вещи, которые вы можете сделать, чтобы переопределить внутренний размер содержимого, и если вы измените текст после размещения представления, он не будет обновляться, если вы не установите это тоже вверх. Но эти вещи остаются верными и для установки numberOfLines = 0 в текстовом поле. Если это не сработает, вероятно, у вас есть другие ограничения, которые неявно устанавливают высоту.
Ваш ответ приемлемый, но если мы добавим ограничение по высоте, это не сработает.
@iOS, если вы добавляете ограничение по высоте, сделайте приоритет ограничений ниже, иначе это не сработает.
Объяснение, почему это работает: stackoverflow.com/a/65861960/815742
Я просмотрел все ответы, и все они сохраняют фиксированную ширину и регулируют только высоту. Если вы хотите отрегулировать также ширину, вы можете очень легко использовать этот метод:
поэтому при настройке текстового представления отключите прокрутку
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)
}
Выходы:
метод делегата не вызывается @Peter Stajger
Вот ответ, если вам нужно динамически изменить размер textView и tableViewCell в staticTableView
Работает как шарм на ios 11 а я работаю в ячейке, как в чат-ячейке с пузырем.
let content = UITextView(frame: CGRect(x: 4, y: 4, width: 0, height: 0))
content.text = "what ever short or long text you wanna try"
content.textAlignment = NSTextAlignment.left
content.font = UIFont.systemFont(ofSize: 13)
let spaceAvailable = 200 //My cell is fancy I have to calculate it...
let newSize = content.sizeThatFits(CGSize(width: CGFloat(spaceAvailable), height: CGFloat.greatestFiniteMagnitude))
content.isEditable = false
content.dataDetectorTypes = UIDataDetectorTypes.all
content.isScrollEnabled = false
content.backgroundColor = UIColor.clear
bkgView.addSubview(content)
Примечание. Таким образом, этот ответ просто подчеркивает, что вам не нужно использовать CGFloat.greatestFiniteMagnitude, если вы ограничены определенной шириной или высотой -> spaceAvailable в моем случае может быть максимальной шириной экрана - Интервалы и ширина других меток или минимальная ширина экрана все зависит от того, что я показываю ...
отключить прокрутку
добавить константы
и добавьте свой текст
[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. Swift 3.0 и выше.
UITextView к View. Я добавляю это с помощью кода, вы можете добавить через конструктор интерфейсов.UITextViewDelegatefunc textViewDidChange(_ textView: UITextView) для настройки размера TextViewКод:
//1. Add your UITextView in ViewDidLoad
let textView = UITextView()
textView.frame = CGRect(x: 0, y: 0, width: 200, height: 100)
textView.backgroundColor = .lightGray
textView.text = "Here is some default text."
//2. Add constraints
textView.translatesAutoresizingMaskIntoConstraints = false
[
textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
textView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
textView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
textView.heightAnchor.constraint(equalToConstant: 50),
textView.widthAnchor.constraint(equalToConstant: 30)
].forEach{ $0.isActive = true }
textView.font = UIFont.preferredFont(forTextStyle: .headline)
textView.delegate = self
textView.isScrollEnabled = false
textViewDidChange(textView)
//3. Implement the delegate method.
func textViewDidChange(_ textView: UITextView) {
let size = CGSize(width: view.frame.width, height: .infinity)
let estimatedSize = textView.sizeThatFits(size)
textView.constraints.forEach { (constraint) in
if constraint.firstAttribute == .height {
print("Height: ", estimatedSize.height)
constraint.constant = estimatedSize.height
}
}
}
Это довольно просто с наблюдением ключевого значения (KVO), просто создайте подкласс UITextView и выполните:
private func setup() { // Called from init or somewhere
fitToContentObservations = [
textView.observe(\.contentSize) { _, _ in
self.invalidateIntrinsicContentSize()
},
// For some reason the content offset sometimes is non zero even though the frame is the same size as the content size.
textView.observe(\.contentOffset) { _, _ in
if self.contentOffset != .zero { // Need to check this to stop infinite loop
self.contentOffset = .zero
}
}
]
}
public override var intrinsicContentSize: CGSize {
return contentSize
}
Если вы не хотите создавать подклассы, вы можете попробовать выполнить textView.bounds = textView.contentSize в обозревателе contentSize.
Это отлично работает для Swift 5, если вы хотите подогнать свой TextView, когда пользователь напишет текст на лету.
Просто реализуйте UITextViewDelegate с помощью:
func textViewDidChange(_ textView: UITextView) {
let newSize = textView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))
textView.frame.size = CGSize(width: newSize.width, height: newSize.height)
}
Самый простой способ - использовать UITextViewDelegate:
func textViewDidChange(_ textView: UITextView) {
textView.sizeToFit()
textviewHeight.constant = textView.contentSize.height
}
Самым простым решением, которое сработало для меня, было наложить ограничение высоты на textView в раскадровке, а затем подключить textView и ограничение высоты к коду:
@IBOutlet var myAwesomeTextView: UITextView!
@IBOutlet var myAwesomeTextViewHeight: NSLayoutConstraint!
Затем, после установки стилей текста и абзаца, добавьте это в viewDidAppear:
self.myAwesomeTextViewHeight.constant = self.myAwesomeTextView.contentSize.height
Некоторые примечания:
Похоже, этот парень понял это для NSTextView, и его ответ применим и к iOS. Оказывается, intrinsicContentSize не синхронизируется с менеджером компоновки. Если макет происходит после intrinsicContentSize, у вас может быть несоответствие.
Его легко исправить.
NSTextView в NSOutlineView с установкой IntrinsicContentSize неправильной высоты
Пожалуйста, подумайте об обновлении правильного ответа, так как принятый приводит к ненужным вычислениям, теперь для этой проблемы есть свойство contentSize.