UITableViewCell dengan tinggi UITextView di iOS 7?

121

Bagaimana saya bisa menghitung tinggi UITableViewCell dengan UITextView di dalamnya di iOS 7?

Saya menemukan banyak jawaban untuk pertanyaan serupa, tetapi sizeWithFont:mengambil bagian dalam setiap solusi dan metode ini sudah usang!

Saya tahu saya harus menggunakan, - (CGFloat)tableView:heightForRowAtIndexPath:tetapi bagaimana cara menghitung ketinggian yang dibutuhkan TextView saya untuk menampilkan keseluruhan teks?

MyJBMe
sumber

Jawaban:

428

Pertama-tama, sangat penting untuk diperhatikan, bahwa ada perbedaan besar antara UITextView dan UILabel dalam hal bagaimana teks ditampilkan. UITextView tidak hanya memiliki sisipan di semua perbatasan, tetapi juga tata letak teks di dalamnya sedikit berbeda.

Oleh karena itu, sizeWithFont:adalah cara yang buruk untuk menggunakan UITextView.

Sebaliknya UITextViewsendiri memiliki fungsi yang disebut sizeThatFits:yang akan mengembalikan ukuran terkecil yang diperlukan untuk menampilkan semua konten di UITextViewdalam kotak pembatas, yang dapat Anda tentukan.

Berikut ini akan bekerja sama untuk iOS 7 dan versi yang lebih lama dan untuk saat ini tidak termasuk metode apa pun, yang tidak digunakan lagi.


Solusi Sederhana

- (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;
}

Fungsi ini akan mengambil a NSAttributedStringdan lebar yang diinginkan sebagai a CGFloatdan mengembalikan tinggi yang dibutuhkan


Solusi Terperinci

Karena saya baru-baru ini melakukan sesuatu yang serupa, saya pikir saya juga akan membagikan beberapa solusi untuk Masalah terkait yang saya temui. Saya berharap ini akan membantu seseorang.

Ini jauh lebih mendalam dan akan mencakup hal-hal berikut:

  • Tentunya: pengaturan tinggi sebuah UITableViewCellberdasarkan ukuran yang dibutuhkan untuk menampilkan konten yang lengkapUITextView
  • Merespons perubahan teks (dan menganimasikan perubahan ketinggian baris)
  • Menjaga kursor di dalam area yang terlihat dan menjaga responden pertama di UITextViewsaat mengubah ukuran UITableViewCellsaat mengedit

Jika Anda bekerja dengan tampilan tabel statis atau Anda hanya memiliki jumlah UITextViews yang diketahui , Anda dapat membuat langkah 2 jauh lebih sederhana.

1. Pertama, timpa 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. Tentukan fungsi yang menghitung ketinggian yang dibutuhkan:

Tambahkan NSMutableDictionary(dalam contoh ini disebut textViews) sebagai variabel instan ke AndaUITableViewController subkelas .

Gunakan kamus ini untuk menyimpan referensi ke individu UITextViewsseperti:

(dan ya, indexPaths adalah kunci yang valid untuk kamus )

- (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;
}

Fungsi ini sekarang akan menghitung tinggi sebenarnya:

- (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. Aktifkan Pengubahan Ukuran sambil Mengedit

Untuk dua fungsi berikutnya, penting, bahwa delegasi UITextViewsdiatur ke Anda UITableViewController. Jika Anda membutuhkan sesuatu yang lain sebagai delegasi, Anda dapat mengatasinya dengan membuat panggilan yang relevan dari sana atau menggunakan hook NSNotificationCenter yang sesuai.

- (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. Ikuti kursor saat Mengedit

- (void)textViewDidBeginEditing:(UITextView *)textView {
    [self scrollToCursorForTextView:textView];
}

Ini akan membuat UITableViewscroll ke posisi kursor, jika tidak berada di dalam Rect yang terlihat dari 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. Sesuaikan persegi yang terlihat, dengan mengatur insets

Saat mengedit, sebagian dari Anda UITableViewmungkin dilindungi oleh Keyboard. Jika sisipan tampilan tabel tidak disesuaikan, scrollToCursorForTextView:tidak akan dapat menggulir ke kursor Anda, jika berada di bagian bawah tampilan tabel.

- (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];
}

Dan bagian terakhir:

Di dalam tampilan Anda dimuat, daftar untuk Pemberitahuan untuk perubahan Keyboard melalui 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];
}

Tolong jangan marah padaku, karena membuat jawaban ini begitu lama. Meskipun tidak semuanya diperlukan untuk menjawab pertanyaan, saya yakin bahwa ada orang lain yang dapat membantu masalah yang terkait langsung ini.


MEMPERBARUI:

Seperti yang ditunjukkan Dave Haupert, saya lupa menyertakan rectVisiblefungsinya:

- (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);
}

Juga saya perhatikan, itu scrollToCursorForTextView:masih menyertakan referensi langsung ke salah satu BidangTeks di proyek saya. Jika Anda memiliki masalah dengan bodyTextViewtidak ditemukannya, periksa versi terbaru dari fungsi tersebut.

Tim Bodeit
sumber
1
Kode itu bekerja dengan baik sama sekali! Ini mengubah ukuran semuanya! Tapi, TextView saya selalu memiliki tinggi 30px! Apakah ada pengaturan yang tidak boleh saya atur, atau ada sesuatu yang tidak diizinkan di UITextView?
MyJBMe
1
Solusi ini sepertinya tidak berfungsi pada salin dan tempel jika teksnya besar, ada ide?
Viking
2
@Tim Bodeit, solusi Anda berhasil, terima kasih! Tapi saya pikir Anda harus mencatat dalam komentar, bahwa menetapkan attributedTexttanpa menentukan font, warna dan teks keselarasan mengarah ke pengaturan nilai default dari atribut NSAttributedString ke textView. Dalam kasus saya itu menyebabkan mendapatkan ketinggian yang berbeda dari tampilan teks untuk teks yang sama.
Alexander
4
Ini adalah salah satu jawaban Stack Overflow favorit saya sepanjang masa - terima kasih!
Richard Venable
3
@TimBodeit: Saya tidak bisa membuatnya berfungsi di iOS8. Tolong beritahu saya bagaimana ini bisa diperbaiki.
Arun Gupta
37

Ada fungsi baru untuk menggantikan sizeWithFont, yaitu boundingRectWithSize.

Saya menambahkan fungsi berikut ke proyek saya, yang memanfaatkan fungsi baru di iOS7 dan yang lama di iOS lebih rendah dari 7. Ini pada dasarnya memiliki sintaks yang sama dengan 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
        }
    }

Anda dapat menambahkan IOS_NEWER_OR_EQUAL_TO_7 itu pada file prefix.pch Anda di proyek Anda sebagai:

#define IOS_NEWER_OR_EQUAL_TO_7 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 7.0 )
manecosta
sumber
UITextView saya masih tidak berskala dengan baik dan menjadi dapat digulir ketika teks mencakup 3 baris; pastebin.com/Wh6vmBqh
Martin de Keijzer
Pernyataan return kedua juga menampilkan peringatan deprecation di XCode.
Martin de Keijzer
Apakah Anda juga menyetel ukuran UItextView ke ukuran teks yang dihitung, di cellForRowAtIndexPath? Anda juga tidak perlu khawatir tentang peringatan di pengembalian kedua karena ini hanya digunakan ketika aplikasi dijalankan pada perangkat iOS6 di mana fungsinya tidak ditinggalkan.
manecosta
Bisakah Anda memberikan contoh sederhana tentang cara menggunakan fungsi ini?
Zorayr
Dokumentasi @manecosta Apple mengatakan bahwa Anda harus 'membatasi' hasilnya: Di iOS 7 dan yang lebih baru, metode ini mengembalikan ukuran pecahan (dalam komponen ukuran dari CGRect yang dikembalikan); untuk menggunakan ukuran yang dikembalikan ke tampilan ukuran, Anda harus menggunakan menaikkan nilainya ke bilangan bulat terdekat yang lebih tinggi menggunakan fungsi ceil.
HpTerm
9

Jika Anda menggunakan UITableViewAutomaticDimension, saya memiliki solusi yang sangat sederhana (khusus iOS 8). Dalam kasus saya ini adalah tampilan tabel statis, tetapi saya rasa Anda dapat menyesuaikan ini untuk prototipe dinamis ...

Saya memiliki outlet kendala untuk ketinggian tampilan teks dan saya telah menerapkan metode berikut seperti ini:

// 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];
}

Tapi ingat : tampilan teks harus dapat di-scroll, dan Anda harus menyiapkan pembatas Anda agar berfungsi untuk dimensi otomatis:

  • atur semua tampilan dalam sel dalam kaitannya satu sama lain, dengan ketinggian tetap (termasuk tinggi tampilan teks, yang akan Anda ubah secara programatik)
  • tampilan paling atas memiliki jarak atas dan tampilan paling bawah memiliki jarak paling bawah ke tampilan super;

Contoh sel paling dasar adalah:

  • tidak ada tampilan lain di dalam sel kecuali tampilan teks
  • 0 margin di sekitar semua sisi tampilan teks dan batasan tinggi yang telah ditentukan untuk tampilan teks.
dec-vt100
sumber
1
tampilan teks TIDAK boleh digulir
Akshit Zaveri
Saya mendapatkan ukuran yang sama di bawah updateTextviewHeight sepanjang waktu. Sepertinya ukuran konten salah. Pengguliran dinonaktifkan.
Dvole
5

Jawaban Tim Bodeit bagus. Saya menggunakan kode Simple Solution untuk mendapatkan tinggi tampilan teks dengan benar, dan menggunakan ketinggian itu di heightForRowAtIndexPath. Tapi saya tidak menggunakan jawaban lainnya untuk mengubah ukuran tampilan teks. Sebagai gantinya, saya menulis kode untuk mengubah frametampilan teks cellForRowAtIndexPath.

Semuanya berfungsi di iOS 6 ke bawah, tetapi di iOS 7 teks dalam tampilan teks tidak dapat ditampilkan sepenuhnya meskipun frametampilan teks memang diubah ukurannya. (Saya tidak menggunakan Auto Layout). Itu harus menjadi alasan bahwa di iOS 7 ada TextKitdan posisi teks dikontrol oleh NSTextContainerin UITextView. Jadi dalam kasus saya, saya perlu menambahkan baris untuk mengatur someTextViewagar berfungsi dengan benar di iOS 7.

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

Seperti yang dikatakan dalam dokumentasi, apa yang dilakukan properti itu adalah:

Mengontrol apakah penerima menyesuaikan tinggi persegi panjang pembatasnya saat tampilan teks diubah ukurannya. Nilai default: TIDAK.

Jika dibiarkan dengan nilai default, setelah mengubah ukuran framedari someTextView, ukuran textContainertidak akan berubah, sehingga teks hanya dapat ditampilkan di area sebelum diubah ukurannya.

Dan mungkin diperlukan untuk mengatur scrollEnabled = NOseandainya ada lebih dari satu textContainer, sehingga teks akan mengalir dari satu textContainerke yang lain.

PowerQian
sumber
4

Berikut satu solusi lagi yang bertujuan untuk kesederhanaan dan pembuatan prototipe cepat :

Mempersiapkan:

  1. Tabel dengan sel prototipe.
  2. Setiap sel berisi ukuran dinamis UITextView dengan konten lainnya.
  3. Sel prototipe dikaitkan dengan TableCell.h .
  4. UITableViewdikaitkan dengan TableViewController.h.

Larutan:

(1) Tambahkan ke 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) Tambahkan ke 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;
}

Penjelasan:

Jadi yang terjadi di sini adalah: setiap tampilan teks terikat ke tinggi sel tabel dengan batasan vertikal dan horizontal - itu berarti ketika tinggi sel tabel meningkat, tampilan teks juga akan meningkatkan ukurannya. Saya menggunakan versi modifikasi dari kode @ manecosta untuk menghitung tinggi tampilan teks yang diperlukan agar sesuai dengan teks yang diberikan dalam sel. Jadi itu artinya diberi teks dengan jumlah karakter X,frameForText: akan mengembalikan ukuran yang akan memiliki propertisize.height yang sesuai dengan tinggi tampilan teks yang dibutuhkan.

Sekarang, yang tersisa hanyalah memperbarui tinggi sel agar sesuai dengan tinggi tampilan teks yang diperlukan. Dan ini dicapai pada heightForRowAtIndexPath:. Seperti disebutkan di komentar, karena size.heighthanya tinggi untuk tampilan teks dan bukan seluruh sel, harus ada beberapa offset yang ditambahkan ke dalamnya. Dalam kasus contoh, nilainya adalah 80.

Zorayr
sumber
Apa kepanjangan dari 'dream.dream' ini?
MyJBMe
@MyJBMe maaf itu adalah bagian dari proyek saya sendiri - Saya telah memperbarui kode yang sesuai. dream.dreamadalah teks yang saya render dalam tampilan teks.
Zorayr
3

Satu pendekatan jika Anda menggunakan tata letak otomatis adalah membiarkan mesin tata letak otomatis menghitung ukuran untuk Anda. Ini bukan pendekatan yang paling efisien tetapi cukup nyaman (dan bisa dibilang paling akurat). Ini menjadi lebih nyaman karena kompleksitas tata letak sel tumbuh - misalnya, tiba-tiba Anda memiliki dua atau lebih tampilan teks / bidang dalam sel.

Saya menjawab pertanyaan serupa dengan sampel lengkap untuk mengukur sel tableview menggunakan tata letak otomatis, di sini:

Bagaimana cara mengubah ukuran superview agar sesuai dengan semua subview dengan autolayout?

TomSwift
sumber
1

Solusi mulus lengkap adalah sebagai berikut.

Pertama, kita membutuhkan kelas sel dengan 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];
    }
}

Selanjutnya, kami menggunakannya di 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
  • Di sini minLinesmemungkinkan untuk menyetel tinggi minimum untuk textView (untuk menahan meminimalkan ketinggian dengan AutoLayout dengan UITableViewAutomaticDimension).

  • moveRowAtIndexPath:indexPath: dengan indexPath yang sama memulai penghitungan ulang tinggi tableViewCell dan tata letak ulang.

  • performWithoutAnimation: menghapus efek samping (offset konten tableView melompat saat memulai baris baru saat mengetik).

  • Penting untuk mempertahankan relativeFrameOriginY(bukan contentOffsetY!) Selama pembaruan sel karena contentSizesel sebelum sel saat ini dapat diubah oleh kalkulus autoLayout dengan cara yang tidak terduga. Ini menghilangkan lompatan visual pada tanda hubung sistem saat mengetik kata-kata panjang.

  • Perhatikan bahwa Anda tidak boleh menyetel properti estimatedRowHeight ! Berikut ini tidak berhasil

    self.tableView.estimatedRowHeight = UITableViewAutomaticDimension;

    Gunakan hanya metode tableViewDelegate.

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

Jika seseorang tidak keberatan dengan pengikatan lemah antara tableView dan tableViewCell serta memperbarui geometri tableView dari tableViewCell , TextInputTableViewCellkelas di atas dapat ditingkatkan :

@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
malex
sumber
1
  1. Letakkan UILabel di belakang UITextView Anda.
  2. Gunakan jawaban ini: https://stackoverflow.com/a/36054679/6681462 ke UILabel yang Anda buat
  3. Beri mereka batasan dan font yang sama
  4. Atur teks yang sama;

Tinggi sel Anda akan dihitung oleh konten UILabel, tetapi semua teks akan ditampilkan oleh BidangTeks.

ilnur
sumber
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;

Saya rasa dengan cara ini Anda dapat menghitung tinggi tampilan teks Anda dan kemudian mengubah ukuran sel tampilan tabel Anda sesuai dengan ketinggian itu sehingga Anda dapat menampilkan teks lengkap pada sel

D-eptdeveloper
sumber
0

Versi cepat

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
}
Adam Smaka
sumber
0

Jika Anda ingin menyesuaikan UITableViewCellketinggian secara otomatis berdasarkan ketinggian bagian dalam UITextView. Lihat jawaban saya di sini: https://stackoverflow.com/a/45890087/1245231

Solusinya cukup sederhana dan harus bekerja sejak iOS 7. Pastikan bahwa Scrolling Enabledopsi diaktifkan off untuk UITextViewdalam UITableViewCelldalam storyboard.

Kemudian di viewDidLoad () UITableViewController Anda, setel tableView.rowHeight = UITableViewAutomaticDimensiondan tableView.estimatedRowHeight > 0seperti:

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 44.0
}

Itu dia. UITableViewCellKetinggian akan secara otomatis disesuaikan berdasarkan tinggi bagian dalam UITextView.

petrsyn.dll
sumber
-2

Untuk iOS 8 ke atas, Anda cukup menggunakan

your_tablview.estimatedrowheight= minheight kamu ingin

your_tableview.rowheight=UItableviewautomaticDimension
Sandy
sumber