Прежде всего, очень важно отметить, что существует большая разница между 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;
}
Эта функция примет a NSAttributedString
и желаемую ширину как a CGFloat
и вернет необходимую высоту.
Подробное решение
Поскольку я недавно сделал нечто подобное, я подумал, что также поделюсь некоторыми решениями связанных проблем, с которыми я столкнулся. Надеюсь, это кому-нибудь поможет.
Это гораздо более подробно и будет охватывать следующее:
- Конечно: установка высоты на
UITableViewCell
основе размера, необходимого для отображения полного содержимого содержащегосяUITextView
- Реагировать на изменения текста (и анимировать изменение высоты строки)
- Удерживая курсор внутри видимой области и удерживая первого респондента на
UITextView
значке при изменении размера во UITableViewCell
время редактирования
Если вы работаете со статическим табличным представлением или у вас есть только известное количество UITextView
s, вы потенциально можете значительно упростить шаг 2.
1. Сначала перезапишите 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. Определите функцию, которая вычисляет необходимую высоту:
Добавьте 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 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
текста может быть закрыта клавиатурой. Если вставки tableviews не скорректированы, scrollToCursorForTextView:
вы не сможете прокручивать курсор до вашего курсора, если он находится в нижней части tableview.
- (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:
в моем проекте все еще есть прямая ссылка на одно из текстовых полей. Если у вас возникла проблема с тем, что вас bodyTextView
не нашли, проверьте обновленную версию функции.