Перш за все, дуже важливо зазначити, що між 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не знайшли, перевірте оновлену версію функції.