Перш за все, дуже важливо зазначити, що між UITextView та UILabel існує велика різниця, коли мова йде про те, як відображається текст. Не тільки UITextView має вставки на всіх кордонах, але і макет тексту всередині нього дещо інший.
Тому sizeWithFont:
для UITextViews це поганий спосіб.
Натомість UITextView
сама функція називається, sizeThatFits:
яка повертає найменший розмір, необхідний для відображення всього вмісту UITextView
всередині обмежувального поля, яке ви можете вказати.
Наведене нижче буде працювати однаково як для iOS 7, так і для старих версій, і на даний момент не включає жодних методів, які застаріли.
Просте рішення
- (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;
}
Ця функція прийме а NSAttributedString
і потрібну ширину як a CGFloat
і поверне потрібну висоту
Детальне рішення
Оскільки я нещодавно робив щось подібне, я думав, що також поділюсь деякими рішеннями пов'язаних з нами проблем. Сподіваюся, це комусь допоможе.
Це набагато глибше і охоплює наступне:
- Звичайно: встановлення висоти на
UITableViewCell
основі розміру, необхідного для відображення повного вмісту вміщеногоUITextView
- Відповідь на зміни тексту (і анімуйте зміни висоти рядка)
- Зберігання курсору у видимій області та збереження першого відповіді на
UITextView
час зміни розміру під UITableViewCell
час редагування
Якщо ви працюєте зі статичним поданням таблиці або у вас є лише відома кількість UITextView
s, потенційно ви можете зробити крок 2 набагато простішим.
1. Спочатку перезапишіть висотуForRowAtIndexPath:
- (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. Визначте функцію, яка обчислила необхідну висоту:
Додайте NSMutableDictionary
(у цьому прикладі називається textViews
) змінну екземпляра до своєїUITableViewController
підкласу.
Використовуйте цей словник для зберігання посилань на людину, UITextViews
як-от так:
(і так, indexPaths є дійсними ключами для словників )
- (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;
}
Ця функція тепер обчислить фактичну висоту:
- (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. Увімкніть зміну розміру під час редагування
Для наступних двох функцій важливо, щоб делегат параметра UITextViews
був встановлений на ваш UITableViewController
. Якщо вам потрібен ще делегат як делегат, ви можете обійти його, здійснивши відповідні дзвінки звідти або використовуючи відповідні гачки 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. Під час редагування слідкуйте за курсором
- (void)textViewDidBeginEditing:(UITextView *)textView {
[self scrollToCursorForTextView:textView];
}
Це зробить UITableView
прокрутку до позиції курсора, якщо він не знаходиться всередині видимого Rect of 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. Відрегулюйте видиму пряму ділянку, встановивши вставки
Під час редагування частини Вашого UITableView
пристрою можуть бути охоплені клавіатурою. Якщо вставки таблиці перегляду не скориговані, scrollToCursorForTextView:
не вдасться прокрутити курсор, якщо він знаходиться в нижній частині таблиці.
- (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];
}
І остання частина:
Всередині вашого перегляду завантажилися, підпишіться на сповіщення про зміни клавіатури через 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];
}
Будь ласка, не гнівайтесь на мене, тому що я відповідав так довго. Хоча для відповіді на це питання не все, я вважаю, що є й інші люди, яким ці корисні питання будуть корисні.
ОНОВЛЕННЯ:
Як зауважив Дейв Хауперт, я забув включити rectVisible
функцію:
- (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);
}
Також я помітив, що scrollToCursorForTextView:
все ще містив пряме посилання на одне з TextFields у своєму проекті. Якщо у вас є проблема з тим, що його bodyTextView
не знайшли, перевірте оновлену версію функції.