İOS 7'de UITextView yüksekliğine sahip UITableViewCell?


121

İOS 7'de UITextView olan bir UITableViewCell'in yüksekliğini nasıl hesaplayabilirim?

Benzer sorulara birçok cevap buldum, ancak sizeWithFont:her çözümde yer alıyor ve bu yöntem kullanımdan kaldırıldı!

- (CGFloat)tableView:heightForRowAtIndexPath:Kullanmam gerektiğini biliyorum ama TextView'imin tüm metni görüntülemek için ihtiyaç duyduğu yüksekliği nasıl hesaplayabilirim?

Yanıtlar:


428

Her şeyden önce, metnin nasıl işlendiğine gelince, UITextView ve UILabel arasında büyük bir fark olduğuna dikkat etmek çok önemlidir. UITextView yalnızca tüm kenarlıklarda girintilere sahip olmakla kalmaz, aynı zamanda içindeki metin düzeni de biraz farklıdır.

Bu nedenle, sizeWithFont:UITextViews için gitmenin kötü bir yoludur.

Bunun yerine, UITextViewkendi sizeThatFits:belirleyebileceğiniz UITextViewbir sınırlayıcı kutunun içindeki tüm içeriği görüntülemek için gereken en küçük boyutu döndürecek bir işleve sahiptir .

Aşağıdakiler hem iOS 7 hem de daha eski sürümler için eşit şekilde çalışacaktır ve şu an itibariyle kullanımdan kaldırılan herhangi bir yöntemi içermemektedir.


Basit Çözüm

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

Bu işlev, bir NSAttributedStringve istenen genişliği a olarak alacak ve CGFloatgereken yüksekliği döndürecektir.


Ayrıntılı Çözüm

Yakın zamanda benzer bir şey yaptığım için, karşılaştığım bağlantılı Sorunlar için de bazı çözümler paylaşacağımı düşündüm. Umarım birine yardımcı olur.

Bu çok daha derinlemesine ve aşağıdakileri kapsayacak:

  • Elbette: UITableViewCelliçerilen bir içeriğin tüm içeriğini görüntülemek için gereken boyuta göre a'nın yüksekliğini ayarlamakUITextView
  • Metin değişikliklerine yanıt verin (ve satırın yükseklik değişikliklerini canlandırın)
  • İmleci görünen alanın içinde tutmak ve düzenleme UITextViewsırasında yeniden boyutlandırırken ilk müdahaleyi UITableViewCellyapmak

Statik bir tablo görünümüyle çalışıyorsanız veya yalnızca bilinen sayıda UITextViewURL'niz varsa, 2. adımı çok daha basit hale getirebilirsiniz.

1. Önce, heightForRowAtIndexPath'in üzerine yazın:

- (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. Gerekli yüksekliği hesaplayan işlevi tanımlayın:

Bir ekleme NSMutableDictionary(denilen bu örnekte textViewsbir örnek değişkeni olarak) sizinUITableViewControllerAlt sınıfınıza .

Bu sözlüğü, aşağıdaki UITextViewsgibi bireye yapılan referansları saklamak için kullanın :

(ve evet, indexPaths sözlükler için geçerli anahtarlardır )

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

Bu fonksiyon şimdi gerçek yüksekliği hesaplayacaktır:

- (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. Düzenleme Sırasında Yeniden Boyutlandırmayı Etkinleştir

Sonraki iki işlev için, temsilcisinin UITextViewssizin için ayarlanması önemlidir UITableViewController. Temsilci olarak başka bir şeye ihtiyacınız varsa, oradan ilgili aramaları yaparak veya uygun NSNotificationCenter kancalarını kullanarak bunun üstesinden gelebilirsiniz.

- (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. Düzenleme sırasında imleci takip edin

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

Bu UITableView, UITableView’un görünür Rect’i içinde değilse , kaydırmayı imlecin konumuna getirecektir :

- (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. İç kısımları ayarlayarak görünür yönünü ayarlayın

Düzenleme sırasında, bazı kısımlarınız UITableViewKlavye kapsamında olabilir. Tablo görünümleri girintileri ayarlanmadıysa, scrollToCursorForTextView:tablo görünümünün altındaysa imlecinize kaydırılamayacaktır.

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

Ve son kısım:

Görünümünüzün içinde yüklendi, Klavye değişiklikleri için şu yollarla kaydolun 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];
}

Bu cevabı bu kadar uzun süre verdiğim için lütfen bana kızma. Soruyu cevaplamak için hepsine ihtiyaç duyulmasa da, bu doğrudan bağlantılı sorunların yardımcı olacağı başka insanların da olduğuna inanıyorum.


GÜNCELLEME:

Dave Haupert'in belirttiği gibi, rectVisibleişlevi eklemeyi unuttum :

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

Ayrıca scrollToCursorForTextView:, projemdeki TextField'lardan birine hala doğrudan bir referans olduğunu fark ettim . bodyTextViewBulunamamakla ilgili bir sorununuz varsa , işlevin güncellenmiş sürümünü kontrol edin.


1
Bu kod hiç iyi çalışıyor! Her şeyi yeniden boyutlandırıyor! Ancak, TextView her zaman 30px yüksekliğe ulaşır! Ayarlamama izin verilmeyen ayarlar var mı yoksa UITextView'da izin verilmeyen bir şey var mı?
MyJBMe

1
Bu çözüm, metin büyükse kopyalayıp yapıştırmada işe yaramıyor gibi görünüyor, herhangi bir fikir var mı?
Vikingler

2
@Tim Bodeit, çözümünüz işe yarıyor, teşekkürler! Ancak, attributedTextyazı tipi, renk ve metin hizalamasını belirtmeden atamanın , NSAttributedString özniteliklerinin varsayılan değerlerinin textView için ayarlanmasına yol açtığını yorumda not etmelisiniz. Benim durumumda, aynı metin için metin görünümünün farklı yüksekliklerinin alınmasına neden oluyor.
Alexander

4
Bu, tüm zamanların en sevdiğim Stack Overflow cevaplarından biridir - teşekkürler!
Richard Venable

3
@TimBodeit: Bunu iOS8'de çalıştıramıyorum. Lütfen bunun nasıl düzeltilebileceğini bana bildirin.
Arun Gupta

37

BoundingRectWithSize olan sizeWithFont'un yerini alacak yeni bir işlev vardır.

Projeme aşağıdaki işlevi ekledim, bu yeni işlevi iOS7'de ve eski işlevi 7'den düşük iOS'ta kullanır. Temelde sizeWithFont ile aynı sözdizimine sahiptir:

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

Bu IOS_NEWER_OR_EQUAL_TO_7'yi projenizdeki prefix.pch dosyanıza şu şekilde ekleyebilirsiniz:

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

UITextView'larım hala çok iyi ölçeklenmiyor ve metin 3 satıra yayıldığında kaydırılabilir hale geliyor; pastebin.com/Wh6vmBqh
Martin de Keijzer

İkinci dönüş ifadesi de XCode'da bir kullanımdan kaldırma uyarısı atar.
Martin de Keijzer

Ayrıca UItextView boyutunu cellForRowAtIndexPath içindeki metnin hesaplanan boyutuna mı ayarlıyorsunuz? Ayrıca, ikinci dönüşteki uyarı için endişelenmemelisiniz, çünkü uygulama yalnızca işlevin kullanımdan kaldırılmadığı bir iOS6 cihazında çalıştırıldığında kullanılır.
manecosta

Bu işlevi nasıl kullanacağınıza dair basit bir örnek verebilir misiniz?
Zorayr

@manecosta Apple'ın dokümantasyonu sonucu 'iptal etmeniz' gerektiğini söylüyor: iOS 7 ve sonraki sürümlerde, bu yöntem kesirli boyutları döndürür (döndürülen CGRect'in boyut bileşeninde); boyut görünümlerine döndürülen boyutu kullanmak için, ceil işlevini kullanarak değerini en yakın yüksek tam sayıya yükselt seçeneğini kullanmanız gerekir.
HpTerm

9

UITableViewAutomaticDimension kullanıyorsanız, gerçekten basit (yalnızca iOS 8) bir çözümüm var. Benim durumumda bu statik bir tablo görünümü, ancak bunu dinamik prototipler için uyarlayabilirsiniz ...

Metin görünümünün yüksekliği için bir kısıtlama çıkışım var ve bunun gibi aşağıdaki yöntemleri uyguladım:

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

Ancak unutmayın : metin görünümü kaydırılabilir olmalıdır ve kısıtlamalarınızı otomatik boyut için çalışacak şekilde ayarlamalısınız:

  • Hücredeki tüm görünümü birbirine göre sabit yüksekliklerle ayarlayın (programatik olarak değiştireceğiniz metin görünümü yüksekliği dahil)
  • en üstteki görünümün üst aralığı ve en alttaki görünümün süper görünüme kadar olan alt aralığı vardır;

En temel hücre örneği:

  • hücrede metin görünümü dışında başka görünüm yok
  • Metin görünümünün tüm kenarlarında 0 kenar boşluğu ve metin görünümü için önceden tanımlanmış bir yükseklik kısıtlaması.

1
metin görünümü gerekir DEĞİL kaydırılabilir olmak
Akshit Zaveri

UpdateTextviewHeight altında her zaman aynı boyutu alıyorum. Görünüşe göre içerik boyutu yanlış. Kaydırma devre dışı bırakıldı.
Dvole

5

Tim Bodeit'in cevabı harika. Metin görünümünün yüksekliğini doğru bir şekilde almak için Basit Çözüm kodunu kullandım ve bu yüksekliği heightForRowAtIndexPath. Ancak yanıtın geri kalanını metin görünümünü yeniden boyutlandırmak için kullanmıyorum. Bunun yerine, framemetin görünümünü değiştirmek için kod yazıyorum cellForRowAtIndexPath.

Her şey iOS 6 ve altında çalışıyor, ancak iOS 7'de metin görünümündeki metin, metin görünümü framegerçekten yeniden boyutlandırılsa bile tam olarak gösterilemez . (Kullanmıyorum Auto Layout). İOS 7'de var ki sebebi olmalı TextKitve metnin konumunu kontrol edilir NSTextContaineriçinde UITextView. Bu yüzden benim durumumda someTextView, iOS 7'de düzgün çalışmasını sağlamak için ayarlamak için bir satır eklemem gerekiyor .

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

Belgelerin dediği gibi, bu mülkün yaptığı şey:

Alıcının, metin görünümü yeniden boyutlandırıldığında sınırlayıcı dikdörtgeninin yüksekliğini ayarlayıp ayarlamayacağını kontrol eder. Varsayılan değer: HAYIR.

Varsayılan değerle izin it, sonra yeniden boyutlandırmak Eğer framebir someTextView, büyüklüğü textContainermetin yalnızca boyutlandırma önce bölgede görüntülenebilmesi sonuca götüren, değişmez.

Ve belki de ayarlamak için gerekli olan scrollEnabled = NOdurumlarda birden fazla var textContainerbu yüzden metin birinden yeniden akıtılmasına edeceğini,textContainer diğerine .


4

İşte basitliği ve hızlı prototiplemeyi amaçlayan bir çözüm daha :

Kurmak:

  1. Prototip hücreli tablo.
  2. Her hücre dinamik boyut içerir UITextView diğer içeriklerle .
  3. Prototip hücreler ile ilişkilidir TableCell.h.
  4. UITableViewile ilişkilidir TableViewController.h.

Çözüm:

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

Açıklama:

Yani burada olan şudur: her metin görünümü tablo hücrelerinin yüksekliğine dikey ve yatay kısıtlamalarla bağlıdır - bu, tablo hücresi yüksekliği arttığında, metin görünümünün de boyutunu artırdığı anlamına gelir. @ Manecosta'nın kodunun değiştirilmiş bir sürümünü, bir hücreye verilen metni sığdırmak için metin görünümünün gerekli yüksekliğini hesaplamak için kullandım. Bu, X sayıda karakter içeren bir metin verildiğinde , metin görünümünün gerekli yüksekliğiyle eşleşen frameForText:bir özelliğe sahip bir boyut döndüreceği anlamına gelir size.height.

Şimdi, geriye kalan tek şey, gerekli metin görünümünün yüksekliğiyle eşleşecek şekilde hücre yüksekliğini güncellemektir. Ve bu elde edilir heightForRowAtIndexPath:. Yorumlarda belirtildiği gibi size.height, yalnızca metin görünümü için yükseklik olduğundan ve hücrenin tamamı olmadığından, ona biraz ofset eklenmelidir. Örnek durumunda, bu değer 80 idi.


Bu 'dream.dream' ne anlama geliyor?
MyJBMe

@MyJBMe özür dilerim kendi projemin bir parçasıydı - kodu buna göre güncelledim. dream.dreammetin görünümünde oluşturduğum metindi.
Zorayr

3

Otomatik düzen kullanıyorsanız bir yaklaşım, otomatik düzen motorunun boyutu sizin için hesaplamasına izin vermektir. Bu en verimli yaklaşım değil, ancak oldukça kullanışlıdır (ve muhtemelen en doğru olanıdır). Hücre düzeninin karmaşıklığı arttıkça daha kullanışlı hale gelir - örneğin, aniden hücrede iki veya daha fazla metin görünümünüz / alanınız olur.

Otomatik düzen kullanarak tablo görünümü hücrelerini boyutlandırmak için eksiksiz bir örnekle benzer bir soruyu yanıtladım, burada:

Otomatik düzen ile tüm alt görünümlere uyacak şekilde süpervizyon nasıl yeniden boyutlandırılır?


1

Tam düzgün çözüm aşağıdaki gibidir.

Öncelikle textView olan hücre sınıfına ihtiyacımız var

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

Sonra, onu TableViewController'da kullanıyoruz

@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
  • Burada minLinestextView için minimum yüksekliği ayarlamaya izin verir (UITableViewAutomaticDimension ile AutoLayout ile yüksekliği en aza indirmeye direnmek için).

  • moveRowAtIndexPath:indexPath: aynı indexPath ile tableViewCell yüksekliği yeniden hesaplamayı ve yeniden düzenlemeyi başlatır.

  • performWithoutAnimation: yan etkiyi ortadan kaldırır (yazarken yeni satıra başlarken tableView içeriği ofset atlama).

  • Geçerli hücre autoLayout hesabı tarafından beklenmedik bir şekilde değiştirilmeden önce hücreler nedeniyle hücre güncellemesi sırasında korumak relativeFrameOriginY(değil contentOffsetY!) contentSizeÖnemlidir. Uzun sözcükler yazarken sistem tirelemesindeki görsel sıçramaları kaldırır.

  • Özelliği ayarlamamanız gerektiğini unutmayın estimatedRowHeight ! Aşağıdakiler çalışmıyor

    self.tableView.estimatedRowHeight = UITableViewAutomaticDimension;

    Yalnızca tableViewDelegate yöntemini kullanın.

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

Biri zayıf arasındaki bağlayıcı karşı sakıncası yoksa tableView ve tableViewCell ve gelen tableView güncellenmesi geometri tableViewCell , yükseltmek mümkündür TextInputTableViewCellyukarıdaki sınıf:

@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'i UITextView'unuzun arkasına koyun.
  2. Bu yanıtı kullanın: https://stackoverflow.com/a/36054679/6681462 oluşturduğunuz UILabel'i kullanmak için
  3. Onlara aynı kısıtlamaları ve yazı tiplerini verin
  4. Onlara aynı metni ayarlayın;

Hücrenizin yüksekliği UILabel'in içeriğine göre hesaplanacak, ancak tüm metin TextField tarafından gösterilecektir.


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;

Sanırım bu şekilde metin görünümünüzün yüksekliğini sayabilir ve ardından tablo görünümü hücrenizi bu yüksekliğe göre yeniden boyutlandırabilirsiniz, böylece hücrede tam metni gösterebilirsiniz


0

Swift versiyonu

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İç yüksekliğinin yüksekliğine göre yüksekliğini otomatik olarak ayarlamak istiyorsanız UITextView. Cevabımı burada görün: https://stackoverflow.com/a/45890087/1245231

Çözüm oldukça basittir ve iOS 7'den beri çalışmalıdır . StoryBoard'un içi için Scrolling Enabledseçeneğin kapalı olduğundan emin olun .UITextViewUITableViewCell

Sonra UITableViewController'ınızda viewDidLoad () şu şekilde tableView.rowHeight = UITableViewAutomaticDimensionve tableView.estimatedRowHeight > 0gibi ayarlayın :

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 44.0
}

Bu kadar. UITableViewCellyüksekliği, iç UITextViewyüksekliğe göre otomatik olarak ayarlanacaktır .


-2

İOS 8 ve üstü için sadece kullanabilirsiniz

your_tablview.estimatedrowheight= minheight İstediğiniz

your_tableview.rowheight=UItableviewautomaticDimension
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.