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.
attributedText
bez określania czcionki, koloru i wyrównania tekstu prowadzi do ustawienia domyślnych wartości atrybutów NSAttributedString do textView. W moim przypadku powoduje to uzyskanie różnych wysokości widoku tekstu dla tego samego tekstu.Istnieje nowa funkcja zastępująca sizeWithFont, czyli boundingRectWithSize.
Dodałem następującą funkcję do mojego projektu, która korzysta z nowej funkcji na iOS7 i starej na iOS niższej niż 7. Ma w zasadzie taką samą składnię jak sizeWithFont:
Możesz dodać to IOS_NEWER_OR_EQUAL_TO_7 do swojego pliku prefix.pch w swoim projekcie jako:
źródło
Jeśli używasz UITableViewAutomaticDimension, mam naprawdę proste (tylko iOS 8) rozwiązanie. W moim przypadku jest to statyczny widok tabeli, ale myślę, że można go dostosować do dynamicznych prototypów ...
Mam wyjście ograniczenia dla wysokości widoku tekstu i zaimplementowałem następujące metody:
Ale pamiętaj : widok tekstu musi być przewijalny i musisz ustawić swoje ograniczenia tak, aby działały dla automatycznego wymiaru:
Najbardziej podstawowym przykładem komórki jest:
źródło
Odpowiedź Tima Bodeita jest świetna. Użyłem kodu Prostego rozwiązania, aby poprawnie uzyskać wysokość widoku tekstu i użyć tej wysokości w
heightForRowAtIndexPath
. Ale nie używam reszty odpowiedzi do zmiany rozmiaru widoku tekstu. Zamiast tego piszę kod, aby zmienićframe
widok tekstu wcellForRowAtIndexPath
.Wszystko działa w iOS 6 i niższych, ale w iOS 7 tekst w widoku tekstu nie może być w pełni pokazany, mimo że
frame
widok tekstu jest rzeczywiście zmieniony. (Nie używamAuto Layout
). To powinno być powodem, dla którego w iOS 7 istniejeTextKit
i pozycja tekstu jest kontrolowana przezNSTextContainer
wUITextView
. Więc w moim przypadku muszę dodać linię, aby ustawićsomeTextView
, aby działał poprawnie w iOS 7.Zgodnie z dokumentacją, to, co robi ta właściwość, to:
Jeśli pozostawisz wartość domyślną, po zmianie rozmiaru
frame
zsomeTextView
, rozmiartextContainer
nie zostanie zmieniony, co spowoduje, że tekst będzie wyświetlany tylko w obszarze przed zmianą rozmiaru.A może trzeba ustawić na
scrollEnabled = NO
wypadek, gdyby było ich więcejtextContainer
, aby tekst przepływał z jednegotextContainer
do drugiego.źródło
Oto jeszcze jedno rozwiązanie, które ma na celu prostotę i szybkie prototypowanie :
Ustawiać:
UITextView
z inną zawartością.TableCell.h
.UITableView
jest powiązany zTableViewController.h
.Rozwiązanie:
(1) Dodaj do
TableViewController.m
:(2) Dodaj do
TableCell.m
:Wyjaśnienie:
Więc to, co się tutaj dzieje, jest następujące: każdy widok tekstu jest powiązany z wysokością komórek tabeli przez ograniczenia pionowe i poziome - co oznacza, że gdy wzrasta wysokość komórki tabeli, widok tekstu również zwiększa swój rozmiar. Użyłem zmodyfikowanej wersji kodu @ manecosta, aby obliczyć wymaganą wysokość widoku tekstu, aby zmieścić podany tekst w komórce. Oznacza to, że dany tekst z liczbą X znaków
frameForText:
zwróci rozmiar, który będzie miał właściwośćsize.height
odpowiadającą wymaganej wysokości widoku tekstu.Teraz pozostaje tylko aktualizacja wysokości komórki, aby odpowiadała wymaganej wysokości widoku tekstu. I to osiąga się o godz
heightForRowAtIndexPath:
. Jak zauważono w komentarzach, ponieważsize.height
jest to tylko wysokość widoku tekstu, a nie cała komórka, należy dodać do niej przesunięcie. W przypadku przykładu ta wartość wynosiła 80.źródło
dream.dream
był tekstem, który renderowałem w widoku tekstu.Jedną z metod, jeśli używasz automatycznego układu, jest umożliwienie silnikowi automatycznego układania obliczenia rozmiaru za Ciebie. Nie jest to najbardziej wydajne podejście, ale jest całkiem wygodne (i prawdopodobnie najbardziej dokładne). Staje się to wygodniejsze, gdy rośnie złożoność układu komórki - np. Nagle masz dwa lub więcej widoków tekstu / pól w komórce.
Odpowiedziałem na podobne pytanie z pełną próbką rozmiaru komórek widoku tabeli przy użyciu układu automatycznego, tutaj:
Jak zmienić rozmiar nadzoru, aby dopasować wszystkie podglądy do automatycznego układu?
źródło
Całkowicie gładkie rozwiązanie jest następujące.
Najpierw potrzebujemy klasy komórki z tekstem textView
Następnie używamy go w TableViewController
Tutaj
minLines
pozwala ustawić minimalną wysokość dla textView (aby zapobiec minimalizacji wysokości przez AutoLayout z UITableViewAutomaticDimension).moveRowAtIndexPath:indexPath:
z tym samym indexPath uruchamia ponowne obliczenie wysokości tableViewCell i zmianę układu.performWithoutAnimation:
usuwa efekt uboczny (przesunięcie zawartości tableView przeskakuje przy rozpoczynaniu nowej linii podczas pisania).Ważne jest, aby zachować
relativeFrameOriginY
(niecontentOffsetY
!) Podczas aktualizacji komórki, ponieważcontentSize
komórki, zanim bieżąca komórka może zostać zmieniona przez rachunek autoLayout w nieoczekiwany sposób. Usuwa wizualne skoki przy dzieleniu wyrazów systemowych podczas wpisywania długich słów.Pamiętaj, że nie powinieneś ustawiać właściwości
estimatedRowHeight
! Poniższe nie działaUżywaj tylko metody tableViewDelegate.
==================================================== ========================
Jeśli ktoś nie ma nic przeciwko słabemu wiązaniu między tableView i tableViewCell i aktualizowaniu geometrii tableView z tableViewCell , można zaktualizować
TextInputTableViewCell
klasę powyżej:źródło
Wysokość twojej komórki zostanie obliczona na podstawie zawartości UILabel, ale cały tekst zostanie wyświetlony przez TextField.
źródło
Myślę, że w ten sposób możesz policzyć wysokość widoku tekstu, a następnie zmienić rozmiar komórki widoku tabeli zgodnie z tą wysokością, abyś mógł wyświetlić pełny tekst w komórce
źródło
Szybka wersja
źródło
Jeśli chcesz automatycznie dopasować
UITableViewCell
wysokość na podstawie wysokości wewnętrznejUITextView
wysokości. Zobacz moją odpowiedź tutaj: https://stackoverflow.com/a/45890087/1245231Rozwiązanie jest dość proste i powinno działać od iOS 7. Upewnij się, że
Scrolling Enabled
opcja jest wyłączona dlaUITextView
wnętrzaUITableViewCell
w StoryBoard.Następnie w Twoim viewDidLoad () UITableViewControllera ustaw
tableView.rowHeight = UITableViewAutomaticDimension
itableView.estimatedRowHeight > 0
takie jak:Otóż to.
UITableViewCell
Wysokość zostanie automatycznie dostosowana na podstawie wysokości wewnętrznejUITextView
.źródło
W przypadku iOS 8 i nowszych możesz po prostu użyć
your_tablview.estimatedrowheight= minheight
chceszźródło