Przede wszystkim należy zauważyć, że istnieje duża różnica między UITextView i UILabel, jeśli chodzi o sposób renderowania tekstu. UITextView nie tylko ma wstawki na wszystkich krawędziach, ale także układ tekstu w nim jest nieco inny.
Dlatego sizeWithFont:
jest to zły sposób, aby przejść do UITextViews.
Zamiast tego UITextView
sama ma funkcję o nazwie, sizeThatFits:
która zwraca najmniejszy rozmiar potrzebny do wyświetlenia całej zawartości UITextView
wewnątrz obwiedni, którą możesz określić.
Poniższe działania będą działać tak samo dla iOS 7 i starszych wersji i od tej pory nie obejmują żadnych metod, które są przestarzałe.
Proste rozwiązanie
- (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;
}
Ta funkcja przyjmie a NSAttributedString
i żądaną szerokość jako a CGFloat
i zwróci wymaganą wysokość
Szczegółowe rozwiązanie
Ponieważ ostatnio zrobiłem coś podobnego, pomyślałem, że podzielę się również rozwiązaniami dla powiązanych problemów, które napotkałem. Mam nadzieję, że to komuś pomoże.
Jest to o wiele bardziej szczegółowe i obejmuje następujące zagadnienia:
- Oczywiście: ustawienie wysokości na
UITableViewCell
podstawie rozmiaru potrzebnego do wyświetlenia pełnej zawartości zawartegoUITextView
- Reaguj na zmiany tekstu (i animuj zmiany wysokości wiersza)
- Utrzymywanie kursora wewnątrz widocznego obszaru i utrzymywanie pierwszej osoby na pozycji
UITextView
podczas zmiany rozmiaru UITableViewCell
podczas edycji
Jeśli pracujesz ze statycznym widokiem tabeli lub masz tylko znaną liczbę UITextView
s, możesz potencjalnie znacznie uprościć krok 2.
1. Najpierw nadpisz 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. Zdefiniuj funkcję, która obliczyła potrzebną wysokość:
Dodaj NSMutableDictionary
(w tym przykładzie o nazwie textViews
) jako zmienną instancji do swojej UITableViewController
podklasy.
Użyj tego słownika, aby przechowywać odniesienia do osoby, w następujący UITextViews
sposób:
(i tak, indexPaths to prawidłowe klucze do słowników )
- (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;
}
Ta funkcja obliczy teraz rzeczywistą wysokość:
- (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. Włącz zmianę rozmiaru podczas edycji
W przypadku następnych dwóch funkcji ważne jest, aby delegat UITextViews
był ustawiony na twoją UITableViewController
. Jeśli potrzebujesz czegoś innego jako delegata, możesz to obejść, wykonując z tego miejsca odpowiednie wywołania lub używając odpowiednich punktów zaczepienia 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. Podążaj za kursorem podczas edycji
- (void)textViewDidBeginEditing:(UITextView *)textView {
[self scrollToCursorForTextView:textView];
}
Spowoduje to UITableView
przewinięcie do pozycji kursora, jeśli nie znajduje się on wewnątrz widocznego Recta 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. Dostosuj widoczny prostokąt, ustawiając wypustki
Podczas edycji niektóre elementy UITableView
mogą być zakryte przez klawiaturę. Jeśli wstawki widoku tabeli nie zostaną dostosowane, scrollToCursorForTextView:
nie będzie można przewinąć do kursora, jeśli znajduje się on na dole widoku tabeli.
- (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];
}
I ostatnia część:
Wewnątrz widoku załadowano, zarejestruj się, aby otrzymywać powiadomienia o zmianach klawiatury poprzez 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];
}
Proszę, nie złość się na mnie za tak długą odpowiedź. Chociaż nie wszystko jest potrzebne, aby odpowiedzieć na to pytanie, uważam, że są inne osoby, którym te bezpośrednio związane kwestie będą pomocne.
AKTUALIZACJA:
Jak zauważył Dave Haupert, zapomniałem dodać rectVisible
funkcji:
- (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);
}
Zauważyłem również, że scrollToCursorForTextView:
nadal zawierało bezpośrednie odniesienie do jednego z pól TextField w moim projekcie. Jeśli masz problem z bodyTextView
nie znalezieniem, sprawdź zaktualizowaną wersję funkcji.