Trước hết, điều rất quan trọng cần lưu ý là có sự khác biệt lớn giữa UITextView và UILabel khi nói đến cách văn bản được hiển thị. UITextView không chỉ có nội dung trên tất cả các đường viền mà cả bố cục văn bản bên trong nó cũng hơi khác một chút.
Do đó, đây sizeWithFont:
là một cách tồi để sử dụng UITextViews.
Thay vào đó, UITextView
bản thân nó có một hàm được gọi là hàm sizeThatFits:
này sẽ trả về kích thước nhỏ nhất cần thiết để hiển thị tất cả nội dung UITextView
bên trong hộp giới hạn mà bạn có thể chỉ định.
Các phương pháp sau sẽ hoạt động như nhau cho cả iOS 7 và các phiên bản cũ hơn và tính đến thời điểm hiện tại không bao gồm bất kỳ phương pháp nào không được dùng nữa.
Giải pháp đơn giản
- (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;
}
Hàm này sẽ lấy a NSAttributedString
và chiều rộng mong muốn là a CGFloat
và trả về chiều cao cần thiết
Giải pháp chi tiết
Vì gần đây tôi đã làm điều gì đó tương tự, tôi nghĩ tôi cũng sẽ chia sẻ một số giải pháp cho các Vấn đề được kết nối mà tôi gặp phải. Tôi hy vọng nó sẽ giúp ai đó.
Điều này chuyên sâu hơn nhiều và sẽ bao gồm những điều sau:
- Tất nhiên: đặt chiều cao của a
UITableViewCell
dựa trên kích thước cần thiết để hiển thị đầy đủ nội dung của mộtUITextView
- Phản hồi các thay đổi văn bản (và tạo hiệu ứng cho các thay đổi về độ cao của hàng)
- Giữ con trỏ bên trong vùng hiển thị và giữ người trả lời đầu tiên ở chế độ
UITextView
thay đổi kích thước UITableViewCell
trong khi chỉnh sửa
Nếu bạn đang làm việc với chế độ xem bảng tĩnh hoặc bạn chỉ có một số UITextView
s đã biết, bạn có thể thực hiện bước 2 đơn giản hơn nhiều.
1. Đầu tiên, hãy ghi đè 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. Xác định hàm tính toán chiều cao cần thiết:
Thêm một NSMutableDictionary
(trong ví dụ này được gọi là textViews
) dưới dạng một biến thể hiện vào UITableViewController
lớp con của bạn .
Sử dụng từ điển này để lưu trữ các tham chiếu đến cá nhân UITextViews
như vậy:
(và vâng, indexPath là khóa hợp lệ cho từ điển )
- (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;
}
Hàm này bây giờ sẽ tính toán chiều cao thực tế:
- (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. Bật Thay đổi kích thước trong khi Chỉnh sửa
Đối với hai hàm tiếp theo, điều quan trọng là đại biểu của hàm UITextViews
được đặt thành của bạn UITableViewController
. Nếu bạn cần một cái gì đó khác với tư cách là người được ủy quyền, bạn có thể giải quyết vấn đề đó bằng cách thực hiện các lệnh gọi liên quan từ đó hoặc sử dụng các móc NSNotificationCenter thích hợp.
- (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. Theo dõi con trỏ trong khi Chỉnh sửa
- (void)textViewDidBeginEditing:(UITextView *)textView {
[self scrollToCursorForTextView:textView];
}
Điều này sẽ làm cho UITableView
cuộn đến vị trí của con trỏ, nếu nó không nằm trong Rect có thể nhìn thấy của 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. Điều chỉnh trực tràng có thể nhìn thấy, bằng cách cài đặt các bộ phận
Trong khi chỉnh sửa, các phần của bạn UITableView
có thể bị Bàn phím che mất. Nếu nội dung của chế độ xem bảng không được điều chỉnh, scrollToCursorForTextView:
sẽ không thể cuộn đến con trỏ của bạn, nếu con trỏ ở cuối chế độ xem bảng.
- (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];
}
Và phần cuối cùng:
Bên trong chế độ xem của bạn đã tải, hãy đăng ký Thông báo cho các thay đổi trên Bàn phím thông qua 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];
}
Xin đừng giận tôi, vì đã làm câu trả lời này quá lâu. Mặc dù không phải tất cả đều cần thiết để trả lời câu hỏi, nhưng tôi tin rằng có những người khác, những người mà những vấn đề liên quan trực tiếp này sẽ hữu ích.
CẬP NHẬT:
Như Dave Haupert đã chỉ ra, tôi đã quên bao gồm rectVisible
hàm:
- (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);
}
Ngoài ra, tôi nhận thấy, điều đó scrollToCursorForTextView:
vẫn bao gồm một tham chiếu trực tiếp đến một trong các Trường Văn bản trong dự án của tôi. Nếu bạn gặp sự cố bodyTextView
không tìm thấy, hãy kiểm tra phiên bản cập nhật của chức năng.