13 ответов:
Я за это минимальное изменение кода: просто добавьте эти две строки после
addSubviewи прежде чем хвататься заheightнаframe... [scrollView1 addSubview: myTextView]; [myTextView sizeToFit]; //added [myTextView layoutIfNeeded]; //added CGRect frame = myTextView.frame; ...это тестируется обратная совместимость с iOS 6. Примечание что он сжимает-обертывает ширину. Если вы просто заинтересованы в высоте и имеете фиксированную ширину, просто возьмите новую высоту, но установите исходную ширину, и она работает так же, как и раньше на iOS 6 и 7.
(спекуляция: он делает размер, чтобы соответствовать на iOS 7 также, но макет обновляется позже или в отдельном потоке, и это заставляет макет немедленно обновляться, чтобы его фрейм обновлялся вовремя для использования его значения высоты несколькими строками позже в том же потоке.)
Примечания:
1) вы могли бы или не могли бы реализовать внешний контейнер изменить размер таким образом. Это, кажется, общий фрагмент, хотя, и я использовал его в своих проектах.
2) с
sizeToFitкажется, работает, как ожидалось на iOS 7 вам, вероятно, не нужен преждевременный addSubView. Будет ли он по-прежнему работать на iOS 6, тогда я не проверял.3) спекуляция: лишний
layoutIfNeededсредний поток может быть дорогостоящим. Альтернативой, как я вижу, является изменение размера внешнего контейнера при обратном вызове макета (срабатывает или нет в зависимости от того, решает ли ОС, нужен ли макет или нет), где изменение размера внешнего контейнера вызовет другое обновление макета. Оба обновления могут быть объединены с другими обновлениями макета должен быть больше эффективный. Если вы сделать есть такое решение и вы можете показать, что он и более эффективно, добавьте его в качестве ответа, и я обязательно упомяну об этом здесь.
так как я использую Auto Layout, я использую значение
[textView sizeThatFits:CGSizeMake(textView.frame.size.width, CGFLOAT_MAX)].heightобновитьconstantнаtextView' s высотаUILayoutConstraint.
Я использую адаптированную версию ответа madmik, которая устраняет фактор выдумки:
- (CGFloat)measureHeightOfUITextView:(UITextView *)textView { if ([textView respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)]) { // This is the code for iOS 7. contentSize no longer returns the correct value, so // we have to calculate it. // // This is partly borrowed from HPGrowingTextView, but I've replaced the // magic fudge factors with the calculated values (having worked out where // they came from) CGRect frame = textView.bounds; // Take account of the padding added around the text. UIEdgeInsets textContainerInsets = textView.textContainerInset; UIEdgeInsets contentInsets = textView.contentInset; CGFloat leftRightPadding = textContainerInsets.left + textContainerInsets.right + textView.textContainer.lineFragmentPadding * 2 + contentInsets.left + contentInsets.right; CGFloat topBottomPadding = textContainerInsets.top + textContainerInsets.bottom + contentInsets.top + contentInsets.bottom; frame.size.width -= leftRightPadding; frame.size.height -= topBottomPadding; NSString *textToMeasure = textView.text; if ([textToMeasure hasSuffix:@"\n"]) { textToMeasure = [NSString stringWithFormat:@"%@-", textView.text]; } // NSString class method: boundingRectWithSize:options:attributes:context is // available only on ios7.0 sdk. NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; [paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping]; NSDictionary *attributes = @{ NSFontAttributeName: textView.font, NSParagraphStyleAttributeName : paragraphStyle }; CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil]; CGFloat measuredHeight = ceilf(CGRectGetHeight(size) + topBottomPadding); return measuredHeight; } else { return textView.contentSize.height; } }
основываясь на других ответах, я заставил его работать(в Swift). Это решает проблему с символом новой строки.
textView.sizeToFit() textView.layoutIfNeeded() let height = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max)).height textView.contentSize.height = heightтребуется автоматическая компоновка.
если вы используете Auto Layout, вы можете создать тривиальный
UITextViewподкласс, который самостоятельно определяет высоту текстового представления в соответствии с содержимым:@interface ContentHeightTextView : UITextView @end @interface ContentHeightTextView () @property (nonatomic, strong) NSLayoutConstraint *heightConstraint; @end @implementation ContentHeightTextView - (void)layoutSubviews { [super layoutSubviews]; CGSize size = [self sizeThatFits:CGSizeMake(self.bounds.size.width, FLT_MAX)]; if (!self.heightConstraint) { self.heightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0f constant:size.height]; [self addConstraint:self.heightConstraint]; } self.heightConstraint.constant = size.height; [super layoutSubviews]; } @endконечно, ширина и положение текстового представления должны определяться дополнительными ограничениями, настроенными в другом месте программы.
если вы создаете это пользовательское текстовое представление В IB, дайте текстовому представлению ограничение высоты для удовлетворения Xcode; просто убедитесь, что ограничение высоты, созданное в IB, является просто заполнителем (т. е. установите флажок "удалить во время сборки").
альтернативный способ реализации
UITextViewподкласс выглядит следующим образом (эта реализация может квалифицироваться как лучшая практика):@interface ContentHeightTextView () @property (nonatomic, strong) NSLayoutConstraint *heightConstraint; @end @implementation ContentHeightTextView - (void)layoutSubviews { [super layoutSubviews]; [self setNeedsUpdateConstraints]; } - (void)updateConstraints { CGSize size = [self sizeThatFits:CGSizeMake(self.bounds.size.width, FLT_MAX)]; if (!self.heightConstraint) { self.heightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0f constant:size.height]; [self addConstraint:self.heightConstraint]; } self.heightConstraint.constant = size.height; [super updateConstraints]; } @end
Если вы используете auto-layout, вы можете использовать следующий подкласс UITextView, который добавляет внутреннюю высоту:
@implementation SelfSizingTextView - (void)setText:(NSString *)text { [super setText:text]; [self invalidateIntrinsicContentSize]; } - (void)setFont:(UIFont *)font { [super setFont:font]; [self invalidateIntrinsicContentSize]; } - (CGSize)intrinsicContentSize { CGFloat width = self.frame.size.width; CGSize size = [self sizeThatFits:CGSizeMake(width, MAXFLOAT)]; return CGSizeMake(UIViewNoIntrinsicMetric, size.height); } @end
этот метод, кажется, работает.
// 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; } }
Если вы используете iOS 7+, Вы можете просто включить автоматическую компоновку, прикрепить каждую из сторон текстового представления к краю его родительского представления, и он отлично работает. Дополнительный код не требуется.
в iOS 8 вы унаследуете некоторое смещение контента от родителя, от которого Вам также нужно избавиться.
пример подкласса
// Originally from https://github.com/Nikita2k/resizableTextView #import "ResizableTextView.h" @implementation ResizableTextView - (void) updateConstraints { // calculate contentSize manually // ios7 doesn't calculate it before viewDidAppear and we'll get here before CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)]; // set the height constraint to change textView height [self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) { if (constraint.firstAttribute == NSLayoutAttributeHeight) { constraint.constant = contentSize.height; *stop = YES; } }]; [super updateConstraints]; } - (void)setContentOffset:(CGPoint)contentOffset { // In iOS 8 we seem to be inheriting the content offset from the parent. // I'm not interested } @end
в раскадровке, если вы используете ограничения, убедитесь, что вы ограничены своим супервизором на вкладке "линейка" правой панели на xcode для UITextView. Моя проблема заключалась в том, что у меня было ограничение -80 pts на "конечное пространство".
ребята, использующие autolayout и ваш sizetofit не работает, а затем, пожалуйста, проверьте ограничение ширины один раз. Если вы пропустили ограничение ширины, то высота будет точно.
нет необходимости использовать любой другой API. только одна строка исправит все проблемы.
[_textView sizeToFit];здесь я занимался только высотой, сохраняя фиксированную ширину и пропустил ограничение ширины моего TextView в раскадровке.
и это должно было показать динамическое содержимое из сервисы.
надеюсь, что это может помочь..
Я написал категорию над
UITextView:- (CGSize)intrinsicContentSize { return self.contentSize; } - (void)setContentSize:(CGSize)contentSize { [super setContentSize:contentSize]; [self invalidateIntrinsicContentSize]; }, когда
UIKitзадаетcontentSize,UITextViewнастраивает своюintrinsic content size. Это хорошо играет сautolayout.
ответ, данный bilobatum, отлично работал с автоматической компоновкой, т. е. подклассом textview.
Если вы хотите ограничить высоту текстового представления добавить еще одно ограничение (я добавил его с помощью раскадровки, т. е. высота
затем внутри подкласса уменьшите приоритет ограничения высоты до 750 (self.heightConstraint.priority = 750), чтобы избежать конфликта между ограничением высоты, добавленным в подкласс, и ограничением высоты, добавленным раскадровка.


Comments