Zunächst ist es sehr wichtig zu beachten, dass es einen großen Unterschied zwischen UITextView und UILabel gibt, wenn es darum geht, wie Text gerendert wird. UITextView verfügt nicht nur über Einfügungen an allen Rändern, sondern auch ein etwas anderes Textlayout.
Daher sizeWithFont:
ist UITextViews ein schlechter Weg.
Stattdessen hat UITextView
selbst eine Funktion aufgerufen, sizeThatFits:
die die kleinste Größe zurückgibt, die erforderlich ist, um den gesamten Inhalt UITextView
eines Begrenzungsrahmens anzuzeigen , den Sie angeben können.
Das Folgende funktioniert sowohl für iOS 7 als auch für ältere Versionen gleichermaßen und enthält derzeit keine veralteten Methoden.
Einfache Lösung
- (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;
}
Diese Funktion nimmt a NSAttributedString
und die gewünschte Breite als CGFloat
und gibt die benötigte Höhe zurück
Detaillierte Lösung
Da ich kürzlich etwas Ähnliches getan habe, dachte ich, ich würde auch einige Lösungen für die damit verbundenen Probleme teilen, auf die ich gestoßen bin. Ich hoffe es wird jemandem helfen.
Dies ist weitaus ausführlicher und wird Folgendes abdecken:
- Natürlich: Festlegen der Höhe von a
UITableViewCell
basierend auf der Größe, die zum Anzeigen des vollständigen Inhalts eines enthaltenen Inhalts erforderlich istUITextView
- Reagieren Sie auf Textänderungen (und animieren Sie die Höhenänderungen der Zeile).
- Halten Sie den Cursor im sichtbaren Bereich und halten Sie den Ersthelfer
UITextView
beim Ändern der Größe UITableViewCell
während der Bearbeitung auf
Wenn Sie mit einer statischen Tabellenansicht arbeiten oder nur eine bekannte Anzahl von UITextView
s haben, können Sie Schritt 2 möglicherweise viel einfacher gestalten.
1. Überschreiben Sie zunächst den 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. Definieren Sie die Funktion, die die benötigte Höhe berechnet hat:
Fügen Sie Ihrer Unterklasse eine NSMutableDictionary
(in diesem Beispiel als textViews
) Instanzvariable hinzu UITableViewController
.
Verwenden Sie dieses Wörterbuch, um Verweise auf die Person UITextViews
wie folgt zu speichern :
(und ja, indexPaths sind gültige Schlüssel für Wörterbücher )
- (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;
}
Diese Funktion berechnet nun die tatsächliche Höhe:
- (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. Aktivieren Sie die Größenänderung während der Bearbeitung
Für die nächsten beiden Funktionen ist es wichtig, dass der Delegat von UITextViews
auf Ihren eingestellt ist UITableViewController
. Wenn Sie als Delegat etwas anderes benötigen, können Sie dies umgehen, indem Sie die entsprechenden Anrufe von dort aus tätigen oder die entsprechenden NSNotificationCenter-Hooks verwenden.
- (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. Folgen Sie dem Cursor beim Bearbeiten
- (void)textViewDidBeginEditing:(UITextView *)textView {
[self scrollToCursorForTextView:textView];
}
Dadurch wird der UITableView
Bildlauf zur Position des Cursors ausgeführt, wenn er sich nicht im sichtbaren Bereich der UITableView befindet:
- (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. Stellen Sie das sichtbare Rechteck ein, indem Sie Einsätze einstellen
Während der Bearbeitung können Teile von Ihnen UITableView
von der Tastatur abgedeckt werden. Wenn die Tabellenansichten nicht angepasst sind, scrollToCursorForTextView:
kann nicht zum Cursor gescrollt werden, wenn er sich am unteren Rand der Tabellenansicht befindet.
- (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];
}
Und letzter Teil:
Melden Sie sich in Ihrer Ansicht, die geladen wurde, für die Benachrichtigungen für Tastaturänderungen an über 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];
}
Bitte sei nicht böse auf mich, weil ich diese Antwort so lange gemacht habe. Obwohl nicht alles zur Beantwortung der Frage benötigt wird, glaube ich, dass es andere Menschen gibt, denen diese direkt verwandten Themen hilfreich sein werden.
AKTUALISIEREN:
Wie Dave Haupert betonte, habe ich vergessen, die rectVisible
Funktion aufzunehmen:
- (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);
}
Ich bemerkte auch, dass dies scrollToCursorForTextView:
immer noch einen direkten Verweis auf eines der TextFields in meinem Projekt enthielt. Wenn Sie ein Problem damit haben, bodyTextView
nicht gefunden zu werden, überprüfen Sie die aktualisierte Version der Funktion.