iOS7 UITextView contentsize.альтернатива высоты


Я портирую одно из приложений с iOS 6.1 на iOS 7. Я использую макет, где есть UITextView Это имеет фиксированную ширину, но его высота основана на его contentsize. Для iOS 6.1 проверка contentsize.высота и установка его в качестве высоты кадра textview было достаточно, но он не работает на iOS 7.

Как я могу тогда создать UITextView с фиксированной шириной, но динамической высотой на основе текста, который он показывает?

примечание: Я создаю эти представления из кода, а не с Конструктор Интерфейсов.

9 76

9 ответов:

С помощью этого кода Вы можете изменить высоту вашего UITextView в зависимости от фиксированной ширины (он работает на iOS 7 и предыдущей версии):

- (CGFloat)textViewHeightForAttributedText:(NSAttributedString *)text andWidth:(CGFloat)width
{
    UITextView *textView = [[UITextView alloc] init];
    [textView setAttributedText:text];
    CGSize size = [textView sizeThatFits:CGSizeMake(width, FLT_MAX)];
    return size.height;
}

С помощью этой функции вы возьмете NSAttributedString и фиксированную ширину, чтобы вернуть необходимую высоту.

если вы хотите вычислить кадр из текста с определенным шрифтом, вам нужно использовать следующий код:

- (CGSize)text:(NSString *)text sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
{
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
    {
        CGRect frame = [text boundingRectWithSize:size
                                          options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
                                       attributes:@{NSFontAttributeName:font}
                                          context:nil];
        return frame.size;
    }
    else
    {
        return [text sizeWithFont:font constrainedToSize:size];
    }
}

вы можете добавить, что SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO на ваш префикс.PCH файл в вашем проекте как:

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

вы также можете заменить предыдущий тест SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) by:

if ([text respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)])‌

это сработало для меня для iOS6 и 7:

CGSize textViewSize = [self.myTextView sizeThatFits:CGSizeMake(self.myTextView.frame.size.width, FLT_MAX)];
    self.myTextView.height = textViewSize.height;

в iOS7, UITextView использует NSLayoutManager макет текста:

// If YES, then the layout manager may perform glyph generation and layout for a given portion of the text, without having glyphs or layout for preceding portions.  The default is NO.  Turning this setting on will significantly alter which portions of the text will have glyph generation or layout performed when a given generation-causing method is invoked.  It also gives significant performance benefits, especially for large documents.
@property(NS_NONATOMIC_IOSONLY) BOOL allowsNonContiguousLayout;

отключить allowsNonContiguousLayout исправить contentSize:

textView.layoutManager.allowsNonContiguousLayout = NO;

используйте эту маленькую функцию

-(CGSize) getContentSize:(UITextView*) myTextView{
    return [myTextView sizeThatFits:CGSizeMake(myTextView.frame.size.width, FLT_MAX)];
}

мое окончательное решение основано на HotJard, но включает в себя как верхние, так и нижние вставки текстового контейнера вместо использования 2*fabs(textView.contentInset.сверху) :

- (CGFloat)textViewHeight:(UITextView *)textView
{
    return ceilf([textView.layoutManager usedRectForTextContainer:textView.textContainer].size.height +
                 textView.textContainerInset.top +
                 textView.textContainerInset.bottom);
}

есть более простое решение, используя этот метод:

+(void)adjustTextViewHeightToContent:(UITextView *)textView;
{
    if([[UIDevice currentDevice].systemVersion floatValue] >= 7.0f){
        textView.height = [textView.layoutManager usedRectForTextContainer:textView.textContainer].size.height+2*fabs(textView.contentInset.top);
    }else{
        textView.height = textView.contentSize.height;
    }
}

UPD: работает только для отображения текста (isEditable = NO)

   _textView.textContainerInset = UIEdgeInsetsZero;
   _textView.textContainer.lineFragmentPadding = 0;

просто не забудьте lineFragmentPadding

простое решение - textView.isScrollEnabled = false отлично работает, когда внутри другого вида прокрутки или ячейки tableView с UITableViewAutomaticDimension

@Ana's, @ Blake Hamilton решение в Свифт.

var contentHeight: CGFloat = textView.sizeThatFits(textView.frame.size).height

хорошая вещь для меня было то, что это также возвращает правильный contentSize, когда isScrollEnable имеет значение false. Значение false возвращает размер кадра текстового представления вместо размера содержимого.