Como dimensiono um UITextView para seu conteúdo no iOS 7?

Eu tenho usado a resposta aceita aqui por anos.

No iOS 7, o contentSize.height se torna o frame.height-8, independentemente do conteúdo de texto.

O que é um método de trabalho para ajustar a altura no iOS 7?

Eu sou a favor dessa mudança mínima de código: basta adicionar essas duas linhas após o addSubview e antes de pegar a height do frame

 ... [scrollView1 addSubview: myTextView]; [myTextView sizeToFit]; //added [myTextView layoutIfNeeded]; //added CGRect frame = myTextView.frame; ... 

Isso é testado com compatibilidade retroativa com o iOS 6. OBSERVE que ele encolhe a largura. Se você estiver interessado apenas na altura e tiver uma largura fixa, basta pegar a nova altura, mas definir a largura original, e ela funciona exatamente como antes no iOS 6 e 7.

(Especulação: ele faz tamanho para caber no iOS 7 também, mas o layout é atualizado mais tarde ou em um thread separado, e isso força o layout imediatamente para que seu quadro seja atualizado a tempo de usar seu valor de altura algumas linhas depois no mesmo segmento.)

NOTAS:

1) Você pode ou não ter implementado o redimensionamento do contêiner externo dessa maneira. Parece ser um trecho comum, e eu usei em meus projetos.

2) Como sizeToFit parece funcionar como esperado no iOS 7, provavelmente você não precisa do addSubView prematuro. Se ainda funcionará no iOS 6, então não foi testado por mim.

3) Especulação: O meio-fio extra layoutIfNeeded pode ser caro. A alternativa que vejo é resize o contêiner externo no retorno de chamada do layout (triggersdo ou não, dependendo de o SO decidir se o layout é necessário ou não), em que o redimensionamento do contêiner externo causará outra atualização de layout. Ambas as atualizações podem ser combinadas com outras atualizações de layout para serem mais eficientes. Se você tiver essa solução e puder mostrar que ela é mais eficiente, adicione-a como resposta e mencionarei aqui.

Como estou usando o Auto Layout, eu uso o valor de [textView sizeThatFits:CGSizeMake(textView.frame.size.width, CGFLOAT_MAX)].height para atualizar a constant da altura UILayoutConstraint .

Eu uso uma versão adaptada da resposta do madmik que elimina o fator fudge:

 - (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; } } 

Com base em outras respostas, fiz com que funcionasse (no Swift). Isso resolve o problema com o caractere de nova linha.

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

Auto Layout é necessário.

Se você estiver usando o Auto Layout, poderá criar uma subclass UITextView comum que auto dimensiona a altura da exibição de texto para se ajustar ao conteúdo:

 @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 

É claro que a largura e a posição da visão de texto devem ser definidas por restrições adicionais configuradas em outras partes do programa.

Se você criar esta textview personalizada no IB, dê à textview uma restrição de altura para satisfazer o Xcode; apenas certifique-se de que a restrição de altura criada no IB seja meramente um espaço reservado (isto é, marque a checkbox que diz “Remover no tempo de compilation”).

insira a descrição da imagem aqui

Uma maneira alternativa de implementar a subclass UITextView é a seguinte (essa implementação pode ser qualificada como melhor prática):

 @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 

Se você estiver usando o layout automático, poderá usar a seguinte subclass UITextView que adiciona uma altura intrínseca:

 @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 

esse método parece funcionar.

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

Se você estiver usando o iOS 7+, basta ativar o layout automático, fixar cada um dos lados da exibição de texto na extremidade da visualização principal e funcionar bem. Nenhum código adicional é necessário.

No iOS 8, você herdará algum deslocamento de conteúdo do pai, do qual também precisa se livrar.

Um exemplo de subclass

 // 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 

No storyboard, se estiver usando restrições, verifique se está restrito à sua super visão na guia ‘régua’ do painel à direita no xcode do UITextView. Meu problema era que eu tinha uma restrição de -80 pts no ‘Espaço à direita’.

insira a descrição da imagem aqui

Os indivíduos que usam o autolayout e o seu sizetofit não estão funcionando, então, verifique sua restrição de largura uma vez. Se você perdeu a restrição de largura, a altura será precisa.

Não há necessidade de usar qualquer outra API. apenas uma linha resolveria todo o problema.

 [_textView sizeToFit]; 

Aqui, eu estava preocupado apenas com a altura, mantendo a largura fixa e tinha perdido a restrição de largura do meu TextView no storyboard.

E isso foi para mostrar o conteúdo dynamic dos serviços.

Espero que isso possa ajudar ..

Eu escrevi uma categoria sobre o UITextView :

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

Quando o UIKit define seu contentSize , o UITextView ajusta seu intrinsic content size . Isso funciona muito bem com autolayout .

A resposta dada pelo bilobatum funcionou perfeitamente com o layout automático, ou seja, a subclass da visão de texto.

Se você quiser limitar a altura da textview, adicione outra restrição (adicionei-a usando o storyboard, ou seja, altura <= 166 (altura conforme sua necessidade))

Em seguida, dentro da subclass, reduza a prioridade de restrição de altura para 750 (self.heightConstraint.priority = 750) para evitar conflito entre a restrição de altura adicionada na subclass e a restrição de altura adicionada no storyboard.

Intereting Posts