Prima di tutto, è molto importante notare che c'è una grande differenza tra UITextView e UILabel quando si tratta di come il testo viene reso. Non solo UITextView ha inserti su tutti i bordi, ma anche il layout del testo al suo interno è leggermente diverso.
Pertanto, sizeWithFont:
è un brutto modo per utilizzare UITextViews.
Invece esso UITextView
stesso ha una funzione chiamata sizeThatFits:
che restituirà la dimensione più piccola necessaria per visualizzare tutti i contenuti UITextView
all'interno di un riquadro di delimitazione, che puoi specificare.
Quanto segue funzionerà allo stesso modo sia per iOS 7 che per le versioni precedenti e al momento non include alcun metodo, che è deprecato.
Soluzione semplice
- (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;
}
Questa funzione prenderà a NSAttributedString
e la larghezza desiderata come a CGFloat
e restituirà l'altezza necessaria
Soluzione dettagliata
Dato che di recente ho fatto qualcosa di simile, ho pensato di condividere anche alcune soluzioni ai problemi connessi che ho riscontrato. Spero che possa aiutare qualcuno.
Questo è molto più approfondito e coprirà quanto segue:
- Certamente: impostare l'altezza di un in
UITableViewCell
base alla dimensione necessaria per visualizzare l'intero contenuto di un contenutoUITextView
- Rispondi alle modifiche del testo (e anima le modifiche di altezza della riga)
- Mantenere il cursore all'interno dell'area visibile e mantenere il primo risponditore
UITextView
attivo durante il ridimensionamento UITableViewCell
durante la modifica
Se stai lavorando con una vista tabella statica o hai solo un numero noto di UITextView
s, puoi potenzialmente rendere il passaggio 2 molto più semplice.
1. Innanzitutto, sovrascrivi 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. Definisci la funzione che ha calcolato l'altezza necessaria:
Aggiungi un NSMutableDictionary
(in questo esempio chiamato textViews
) come variabile di istanza alla tua UITableViewController
sottoclasse.
Usa questo dizionario per memorizzare i riferimenti all'individuo in questo UITextViews
modo:
(e sì, indexPaths sono chiavi valide per i dizionari )
- (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;
}
Questa funzione ora calcolerà l'altezza effettiva:
- (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. Abilita il ridimensionamento durante la modifica
Per le prossime due funzioni, è importante che il delegato di UITextViews
sia impostato sul tuo UITableViewController
. Se hai bisogno di qualcos'altro come delegato, puoi aggirare il problema effettuando le chiamate pertinenti da lì o utilizzando gli hook NSNotificationCenter appropriati.
- (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. Seguire il cursore durante la modifica
- (void)textViewDidBeginEditing:(UITextView *)textView {
[self scrollToCursorForTextView:textView];
}
Questo farà UITableView
scorrere fino alla posizione del cursore, se non è all'interno del Rect visibile di 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. Regolare il rettangolo visibile, impostando gli inserti
Durante la modifica, alcune parti UITableView
potrebbero essere coperte dalla tastiera. Se i riquadri delle visualizzazioni di tabella non vengono regolati, scrollToCursorForTextView:
non sarà possibile scorrere fino al cursore, se si trova nella parte inferiore della visualizzazione di tabella.
- (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 ultima parte:
All'interno della tua visualizzazione è stata caricata, iscriviti alle notifiche per le modifiche alla tastiera tramite 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];
}
Per favore, non arrabbiarti con me, per aver dato questa risposta così a lungo. Sebbene non tutto sia necessario per rispondere alla domanda, credo che ci siano altre persone a cui queste questioni direttamente correlate saranno utili.
AGGIORNARE:
Come ha sottolineato Dave Haupert, ho dimenticato di includere la rectVisible
funzione:
- (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);
}
Inoltre ho notato che scrollToCursorForTextView:
includeva ancora un riferimento diretto a uno dei TextField nel mio progetto. Se hai un problema con il bodyTextView
non essere trovato, controlla la versione aggiornata della funzione.