まず、テキストのレンダリング方法に関して、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
と目的の幅を として取り、CGFloat
必要な高さを返します。
詳細なソリューション
私は最近似たようなことをしたので、私が遭遇した接続された問題の解決策もいくつか共有したいと思いました. それが誰かを助けることを願っています。
これははるかに詳細で、次の内容をカバーします。
- もちろん
UITableViewCell
、含まれている の内容全体を表示するために必要なサイズに基づいての高さを設定するUITextView
- テキストの変更に対応する (および行の高さの変更をアニメートする)
- カーソルを表示領域内に保持し、編集中
UITextView
にサイズを変更するときにファーストレスポンダを保持するUITableViewCell
静的なテーブル ビューを使用している場合、または既知の数の しかない場合は、UITextView
ステップ 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.編集中のサイズ変更を有効にする
次の 2 つの関数では、 のデリゲートが に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
UITableView の可視 Rect 内にない場合、カーソルの位置までスクロールします。
- (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];
}
この回答をとても長くしたことで、私に腹を立てないでください。質問に答えるためにすべてが必要なわけではありませんが、これらの直接関連する問題が役立つ人が他にもいると思います.
アップデート:
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 の 1 つへの直接参照がまだ含まれていることに気付きました。bodyTextView
見つからないという問題がある場合は、機能の更新バージョンを確認してください。