Antes de tudo, é muito importante observar que há uma grande diferença entre o UITextView e o UILabel quando se trata de como o texto é renderizado. O UITextView não apenas possui inserções em todas as bordas, mas também o layout do texto dentro dele é um pouco diferente.
Portanto, sizeWithFont:
é um caminho ruim para o UITextViews.
Em vez disso, UITextView
ele próprio possui uma função chamada sizeThatFits:
que retornará o menor tamanho necessário para exibir todo o conteúdo da UITextView
caixa delimitadora que você pode especificar.
O seguinte funcionará igualmente para as versões iOS 7 e anteriores e, a partir de agora, não inclui nenhum método que foi preterido.
Solução Simples
- (CGFloat)textViewHeightForAttributedText: (NSAttributedString*)text andWidth: (CGFloat)width {
UITextView *calculationView = [[UITextView alloc] init];
[calculationView setAttributedText:text];
CGSize size = [calculationView sizeThatFits:CGSizeMake(width, FLT_MAX)];
return size.height;
}
Esta função terá ae NSAttributedString
a largura desejada como ae CGFloat
retornará a altura necessária
Solução detalhada
Como fiz recentemente algo semelhante, pensei em compartilhar algumas soluções para os problemas conectados que encontrei. Espero que ajude alguém.
Isso é muito mais profundo e abrangerá o seguinte:
- Obviamente: definir a altura de um com
UITableViewCell
base no tamanho necessário para exibir o conteúdo completo de um contidoUITextView
- Responder a alterações de texto (e animar as alterações de altura da linha)
- Mantendo o cursor dentro da área visível e mantendo o primeiro respondedor
UITextView
ao redimensionar UITableViewCell
enquanto edita
Se você estiver trabalhando com uma exibição de tabela estática ou tiver apenas um número conhecido de UITextView
s, poderá potencialmente tornar a etapa 2 muito mais simples.
1. Primeiro, substitua o heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// check here, if it is one of the cells, that needs to be resized
// to the size of the contained UITextView
if ( )
return [self textViewHeightForRowAtIndexPath:indexPath];
else
// return your normal height here:
return 100.0;
}
2. Defina a função que calculou a altura necessária:
Adicione um NSMutableDictionary
(neste exemplo chamado textViews
) como uma variável de instância à sua UITableViewController
subclasse.
Use este dicionário para armazenar referências à pessoa da seguinte UITextViews
maneira:
(e sim, indexPaths são chaves válidas para dicionários )
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Do you cell configuring ...
[textViews setObject:cell.textView forKey:indexPath];
[cell.textView setDelegate: self]; // Needed for step 3
return cell;
}
Esta função agora calcula a altura real:
- (CGFloat)textViewHeightForRowAtIndexPath: (NSIndexPath*)indexPath {
UITextView *calculationView = [textViews objectForKey: indexPath];
CGFloat textViewWidth = calculationView.frame.size.width;
if (!calculationView.attributedText) {
// This will be needed on load, when the text view is not inited yet
calculationView = [[UITextView alloc] init];
calculationView.attributedText = // get the text from your datasource add attributes and insert here
textViewWidth = 290.0; // Insert the width of your UITextViews or include calculations to set it accordingly
}
CGSize size = [calculationView sizeThatFits:CGSizeMake(textViewWidth, FLT_MAX)];
return size.height;
}
3. Ative o redimensionamento durante a edição
Para as próximas duas funções, é importante que o delegado da UITextViews
seja definido como seu UITableViewController
. Se você precisar de outra coisa como delegado, poderá contorná-lo fazendo as chamadas relevantes a partir daí ou usando os ganchos apropriados do NSNotificationCenter.
- (void)textViewDidChange:(UITextView *)textView {
[self.tableView beginUpdates]; // This will cause an animated update of
[self.tableView endUpdates]; // the height of your UITableViewCell
// If the UITextView is not automatically resized (e.g. through autolayout
// constraints), resize it here
[self scrollToCursorForTextView:textView]; // OPTIONAL: Follow cursor
}
4. Siga o cursor enquanto edita
- (void)textViewDidBeginEditing:(UITextView *)textView {
[self scrollToCursorForTextView:textView];
}
Isso fará a UITableView
rolagem para a posição do cursor, se não estiver dentro do Rect visível do UITableView:
- (void)scrollToCursorForTextView: (UITextView*)textView {
CGRect cursorRect = [textView caretRectForPosition:textView.selectedTextRange.start];
cursorRect = [self.tableView convertRect:cursorRect fromView:textView];
if (![self rectVisible:cursorRect]) {
cursorRect.size.height += 8; // To add some space underneath the cursor
[self.tableView scrollRectToVisible:cursorRect animated:YES];
}
}
5. Ajuste o retângulo visível, definindo inserções
Durante a edição, partes do seu UITableView
podem ser cobertas pelo teclado. Se as inserções das visualizações de tablaturas não forem ajustadas, scrollToCursorForTextView:
não será possível rolar para o cursor, se estiver na parte inferior da visualização de tablatura.
- (void)keyboardWillShow:(NSNotification*)aNotification {
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(self.tableView.contentInset.top, 0.0, kbSize.height, 0.0);
self.tableView.contentInset = contentInsets;
self.tableView.scrollIndicatorInsets = contentInsets;
}
- (void)keyboardWillHide:(NSNotification*)aNotification {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.35];
UIEdgeInsets contentInsets = UIEdgeInsetsMake(self.tableView.contentInset.top, 0.0, 0.0, 0.0);
self.tableView.contentInset = contentInsets;
self.tableView.scrollIndicatorInsets = contentInsets;
[UIView commitAnimations];
}
E última parte:
Dentro da sua visualização, carregue, inscreva-se nas notificações para alterações do teclado através de NSNotificationCenter
:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
Por favor, não fique bravo comigo, por fazer essa resposta por tanto tempo. Embora nem tudo seja necessário para responder à pergunta, acredito que há outras pessoas para quem essas questões diretamente relacionadas serão úteis.
ATUALIZAR:
Como Dave Haupert apontou, eu esqueci de incluir a rectVisible
função:
- (BOOL)rectVisible: (CGRect)rect {
CGRect visibleRect;
visibleRect.origin = self.tableView.contentOffset;
visibleRect.origin.y += self.tableView.contentInset.top;
visibleRect.size = self.tableView.bounds.size;
visibleRect.size.height -= self.tableView.contentInset.top + self.tableView.contentInset.bottom;
return CGRectContainsRect(visibleRect, rect);
}
Também notei que isso scrollToCursorForTextView:
ainda incluía uma referência direta a um dos TextFields no meu projeto. Se você tiver um problema em bodyTextView
não ser encontrado, verifique a versão atualizada da função.