iOS 7でUITextViewの高さを備えたUITableViewCell?


121

iOS 7でUITextViewを含むUITableViewCellの高さを計算するにはどうすればよいですか?

私は同様の質問に対して多くの答えを見つけましたがsizeWithFont:、すべてのソリューションに参加しており、この方法は非推奨です!

使用する必要- (CGFloat)tableView:heightForRowAtIndexPath:があることはわかっていますが、TextViewがテキスト全体を表示するために必要な高さを計算するにはどうすればよいですか?

回答:


428

まず第一に、テキストのレンダリング方法に関しては、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

静的テーブルビューで作業している場合、または既知のUITextViews 数しかない場合は、手順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:、プロジェクトのTextFieldの1つへの直接参照がまだ含まれていることにも気付きました。bodyTextView見つからないという問題がある場合は、関数の更新バージョンを確認してください。


1
そのコードはうまく機能しています!すべてのサイズを変更します!しかし、私のTextViewの高さは常に30pxです。設定を許可されていない設定はありますか、またはUITextViewで許可されていない設定はありますか?
MyJBMe 2013

1
この解決策は、テキストが大きい場合、コピーアンドペーストでは機能しないようです。
バイキング

2
@Tim Bodeit、あなたの解決策は機能します、ありがとう!ただし、attributedTextフォント、色、テキストの配置を指定せずにを割り当てると、textViewにNSAttributedString属性のデフォルト値が設定されることに注意してください。私の場合、同じテキストに対して異なる高さのテキストビューが表示されます。
アレクサンダー

4
これは、私のお気に入りのスタックオーバーフローの回答の1つです。ありがとうございます。
Richard Venable 2014

3
@TimBodeit:これをiOS8で動作させることはできません。これを修正する方法を教えてください。
Arun Gupta

37

sizeWithFontを置き換える新しい関数があり、これはboundingRectWithSizeです。

プロジェクトに次の関数を追加しました。これは、iOS7の新しい関数と7より前のiOSの古い関数を利用します。基本的には、sizeWithFontと同じ構文です。

    -(CGSize)text:(NSString*)text sizeWithFont:(UIFont*)font constrainedToSize:(CGSize)size{
        if(IOS_NEWER_OR_EQUAL_TO_7){
            NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                                              font, NSFontAttributeName,
                                              nil];

            CGRect frame = [text boundingRectWithSize:size
                                              options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
                                           attributes:attributesDictionary
                                              context:nil];

            return frame.size;
        }else{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
            return [text sizeWithFont:font constrainedToSize:size];
#pragma clang diagnostic pop
        }
    }

そのIOS_NEWER_OR_EQUAL_TO_7をプロジェクトのprefix.pchファイルに次のように追加できます。

#define IOS_NEWER_OR_EQUAL_TO_7 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 7.0 )

テキストが3行にまたがる場合、UITextViewはまだ十分に拡大縮小されず、スクロール可能になります。pastebin.com/Wh6vmBqh
マルティンデKeijzer

2番目のreturnステートメントもXCodeで非推奨の警告をスローします。
Martin de Keijzer 2013

また、cellForRowAtIndexPathで、UItextViewのサイズを計算されたテキストのサイズに設定していますか?また、関数が廃止されていないiOS6デバイスでアプリが実行された場合にのみ使用されるため、2番目の戻りの警告について心配する必要はありません。
manecosta 2013

この関数の使い方の簡単な例を教えてください。
Zorayr 2013年

@manecosta Appleのドキュメントには、結果を「ceil」する必要があると記載されています。iOS7以降では、このメソッドは(返されたCGRectのサイズコンポーネントで)小数サイズを返します。返されたサイズを使用してビューのサイズを変更するには、ceil関数を使用して、その値を最も近い整数に上げる必要があります。
HpTerm 2013年

9

UITableViewAutomaticDimensionを使用している場合、私は本当にシンプルな(iOS 8のみ)ソリューションを持っています。私の場合、それは静的なテーブルビューですが、動的なプロトタイプにこれを適合させることができると思います...

テキストビューの高さの制約アウトレットがあり、次のメソッドをこのように実装しました。

// Outlets

@property (weak, nonatomic) IBOutlet UITextView *textView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewHeight;


// Implementation

#pragma mark - Private Methods

- (void)updateTextViewHeight {
    self.textViewHeight.constant = self.textView.contentSize.height + self.textView.contentInset.top + self.textView.contentInset.bottom;
}

#pragma mark - View Controller Overrides

- (void)viewDidLoad {
    [super viewDidLoad];
    [self updateTextViewHeight];
}

#pragma mark - TableView Delegate & Datasource

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 80;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewAutomaticDimension;
}

#pragma mark - TextViewDelegate

- (void)textViewDidChange:(UITextView *)textView {
    [self.tableView beginUpdates];
    [self updateTextViewHeight];
    [self.tableView endUpdates];
}

ただし、テキストビューはスクロール可能でなければならず、自動寸法で機能するように制約を設定する必要があります。

  • セル内のすべてのビューを互いに関連させて、高さを固定して設定します(プログラムで変更するテキストビューの高さを含む)。
  • 一番上のビューには上部の間隔があり、一番下のビューにはスーパービューまでの間隔があります。

最も基本的なセルの例は次のとおりです。

  • テキストビュー以外のセルの他のビューはありません
  • テキストビューのすべての辺のマージン0、およびテキストビューの事前定義された高さの制約。

1
テキストビューはスクロール可能であってはなりません
Akshit Zaveri

updateTextviewHeightで常に同じサイズになります。コンテンツのサイズが間違っているようです。スクロールは無効です。
Dvole

5

Tim Bodeitの答えはすばらしい。Simple Solutionのコードを使用してテキストビューの高さを正しく取得し、その高さをで使用しましたheightForRowAtIndexPath。しかし、私はテキストビューのサイズを変更するために残りの回答を使用しません。代わりに、frameでテキストビューのを変更するコードを記述しますcellForRowAtIndexPath

iOS 6以下ではすべてが機能していますが、iOS 7では、テキストビューのframeサイズが実際に変更されていても、テキストビューのテキストを完全に表示することはできません。(私はを使用していませんAuto Layout)。iOS 7にTextKitはテキストがあり、その位置はNSTextContainerin によって制御されるのはこのためUITextViewです。したがって、私の場合someTextView、iOS 7で正しく機能させるために、を設定する行を追加する必要があります。

    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) {
        someTextView.textContainer.heightTracksTextView = YES;
    }

ドキュメントが言ったように、そのプロパティは何をします:

テキストビューのサイズが変更されたときに、レシーバーが境界の長方形の高さを調整するかどうかを制御します。デフォルト値:NO。

デフォルト値のままにすると、frameofのサイズ変更後someTextView、のサイズはtextContainer変更されないため、サイズ変更前の領域にのみテキストを表示できます。

また、テキストが1つからもう1つにリフローするように、scrollEnabled = NO複数ある場合にを設定する必要があるかもしれません。textContainertextContainer


4

シンプルで迅速なプロトタイピングを目的としたもう1つのソリューションを次に示します。

セットアップ:

  1. プロトタイプセルを含むテーブル。
  2. 各セルには、UITextView他のコンテンツを含む動的サイズが含まれています。
  3. プロトタイプセルはに関連付けられていTableCell.hます。
  4. UITableViewはに関連付けられていTableViewController.hます。

解決:

(1)追加TableViewController.m

 // This is the method that determines the height of each cell.  
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    // I am using a helper method here to get the text at a given cell.
    NSString *text = [self getTextAtIndex:indexPath];

    // Getting the height needed by the dynamic text view.
    CGSize size = [self frameForText:text sizeWithFont:nil constrainedToSize:CGSizeMake(300.f, CGFLOAT_MAX)];

    // Return the size of the current row.
    // 80 is the minimum height! Update accordingly - or else, cells are going to be too thin.
    return size.height + 80; 
}

// Think of this as some utility function that given text, calculates how much 
// space would be needed to fit that text.
- (CGSize)frameForText:(NSString *)text sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
{
    NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                                          font, NSFontAttributeName,
                                          nil];
    CGRect frame = [text boundingRectWithSize:size
                                      options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
                                   attributes:attributesDictionary
                                      context:nil];

    // This contains both height and width, but we really care about height.
    return frame.size;
}

// Think of this as a source for the text to be rendered in the text view. 
// I used a dictionary to map indexPath to some dynamically fetched text.
- (NSString *) getTextAtIndex: (NSIndexPath *) indexPath
{
    return @"This is stubbed text - update it to return the text of the text view.";
}

(2)追加TableCell.m

// This method will be called when the cell is initialized from the storyboard
// prototype. 
- (void)awakeFromNib
{
    // Assuming TextView here is the text view in the cell. 
    TextView.scrollEnabled = YES;
}

説明:

つまり、ここで何が起こっているのかということです。各テキストビューは、垂直方向と水平方向の制約によってテーブルセルの高さにバインドされています。つまり、テーブルセルの高さが増加すると、テキストビューもサイズが増加します。@manecostaのコードの修正バージョンを使用して、セル内の特定のテキストに合わせてテキストビューの必要な高さを計算しました。つまり、X文字のテキストを指定すると、テキストビューの必要な高さに一致frameForText:するプロパティsize.heightを持つサイズが返されます。

あとは、必要なテキストビューの高さに合わせてセルの高さを更新するだけです。そして、これはで達成されheightForRowAtIndexPath:ます。コメントに記載されているように、size.heightはテキストビューの高さであり、セル全体ではないため、オフセットを追加する必要があります。例の場合、この値は80でした。


この「dream.dream」は何を表していますか?
MyJBMe 2013年

@MyJBMe申し訳ありませんが、私のプロジェクトの一部でした-私はそれに応じてコードを更新しました。dream.dreamテキストビューでレンダリングしていたテキストです。
Zorayr 2013年

3

自動レイアウトを使用している場合の1つのアプローチは、自動レイアウトエンジンにサイズを計算させることです。これは最も効率的な方法ではありませんが、かなり便利です(そして間違いなく最も正確です)。セルレイアウトの複雑さが増すにつれて、より便利になります。たとえば、突然、セル内に2つ以上のテキストビュー/フィールドができます。

自動レイアウトを使用してテーブルビューセルのサイズを変更するための完全なサンプルを使用して、同様の質問に回答しました。

自動レイアウトですべてのサブビューに合うようにスーパービューのサイズを変更する方法は?


1

完全なスムーズなソリューションは次のとおりです。

まず、textViewを含むセルクラスが必要です

@protocol TextInputTableViewCellDelegate <NSObject>
@optional
- (void)textInputTableViewCellTextWillChange:(TextInputTableViewCell *)cell;
- (void)textInputTableViewCellTextDidChange:(TextInputTableViewCell *)cell;
@end

@interface TextInputTableViewCell : UITableViewCell
@property (nonatomic, weak) id<TextInputTableViewCellDelegate> delegate;
@property (nonatomic, readonly) UITextView *textView;
@property (nonatomic) NSInteger minLines;
@property (nonatomic) CGFloat lastRelativeFrameOriginY;
@end


#import "TextInputTableViewCell.h"

@interface TextInputTableViewCell () <UITextViewDelegate> {
    NSLayoutConstraint *_heightConstraint;
}
@property (nonatomic) UITextView *textView;
@end

@implementation TextInputTableViewCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        self.selectionStyle = UITableViewCellSelectionStyleNone;

        _textView = [UITextView new];
        _textView.translatesAutoresizingMaskIntoConstraints = NO;
        _textView.delegate = self;
        _textView.scrollEnabled = NO;
        _textView.font = CELL_REG_FONT;
        _textView.textContainer.lineFragmentPadding = 0.0;
        _textView.textContainerInset = UIEdgeInsetsZero;
        [self.contentView addSubview:_textView];

        [self.contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[view]-|" options:nil metrics:nil views:@{@"view": _textView}]];
        [self.contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[view]-|" options:nil metrics:nil views:@{@"view": _textView}]];

        _heightConstraint = [NSLayoutConstraint constraintWithItem: _textView
                         attribute: NSLayoutAttributeHeight
                         relatedBy: NSLayoutRelationGreaterThanOrEqual
                         toItem: nil
                         attribute: NSLayoutAttributeNotAnAttribute
                         multiplier: 0.0
                         constant: (_textView.font.lineHeight + 15)];
        _heightConstraint.priority = UILayoutPriorityRequired - 1;
        [_textView addConstraint:_heightConstraint];
    }
    return self;
}

- (void)prepareForReuse {
    [super prepareForReuse];    
    self.minLines = 1;
}

- (void)setMinLines:(NSInteger)minLines {
    _heightConstraint.constant = minLines * _textView.font.lineHeight + 15;
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    if ([self.delegate respondsToSelector:@selector(textInputTableViewCellTextWillChange:)]) {
        [self.delegate textInputTableViewCellTextWillChange:self];
    }
    return YES;
}

- (void)textViewDidChange:(UITextView *)textView {
    if ([self.delegate respondsToSelector:@selector(textInputTableViewCellTextDidChange:)]) {
        [self.delegate textInputTableViewCellTextDidChange:self];
    }
}

次に、それをTableViewControllerで使用します。

@interface SomeTableViewController () <TextInputTableViewCellDelegate>
@end

@implementation SomeTableViewController

. . . . . . . . . . . . . . . . . . . .

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    TextInputTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: TextInputTableViewCellIdentifier forIndexPath:indexPath];
    cell.delegate = self;
    cell.minLines = 3;
    . . . . . . . . . .  
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewAutomaticDimension;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewAutomaticDimension;
}

- (void)textInputTableViewCellWillChange:(TextInputTableViewCell *)cell {
    cell.lastRelativeFrameOriginY = cell.frame.origin.y - self.tableView.contentOffset.y;
}

- (void)textInputTableViewCellTextDidChange:(TextInputTableViewCell *)cell {
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

    [UIView performWithoutAnimation:^{
        [self.tableView moveRowAtIndexPath:indexPath toIndexPath:indexPath];
    }];

    CGFloat contentOffsetY = cell.frame.origin.y - cell.lastRelativeFrameOriginY;
    self.tableView.contentOffset = CGPointMake(self.tableView.contentOffset.x, contentOffsetY);

    CGRect caretRect = [cell.textView caretRectForPosition:cell.textView.selectedTextRange.start];
    caretRect = [self.tableView convertRect:caretRect fromView:cell.textView];

    CGRect visibleRect = self.tableView.bounds;
    visibleRect.origin.y += self.tableView.contentInset.top;
    visibleRect.size.height -= self.tableView.contentInset.top + self.tableView.contentInset.bottom;
    BOOL res = CGRectContainsRect(visibleRect, caretRect);
    if (!res) {
        caretRect.size.height += 5;
        [self.tableView scrollRectToVisible:caretRect animated:NO];
    }
}
@end
  • ここでminLinesは、textViewの最小の高さを設定できます(UITableViewAutomaticDimensionでAutoLayoutによる高さの最小化に抵抗するため)。

  • moveRowAtIndexPath:indexPath: 同じindexPathを使用すると、tableViewCellの高さの再計算と再レイアウトが開始されます。

  • performWithoutAnimation: 副作用を削除します(tableViewのコンテンツオフセットは、入力中に改行を開始するとジャンプします)。

  • 現在のセルが予期しない方法でautoLayout計算によって変更される前のセルのため、セルの更新中はrelativeFrameOriginYcontentOffsetY!ではなく )保持することが重要contentSizeです。長い単語を入力しているときに、システムハイフネーションの視覚的なジャンプを削除します。

  • プロパティは設定しないでください estimatedRowHeight以下は動作しません

    self.tableView.estimatedRowHeight = UITableViewAutomaticDimension;

    tableViewDelegateメソッドのみを使用してください。

================================================== ========================

tableViewtableViewCell間の弱いバインディングとtableViewCellからのtableViewのジオメトリの更新を気にしない場合は、TextInputTableViewCell上記のクラスをアップグレードできます。

@interface TextInputTableViewCell : UITableViewCell
@property (nonatomic, weak) id<TextInputTableViewCellDelegate> delegate;
@property (nonatomic, weak) UITableView *tableView;
@property (nonatomic, readonly) UITextView *textView;
@property (nonatomic) NSInteger minLines;
@end


#import "TextInputTableViewCell.h"

@interface TextInputTableViewCell () <UITextViewDelegate> {
    NSLayoutConstraint *_heightConstraint;
    CGFloat _lastRelativeFrameOriginY;
}
@property (nonatomic) UITextView *textView;
@end

@implementation TextInputTableViewCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        self.selectionStyle = UITableViewCellSelectionStyleNone;

        _textView = [UITextView new];
        _textView.translatesAutoresizingMaskIntoConstraints = NO;
        _textView.delegate = self;
        _textView.scrollEnabled = NO;
        _textView.font = CELL_REG_FONT;
        _textView.textContainer.lineFragmentPadding = 0.0;
        _textView.textContainerInset = UIEdgeInsetsZero;
        [self.contentView addSubview:_textView];

        [self.contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[view]-|" options:nil metrics:nil views:@{@"view": _textView}]];
        [self.contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[view]-|" options:nil metrics:nil views:@{@"view": _textView}]];

        _heightConstraint = [NSLayoutConstraint constraintWithItem: _textView
                         attribute: NSLayoutAttributeHeight
                         relatedBy: NSLayoutRelationGreaterThanOrEqual
                         toItem: nil
                         attribute: NSLayoutAttributeNotAnAttribute
                         multiplier: 0.0
                         constant: (_textView.font.lineHeight + 15)];
        _heightConstraint.priority = UILayoutPriorityRequired - 1;
        [_textView addConstraint:_heightConstraint];
    }
    return self;
}

- (void)prepareForReuse {
    [super prepareForReuse];    
    self.minLines = 1;
    self.tableView = nil;
}

- (void)setMinLines:(NSInteger)minLines {
    _heightConstraint.constant = minLines * _textView.font.lineHeight + 15;
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {

    _lastRelativeFrameOriginY = self.frame.origin.y - self.tableView.contentOffset.y;
    return YES;
}

- (void)textViewDidChange:(UITextView *)textView {

    NSIndexPath *indexPath = [self.tableView indexPathForCell:self];
    if (indexPath == nil) return;

    [UIView performWithoutAnimation:^{
        [self.tableView moveRowAtIndexPath:indexPath toIndexPath:indexPath];
    }];

    CGFloat contentOffsetY = self.frame.origin.y - _lastRelativeFrameOriginY;
    self.tableView.contentOffset = CGPointMake(self.tableView.contentOffset.x, contentOffsetY);

    CGRect caretRect = [self.textView caretRectForPosition:self.textView.selectedTextRange.start];
    caretRect = [self.tableView convertRect:caretRect fromView:self.textView];

    CGRect visibleRect = self.tableView.bounds;
    visibleRect.origin.y += self.tableView.contentInset.top;
    visibleRect.size.height -= self.tableView.contentInset.top + self.tableView.contentInset.bottom;

    BOOL res = CGRectContainsRect(visibleRect, caretRect);
    if (!res) {
        caretRect.size.height += 5;
        [self.tableView scrollRectToVisible:caretRect animated:NO];
    }
}
@end

1
  1. UILabelをUITextViewの背後に配置します。
  2. この回答を使用してください:https : //stackoverflow.com/a/36054679/6681462あなたが作成したUILabelに
  3. それらに同じ制約とフォントを与える
  4. それらに同じテキストを設定します。

セルの高さはUILabelのコンテンツによって計算されますが、すべてのテキストはTextFieldによって表示されます。


0
UITextView *txtDescLandscape=[[UITextView alloc] initWithFrame:CGRectMake(2,20,310,2)];

    txtDescLandscape.editable =NO;
    txtDescLandscape.textAlignment =UITextAlignmentLeft;
    [txtDescLandscape setFont:[UIFont fontWithName:@"ArialMT" size:15]];
    txtDescLandscape.text =[objImage valueForKey:@"imgdescription"];
    txtDescLandscape.text =[txtDescLandscape.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    [txtDescLandscape sizeToFit];
    [headerView addSubview:txtDescLandscape];

    CGRect txtViewlandscpframe = txtDescLandscape.frame;
    txtViewlandscpframe.size.height = txtDescLandscape.contentSize.height;
    txtDescLandscape.frame = txtViewlandscpframe;

私はこの方法でテキストビューの高さを数え、その高さに応じてテーブルビューセルのサイズを変更して、セルにフルテキストを表示できると思います


0

Swiftバージョン

func textViewHeightForAttributedText(text: NSAttributedString, andWidth width: CGFloat) -> CGFloat {
    let calculationView = UITextView()
    calculationView.attributedText = text
    let size = calculationView.sizeThatFits(CGSize(width: width, height: CGFloat.max))
    return size.height
}

0

UITableViewCellの高さをインナーの高さに基づいて自動的に調整したい場合UITextView。ここで私の答えを参照してください:https : //stackoverflow.com/a/45890087/1245231

解決策は非常に簡単で、7ていることを確認してくださいiOSのため、動作するはずScrolling Enabledのオプションを回すとオフのためにUITextView内部のUITableViewCellストーリーボードに。

次に、UITableViewControllerのviewDidLoad()でtableView.rowHeight = UITableViewAutomaticDimensiontableView.estimatedRowHeight > 0などを設定します。

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 44.0
}

それでおしまい。UITableViewCellの高さは、の高さに基づいて自動的に調整UITextViewされます。


-2

iOS 8以降の場合は、

your_tablview.estimatedrowheight= minheight あなたが欲しい

your_tableview.rowheight=UItableviewautomaticDimension
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.