Как определить размер 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 покрывает+ только:
только с 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
' sscrollEnabled
свойство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:
в моем (ограниченном) опыте,
- (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
к высоте; это добавляет пустую строку под вашим текстом, которая может выглядеть лучше, если есть визуально тяжелые элементы управления непосредственно под видом текста.
достаточно следующих вещей:
- только не забудьте установить прокрутка to нет для
UITextView
:
- правильно установить ограничения автоматической компоновки.
вы даже можете использовать UITableViewAutomaticDimension
.
мы можем сделать это с помощью ограничений .
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 это демонстрирует это в действии, но вот ключ:
- в UITextView должна быть отключена прокрутка, что можно сделать программно или через построитель интерфейса. Он не будет изменять размер, если прокрутка включена, потому что прокрутка позволяет просматривать больше содержание.
- в viewDidLoad для UITableViewController вы должны установить значение для estimatedRowHeight, а затем установить
rowHeight
toUITableViewAutomaticDimension
.
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = self.tableView.rowHeight;
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
- целью развертывания проекта должна быть 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)
}
выходы:
отключить прокрутку
добавить 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