Как настроить UITextView на его содержимое?
Есть ли хороший способ настроить размер UITextView
для соответствия его содержимому? Скажем, например, у меня есть UITextView
, который содержит одну строку текста:
"Hello world"
Затем я добавляю еще одну строку текста:
"Goodbye world"
Есть ли хороший способ в Cocoa Коснитесь, чтобы получить rect
, который будет содержать все строки в текстовом представлении, чтобы я мог соответствующим образом настроить родительское представление?
В качестве другого примера рассмотрим поле примечаний для событий в приложении "Календарь" - обратите внимание на то, как ячейка (и содержащаяся в ней UITextView
) расширяется, чтобы удерживать все строки текста в строке примечаний.
Ответы
Ответ 1
Это работает как для 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;
Ответ 2
Это больше не работает на 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 +:
Только с 6+ (а не 5 или 6) он добавляет "еще одну пустую строку" в UITextView. "Решение RL" прекрасно фиксирует это:
CGRect _f = self.mainPostText.frame;
_f.size.height = self.mainPostText.contentSize.height;
self.mainPostText.frame = _f;
Он исправляет проблему "дополнительной строки" на 6 +.
Ответ 3
Чтобы сделать динамический размер UITextView
внутри a UITableViewCell
, я обнаружил, что следующая комбинация работает в Xcode 6 с iOS 8 SDK:
- Добавьте
UITextView
в UITableViewCell
и привяжите его к сторонам
- Задайте для свойства
UITextView
scrollEnabled
значение NO
. При включенной прокрутке кадр UITextView
не зависит от его размера содержимого, но при отключенной прокрутке существует взаимосвязь между ними.
-
Если ваша таблица использует исходную высоту строки по умолчанию 44, она автоматически вычисляет высоту строки, но если вы измените высоту строки по умолчанию на что-то еще, вам может потребоваться вручную включить автоматический подсчет строки высоты в viewDidLoad
:
tableView.estimatedRowHeight = 150;
tableView.rowHeight = UITableViewAutomaticDimension;
Для динамического определения размера UITextView
s только для чтения, вот оно. Если вы разрешаете пользователям редактировать текст в UITextView
, вам также необходимо:
-
Внедрите метод textViewDidChange:
протокола UITextViewDelegate
и сообщите tableView
перекрашивать себя каждый раз, когда текст редактируется:
- (void)textViewDidChange:(UITextView *)textView;
{
[tableView beginUpdates];
[tableView endUpdates];
}
-
И не забудьте указать делегат UITextView
где-нибудь, либо в Storyboard
, либо в tableView:cellForRowAtIndexPath:
Ответ 4
Очень простое рабочее решение с использованием кода и раскадровки.
По коду
textView.scrollEnabled = false
По раскадровке
Снимите флажок Включение прокрутки
Не нужно ничего делать кроме этого.
Ответ 5
Swift:
textView.sizeToFit()
Ответ 6
В моем (ограниченном) опыте
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
не уважает символы новой строки, поэтому вы можете получить намного меньше CGSize
, чем требуется.
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
похоже, уважает строки новой строки.
Кроме того, текст фактически не отображается в верхней части UITextView
. В моем коде я установил новую высоту UITextView
на 24 пикселя больше высоты, возвращаемой методами sizeOfFont
.
Ответ 7
В 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;
}
}
Ответ 8
Я отправлю правильное решение в нижней части страницы, если кто-то храбр (или отчаялся достаточно), чтобы прочитать это.
Вот репозиторий gitHub для тех, кто не хочет читать весь этот текст: resizableTextView
Это работает с iOs7 (и я уверен, что он будет работать с iOs8) и с автозапуском. Вам не нужны магические числа, отключите макет и прочее. Короткое и элегантное решение.
Я думаю, что весь связанный с ограничением код должен перейти к методу 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.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];
}
Довольно и чисто, правда? И вам не нужно иметь дело с этим кодом в контроллерах!
Но подождите!
Y NO ANIMATION!
Вы можете легко анимировать изменения, чтобы сделать 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];
Ответ 9
Вы попробовали [textView sizeThatFits:textView.bounds]
?
Изменить: sizeThatFits возвращает размер, но фактически не изменяет размер компонента. Я не уверен, что это то, что вы хотите, или если [textView sizeToFit]
больше того, что вы искали. В любом случае, я не знаю, будет ли он идеально соответствовать содержимому, как вы хотите, но это первое, что нужно попробовать.
Ответ 10
Другой метод - найти размер, который определенная строка займет с помощью метода NSString
:
-(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
Возвращает размер прямоугольника, который соответствует данной строке с заданным шрифтом. Передайте размер с требуемой шириной и максимальной высотой, а затем вы можете посмотреть высоту, возвращаемую в соответствии с текстом. Существует версия, которая позволяет также указать режим прерывания строки.
Затем вы можете использовать возвращаемый размер, чтобы изменить размер вашего представления, чтобы он соответствовал.
Ответ 11
Если у вас нет UITextView
под рукой (например, вы просматриваете ячейки таблицы размеров), вам нужно будет вычислить размер, измерив строку, а затем учтите, стороне a 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
к высоте; это добавляет пустую строку под вашим текстом, что может выглядеть лучше, если есть визуально тяжелые элементы управления прямо под текстовым представлением.
Ответ 12
Достаточно вещей:
- Не забудьте установить прокрутку НЕТ для
UITextView
:
- Правильно установите автоматические ограничения компоновки.
Вы даже можете использовать UITableViewAutomaticDimension
.
Ответ 13
Мы можем сделать это с помощью ограничений.
- Установить ограничения высоты для UITextView.
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;
}];
}
затем обновите свое ограничение следующим образом:)
Ответ 14
В сочетании с ответом Майка Макмастера вы можете сделать что-то вроде:
[myTextView setDelegate: self];
...
- (void)textViewDidChange:(UITextView *)textView {
if (myTextView == textView) {
// it changed. Do resizing here.
}
}
Ответ 15
Я узнал способ изменить размер текстового поля в соответствии с текстом внутри него, а также расположить метку под ним в зависимости от высоты текстового поля! Вот код.
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];
Ответ 16
Ребята, использующие автозапуск и ваш sizetofit, не работают, пожалуйста, проверьте один раз ограничение ширины. Если вы пропустили ограничение ширины, высота будет точной.
Не нужно использовать какой-либо другой API. только одна строка исправит всю проблему.
[_textView sizeToFit];
Здесь меня беспокоила только высота, сохраняя фиксированную ширину и пропустив ограничение ширины моего TextView в раскадровке.
И это должно было показать динамический контент из сервисов.
Надеюсь, это поможет.
Ответ 17
Начиная с iOS 8, можно использовать функции автоматического макета UITableView для автоматического изменения размера UITextView без какого-либо настраиваемого кода. Я разместил проект в github, который демонстрирует это в действии, но вот ключ:
- В UITextView должна быть отключена прокрутка, которую вы можете выполнять программно или через конструктор интерфейса. Он не будет изменяться, если прокрутка включена, потому что прокрутка позволяет просматривать более крупный контент.
- В viewDidLoad для UITableViewController вы должны установить значение для оценочногоRowHeight, а затем установить
rowHeight
в UITableViewAutomaticDimension
.
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = self.tableView.rowHeight;
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
- Цель развертывания проекта должна быть iOS 8 или выше.
Ответ 18
Это работало хорошо, когда мне нужно было сделать текст в 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);
}
Ответ 19
вот быстрая версия @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
Ответ 20
Я просмотрел все ответы, и все они фиксируют ширину и регулируют только высоту. Если вы хотите настроить также ширину, вы можете очень легко использовать этот метод:
поэтому при настройке текстового вида отключите прокрутку
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)
}
Выходы:
Ответ 21
отключить прокрутку
добавлять константы
и добавьте текст
[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;
}
Ответ 22
Для iOS 7.0 вместо установки frame.size.height
в contentSize.height
(который в настоящее время ничего не делает) используйте [textView sizeToFit]
.
См. этот вопрос.
Ответ 23
Надеюсь, что это поможет:
- (void)textViewDidChange:(UITextView *)textView {
CGSize textSize = textview.contentSize;
if (textSize != textView.frame.size)
textView.frame.size = textSize;
}
Ответ 24
если какой-либо другой получить здесь, это решение работает для меня, 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;
И это... Cheers
Ответ 25
Лучший способ, который я обнаружил, чтобы изменить размер 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];
Ответ 26
Для тех, кто хочет, чтобы текстовое изображение действительно продвигалось вверх и поддерживало нижнюю позицию.
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);
}
Ответ 27
Единственный код, который будет работать, - это тот, который использует "SizeToFit", как в ответе на jhibberd выше, но на самом деле он не подберет, если вы не назовете его в ViewDidAppear или подключите его к тексту UITextView изменен событие.
Ответ 28
Основываясь на ответе Никиты Ток, я пришел к следующему решению в 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
}
}
}
Ответ 29
Быстрый ответ:
Следующий код вычисляет высоту вашего 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
Ответ 30
Вот ответ, если вам нужно динамически изменять размеры textView
и tableViewCell
в staticTableView
[fooobar.com/info/9519/...