Как определить размер UITextView для его содержимого на iOS 7?



Я использую принятый ответ здесь в течение многих лет.



на iOS 7, contentSize.высота становится рамкой.высота-8, независимо от содержания текста.



каков метод работы для регулировки высоты на iOS 7?

700   13  

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, является просто заполнителем (т. е. установите флажок "удалить во время сборки").

enter image description here

альтернативный способ реализации 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 на "конечное пространство".

enter image description here

ребята, использующие 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

    Ничего не найдено.