Как мне определить размер UITextView для его содержимого?
Есть ли хороший способ отрегулировать размер UITextView
соответствовать своему содержанию? Скажем, например, у меня есть UITextView
который содержит одну строку текста:
"Hello world"
Затем я добавляю еще одну строку текста:
"Goodbye world"
Есть ли хороший способ в Cocoa Touch, чтобы получить rect
что будет содержать все строки в текстовом представлении, чтобы я мог соответствующим образом настроить родительский вид?
В качестве другого примера посмотрите на поле заметок для событий в приложении Календарь - обратите внимание, как ячейка (и UITextView
он содержит) расширяется, чтобы содержать все строки текста в строке заметок.
41 ответ
Надеюсь это поможет:
- (void)textViewDidChange:(UITextView *)textView {
CGSize textSize = textview.contentSize;
if (textSize != textView.frame.size)
textView.frame.size = textSize;
}
Быстрый ответ: следующий код вычисляет высоту вашего 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
Для тех, кто хочет, чтобы текстовый вид действительно двигался вверх и поддерживал позицию нижней строки
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);
}
Самый простой способ спросить 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);
}
С наблюдением ключевого значения (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
наблюдатель.
Этот метод работает для 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;
}
}
Самым простым решением, которое сработало для меня, было наложить ограничение высоты на textView в раскадровке, а затем подключить textView и ограничение высоты к коду:
@IBOutlet var myAwesomeTextView: UITextView!
@IBOutlet var myAwesomeTextViewHeight: NSLayoutConstraint!
Затем, после установки стилей текста и абзаца, добавьте это в viewDidAppear:
self.myAwesomeTextViewHeight.constant = self.myAwesomeTextView.contentSize.height
Некоторые примечания:
- В отличие от других решений, для isScrollEnabled необходимо установить значение true, чтобы это работало.
- В моем случае я устанавливал пользовательские атрибуты для шрифта внутри кода, поэтому мне пришлось установить высоту в viewDidAppear (до этого он не работал должным образом). Если вы не меняете какие-либо атрибуты текста в коде, вы сможете установить высоту в viewDidLoad или в любом другом месте после установки текста.
Похоже, этот парень понял это для NSTextView, и его ответ применим и к iOS. Оказывается, intrinsicContentSize не синхронизируется с менеджером компоновки. Если макет происходит после intrinsicContentSize, у вас может быть несоответствие.
Его легко исправить.
NSTextView в NSOutlineView с установкой IntrinsicContentSize неправильной высоты
Вот шаги
Решение работает на всех версиях iOS. Swift 3.0 и выше.
- Добавьте свой
UITextView
кView
, Я добавляю его с кодом, вы можете добавить через конструктор интерфейса. - Добавить ограничения. Я добавляю ограничения в код, вы можете сделать это и в конструкторе интерфейсов.
- использование
UITextViewDelegate
методfunc 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 } } }
Не уверен, почему люди всегда слишком усложняют вещи: вот оно:
- (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];
}