ก่อนอื่นสิ่งสำคัญคือต้องทราบว่ามีความแตกต่างอย่างมากระหว่าง 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. ปรับ rect ที่มองเห็นได้โดยการตั้งค่าสิ่งที่ใส่เข้าไป
ในขณะที่แก้ไขบางส่วนของคุณ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];
}
โปรดอย่าโกรธฉันที่ตอบคำถามนี้มานาน แม้ว่าจะไม่จำเป็นต้องตอบคำถามทั้งหมด แต่ฉันเชื่อว่ามีคนอื่น ๆ ที่เกี่ยวข้องโดยตรงกับปัญหาเหล่านี้จะเป็นประโยชน์
UPDATE:
ดังที่ Dave Haupert ชี้ให้เห็นฉันลืมใส่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
ไม่พบให้ตรวจสอบเวอร์ชันอัปเดตของฟังก์ชัน