it-swarm.com.ru

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

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

В iOS 7 contentSize.height становится frame.height-8 независимо от текстового содержимого.

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

64
Henrik Erlandsson

Я поддерживаю это минимальное изменение кода: просто добавьте эти две строки после addSubview и перед захватом heightframe

...
[scrollView1 addSubview: myTextView];

    [myTextView sizeToFit]; //added
    [myTextView layoutIfNeeded]; //added

CGRect frame = myTextView.frame;
...

Это проверено на обратную совместимость с iOS 6.NOTEчто он сокращает ширину. Если вас интересует только высота и фиксированная ширина, просто возьмите новую высоту, но установите оригинальную ширину, и она работает так же, как и раньше, на iOS 6 и 7.

(Предположение: он также подходит и для iOS 7, но макет обновляется позже или в отдельном потоке, и это сразу вынуждает макет, так что его фрейм обновляется во времени для использования значения высоты несколько раз строки позже в той же теме.)

ЗАМЕТКИ:

1) Вы могли или не могли бы реализовать изменение размера внешнего контейнера таким образом. Хотя, похоже, это обычный фрагмент кода, и я использовал его в своих проектах.

2) Поскольку sizeToFit в iOS 7 работает должным образом, скорее всего, вам не нужен преждевременный addSubView. Будет ли он работать на iOS 6, тогда я не проверял.

3) Предположение: дополнительная layoutIfNeeded середина может быть дорогостоящей. Альтернатива, как я вижу, состоит в изменении размера внешнего контейнера при обратном вызове макета (запускается или нет в зависимости от того, решает ли ОС, нужен ли макет), когда изменение размера внешнего контейнера вызовет другое обновление макета. Оба обновления могут быть объединены с другими обновлениями макета, чтобы быть более эффективными. Если у вас do есть такое решение, и вы можете показать, что оно более более эффективно, добавьте его в качестве ответа, и я обязательно упомяну его здесь.

55
Henrik Erlandsson

Так как я использую Auto Layout, я использую значение [textView sizeThatFits:CGSizeMake(textView.frame.size.width, CGFLOAT_MAX)].height для обновления constant высоты textViewUILayoutConstraint.

33
ma11hew28

Я использую адаптированную версию ответа 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;
    }
}
17
tarmes

Основываясь на других ответах, я заставил это работать (в Swift) . Это решает проблему с символом новой строки.

textView.sizeToFit()
textView.layoutIfNeeded()
let height = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max)).height
textView.contentSize.height = height

Авто макет нужен.

16
MKatleast3

Если вы используете 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
14
bilobatum

Если вы используете автоматическое размещение, вы можете использовать следующий подкласс 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
4
phatmann

этот метод, кажется, работает.

// 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;
}
}
3
madmik3

Если вы используете iOS 7+, вы можете просто включить автоматическую разметку, прикрепить каждую из сторон текстового представления к краю родительского представления, и оно работает нормально. Дополнительный код не требуется.

1
Swindler

В раскадровке, если используются ограничения, убедитесь, что вы ограничены своим суперпредставлением на вкладке «Линейка» правой панели в xcode для UITextView. Моя проблема заключалась в том, что у меня было ограничение -80 баллов на «Trailing space to». 

enter image description here

0
DanWebster

Ответ, данный bilobatum, отлично работал с автоматическим макетом, то есть подклассом textview.

Если вы хотите ограничить высоту текстового представления, добавьте еще одно ограничение (я добавил его, используя раскадровку, т.е. высоту <= 166 (высота в соответствии с вашими потребностями))

Затем внутри подкласса уменьшите приоритет ограничения высоты до 750 (self.heightConstraint.priority = 750), чтобы избежать конфликта между ограничением высоты, добавленным в подкласс, и ограничением высоты, добавленным в раскадровку.

0
Sunil Bhosale

В 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
0
Johan Forssell

Я написал категорию над UITextView:

- (CGSize)intrinsicContentSize {
    return self.contentSize;
}

- (void)setContentSize:(CGSize)contentSize {
    [super setContentSize:contentSize];
    [self invalidateIntrinsicContentSize];
}

Когда UIKit устанавливает свой contentSize, UITextView настраивает свой intrinsic content size. Это хорошо сочетается с autolayout.

0
Mert Buran

Ребята, использующие autolayout, и ваш sizetofit не работает, тогда, пожалуйста, проверьте ограничение ширины один раз. Если вы пропустили ограничение ширины, высота будет точной.

Нет необходимости использовать любой другой API. только одна строка решит все проблемы.

[_textView sizeToFit];

Здесь я интересовался только высотой, сохраняя фиксированную ширину и пропустив ограничение ширины моего TextView в раскадровке.

И это должно было показать динамический контент от сервисов.

Надеюсь, что это может помочь ..

0
Swaroop S