UITableViewCell mit UITextView-Höhe in iOS 7?

121

Wie kann ich die Höhe einer UITableViewCell mit einer UITextView in iOS 7 berechnen?

Ich habe viele Antworten auf ähnliche Fragen gefunden, sizeWithFont:nehme aber an jeder Lösung teil und diese Methode ist veraltet!

Ich weiß, dass ich verwenden muss, - (CGFloat)tableView:heightForRowAtIndexPath:aber wie berechne ich die Höhe, die meine Textansicht benötigt, um den gesamten Text anzuzeigen?

MyJBMe
quelle

Antworten:

428

Zunächst ist es sehr wichtig zu beachten, dass es einen großen Unterschied zwischen UITextView und UILabel gibt, wenn es darum geht, wie Text gerendert wird. UITextView verfügt nicht nur über Einfügungen an allen Rändern, sondern auch ein etwas anderes Textlayout.

Daher sizeWithFont:ist UITextViews ein schlechter Weg.

Stattdessen hat UITextViewselbst eine Funktion aufgerufen, sizeThatFits:die die kleinste Größe zurückgibt, die erforderlich ist, um den gesamten Inhalt UITextVieweines Begrenzungsrahmens anzuzeigen , den Sie angeben können.

Das Folgende funktioniert sowohl für iOS 7 als auch für ältere Versionen gleichermaßen und enthält derzeit keine veralteten Methoden.


Einfache Lösung

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

Diese Funktion nimmt a NSAttributedStringund die gewünschte Breite als CGFloatund gibt die benötigte Höhe zurück


Detaillierte Lösung

Da ich kürzlich etwas Ähnliches getan habe, dachte ich, ich würde auch einige Lösungen für die damit verbundenen Probleme teilen, auf die ich gestoßen bin. Ich hoffe es wird jemandem helfen.

Dies ist weitaus ausführlicher und wird Folgendes abdecken:

  • Natürlich: Festlegen der Höhe von a UITableViewCellbasierend auf der Größe, die zum Anzeigen des vollständigen Inhalts eines enthaltenen Inhalts erforderlich istUITextView
  • Reagieren Sie auf Textänderungen (und animieren Sie die Höhenänderungen der Zeile).
  • Halten Sie den Cursor im sichtbaren Bereich und halten Sie den Ersthelfer UITextViewbeim Ändern der Größe UITableViewCellwährend der Bearbeitung auf

Wenn Sie mit einer statischen Tabellenansicht arbeiten oder nur eine bekannte Anzahl von UITextViews haben, können Sie Schritt 2 möglicherweise viel einfacher gestalten.

1. Überschreiben Sie zunächst den 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. Definieren Sie die Funktion, die die benötigte Höhe berechnet hat:

Fügen Sie Ihrer Unterklasse eine NSMutableDictionary(in diesem Beispiel als textViews) Instanzvariable hinzu UITableViewController.

Verwenden Sie dieses Wörterbuch, um Verweise auf die Person UITextViewswie folgt zu speichern :

(und ja, indexPaths sind gültige Schlüssel für Wörterbücher )

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

Diese Funktion berechnet nun die tatsächliche Höhe:

- (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. Aktivieren Sie die Größenänderung während der Bearbeitung

Für die nächsten beiden Funktionen ist es wichtig, dass der Delegat von UITextViewsauf Ihren eingestellt ist UITableViewController. Wenn Sie als Delegat etwas anderes benötigen, können Sie dies umgehen, indem Sie die entsprechenden Anrufe von dort aus tätigen oder die entsprechenden NSNotificationCenter-Hooks verwenden.

- (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. Folgen Sie dem Cursor beim Bearbeiten

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

Dadurch wird der UITableViewBildlauf zur Position des Cursors ausgeführt, wenn er sich nicht im sichtbaren Bereich der UITableView befindet:

- (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. Stellen Sie das sichtbare Rechteck ein, indem Sie Einsätze einstellen

Während der Bearbeitung können Teile von Ihnen UITableViewvon der Tastatur abgedeckt werden. Wenn die Tabellenansichten nicht angepasst sind, scrollToCursorForTextView:kann nicht zum Cursor gescrollt werden, wenn er sich am unteren Rand der Tabellenansicht befindet.

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

Und letzter Teil:

Melden Sie sich in Ihrer Ansicht, die geladen wurde, für die Benachrichtigungen für Tastaturänderungen an über 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];
}

Bitte sei nicht böse auf mich, weil ich diese Antwort so lange gemacht habe. Obwohl nicht alles zur Beantwortung der Frage benötigt wird, glaube ich, dass es andere Menschen gibt, denen diese direkt verwandten Themen hilfreich sein werden.


AKTUALISIEREN:

Wie Dave Haupert betonte, habe ich vergessen, die rectVisibleFunktion aufzunehmen:

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

Ich bemerkte auch, dass dies scrollToCursorForTextView:immer noch einen direkten Verweis auf eines der TextFields in meinem Projekt enthielt. Wenn Sie ein Problem damit haben, bodyTextViewnicht gefunden zu werden, überprüfen Sie die aktualisierte Version der Funktion.

Tim Bodeit
quelle
1
Dieser Code funktioniert überhaupt gut! Es ändert die Größe alles! Aber meine TextView hat immer eine Höhe von 30px! Gibt es Einstellungen, die ich nicht festlegen darf, oder gibt es etwas, das ich in UITextView nicht zulassen darf?
MyJBMe
1
Diese Lösung scheint beim Kopieren und Einfügen nicht zu funktionieren, wenn der Text groß ist. Irgendwelche Ideen?
Wikinger
2
@ Tim Bodeit, Ihre Lösung funktioniert, danke! Ich denke jedoch, dass Sie im Kommentar beachten sollten, dass das Zuweisen von attributedTextohne Angabe von Schriftart, Farbe und Textausrichtung zum Festlegen von Standardwerten für NSAttributedString-Attribute für die Textansicht führt. In meinem Fall werden unterschiedliche Höhen der Textansicht für denselben Text angezeigt.
Alexander
4
Dies ist eine meiner Lieblingsantworten für Stapelüberlauf aller Zeiten - danke!
Richard Venable
3
@ TimBodeit: Ich kann dies unter iOS8 nicht zum Laufen bringen. Bitte lassen Sie mich wissen, wie dies behoben werden kann.
Arun Gupta
37

Es gibt eine neue Funktion zum Ersetzen von sizeWithFont, die boundingRectWithSize ist.

Ich habe meinem Projekt die folgende Funktion hinzugefügt, die die neue Funktion unter iOS7 und die alte unter iOS unter 7 verwendet. Sie hat im Grunde die gleiche Syntax wie 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
        }
    }

Sie können IOS_NEWER_OR_EQUAL_TO_7 in Ihrer Datei prefix.pch in Ihrem Projekt wie folgt hinzufügen:

#define IOS_NEWER_OR_EQUAL_TO_7 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 7.0 )
Manecosta
quelle
Meine UITextViews lassen sich immer noch nicht gut skalieren und können gescrollt werden, wenn der Text 3 Zeilen umfasst. pastebin.com/Wh6vmBqh
Martin de Keijzer
Die zweite return-Anweisung gibt auch eine Verfallswarnung in XCode aus.
Martin de Keijzer
Stellen Sie in cellForRowAtIndexPath auch die Größe der UItextView auf die berechnete Größe des Texts ein? Sie sollten sich auch keine Gedanken über die Warnung in der zweiten Rückgabe machen, da sie nur verwendet wird, wenn die App auf einem iOS6-Gerät ausgeführt wird, auf dem die Funktion nicht veraltet ist.
Manecosta
Können Sie ein einfaches Beispiel für die Verwendung dieser Funktion geben?
Zorayr
In der Dokumentation von @manecosta Apple heißt es, dass Sie das Ergebnis "begrenzen" müssen: In iOS 7 und höher gibt diese Methode Bruchgrößen zurück (in der Größenkomponente des zurückgegebenen CGRect). Um eine zurückgegebene Ansicht von Größe zu Größe zu verwenden, müssen Sie den Wert mithilfe der Ceil-Funktion auf die nächsthöhere Ganzzahl erhöhen.
HpTerm
9

Wenn Sie UITableViewAutomaticDimension verwenden, habe ich eine wirklich einfache Lösung (nur iOS 8). In meinem Fall ist es eine statische Tabellenansicht, aber ich denke, Sie könnten dies für dynamische Prototypen anpassen ...

Ich habe einen Einschränkungsausgang für die Höhe der Textansicht und habe die folgenden Methoden wie folgt implementiert:

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

Denken Sie jedoch daran : Die Textansicht muss scrollbar sein, und Sie müssen Ihre Einschränkungen so einrichten, dass sie für die automatische Bemaßung funktionieren:

  • Richten Sie alle Ansichten in der Zelle relativ zueinander mit festen Höhen ein (einschließlich der Höhe der Textansicht, die Sie programmgesteuert ändern werden).
  • Die oberste Ansicht hat den oberen Abstand und die unterste Ansicht hat den unteren Abstand zur Superansicht.

Das grundlegendste Zellenbeispiel ist:

  • Keine anderen Ansichten in der Zelle außer der Textansicht
  • 0 Ränder um alle Seiten der Textansicht und eine vordefinierte Höhenbeschränkung für die Textansicht.
dec-vt100
quelle
1
Die
Textansicht
Ich bekomme die ganze Zeit unter updateTextviewHeight die gleiche Größe. Die Inhaltsgröße scheint falsch zu sein. Das Scrollen ist deaktiviert.
Dvole
5

Tim Bodeits Antwort ist großartig. Ich habe den Code von Simple Solution verwendet, um die Höhe der Textansicht korrekt zu ermitteln und diese Höhe in zu verwenden heightForRowAtIndexPath. Aber ich verwende den Rest der Antwort nicht, um die Größe der Textansicht zu ändern. Stattdessen schreibe ich Code, um die frameTextansicht in zu ändern cellForRowAtIndexPath.

In iOS 6 und darunter funktioniert alles, aber in iOS 7 kann der Text in der Textansicht nicht vollständig angezeigt werden, obwohl die frameGröße der Textansicht tatsächlich geändert wurde. (Ich benutze nicht Auto Layout). Es sollte der Grund sein, dass es in iOS 7 gibt TextKitund die Position des Textes von NSTextContainerin gesteuert wird UITextView. In meinem Fall muss ich also eine Zeile hinzufügen, um die someTextViewfestzulegen, damit sie in iOS 7 ordnungsgemäß funktioniert.

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

Wie in der Dokumentation angegeben, bewirkt diese Eigenschaft Folgendes:

Steuert, ob der Empfänger die Höhe seines Begrenzungsrechtecks ​​anpasst, wenn die Größe seiner Textansicht geändert wird. Standardwert: NEIN.

Wenn Sie den Standardwert beibehalten, wird nach dem Ändern der Größe framevon someTextViewdie Größe des textContainernicht geändert, was dazu führt, dass der Text nur in dem Bereich angezeigt werden kann, bevor die Größe geändert wird.

Und vielleicht muss das für den scrollEnabled = NOFall festgelegt werden, dass es mehr als einen gibt textContainer, damit der Text von einem textContainerzum anderen zurückfließt .

PowerQian
quelle
4

Hier ist eine weitere Lösung, die auf Einfachheit und schnelles Prototyping abzielt :

Konfiguration:

  1. Tabelle mit Prototypzellen.
  2. Jede Zelle enthält eine dynamische Größe UITextViewmit anderen Inhalten.
  3. Prototypzellen sind assoziiert mit TableCell.h.
  4. UITableViewist verbunden mit TableViewController.h.

Lösung:

(1) Hinzufügen zu 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) Hinzufügen zu 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;
}

Erläuterung:

Hier passiert also Folgendes: Jede Textansicht ist durch vertikale und horizontale Einschränkungen an die Höhe der Tabellenzellen gebunden. Wenn also die Höhe der Tabellenzellen zunimmt, vergrößert sich auch die Textansicht. Ich habe eine modifizierte Version des Codes von @ manecosta verwendet, um die erforderliche Höhe einer Textansicht zu berechnen, die zum angegebenen Text in eine Zelle passt. Das bedeutet, dass bei einem Text mit einer X-Anzahl von Zeichen frameForText:eine Größe zurückgegeben wird, deren Eigenschaft size.heightder erforderlichen Höhe der Textansicht entspricht.

Jetzt müssen Sie nur noch die Höhe der Zelle aktualisieren, um sie an die Höhe der erforderlichen Textansicht anzupassen. Und das wird erreicht bei heightForRowAtIndexPath:. Wie in den Kommentaren erwähnt, size.heightsollte nur ein Versatz hinzugefügt werden , da nur die Höhe für die Textansicht und nicht die gesamte Zelle angegeben ist. Im Beispiel betrug dieser Wert 80.

Zorayr
quelle
Wofür steht dieser 'dream.dream'?
MyJBMe
@MyJBMe Entschuldigung, das war Teil meines eigenen Projekts - ich habe den Code entsprechend aktualisiert. dream.dreamwar der Text, den ich in der Textansicht gerendert habe.
Zorayr
3

Ein Ansatz, wenn Sie Autolayout verwenden, besteht darin, die Autolayout-Engine die Größe für Sie berechnen zu lassen. Dies ist nicht der effizienteste Ansatz, aber ziemlich praktisch (und wohl der genaueste). Mit zunehmender Komplexität des Zellenlayouts wird es bequemer - z. B. haben Sie plötzlich zwei oder mehr Textansichten / Felder in der Zelle.

Ich beantwortete eine ähnliche Frage mit einem vollständigen Beispiel für die Dimensionierung von Tabellenansichtszellen mithilfe des automatischen Layouts hier:

Wie kann ich die Größe der Übersicht ändern, um sie an alle Unteransichten mit Autolayout anzupassen?

TomSwift
quelle
1

Die vollständige glatte Lösung ist wie folgt.

Zuerst benötigen wir die Zellenklasse mit einer Textansicht

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

Als nächstes verwenden wir es im 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
  • Hier minLineskönnen Sie die Mindesthöhe für die Textansicht festlegen (um der Höhenminimierung durch AutoLayout mit UITableViewAutomaticDimension zu widerstehen).

  • moveRowAtIndexPath:indexPath: Mit demselben IndexPath wird die Neuberechnung und das Layout der tableViewCell-Höhe gestartet.

  • performWithoutAnimation: Entfernt Nebeneffekte (TableView-Inhaltsoffset springt beim Starten einer neuen Zeile während der Eingabe).

  • Es ist wichtig, relativeFrameOriginY(nicht contentOffsetY!) Während der contentSizeZellenaktualisierung beizubehalten, da die Zellen, bevor die aktuelle Zelle auf unerwartete Weise durch AutoLayout-Berechnung geändert werden kann. Es entfernt visuelle Sprünge bei der Silbentrennung des Systems, während lange Wörter eingegeben werden.

  • Beachten Sie, dass Sie die Eigenschaft nicht festlegen sollten estimatedRowHeight ! Folgendes funktioniert nicht

    self.tableView.estimatedRowHeight = UITableViewAutomaticDimension;

    Verwenden Sie nur die tableViewDelegate-Methode.

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

Wenn es Ihnen nichts ausmacht, eine schwache Bindung zwischen tableView und tableViewCell zu verhindern und die Geometrie der tableView von tableViewCell aus zu aktualisieren , können Sie die obige TextInputTableViewCellKlasse aktualisieren :

@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
quelle
1
  1. Stellen Sie UILabel hinter Ihre UITextView.
  2. Verwenden Sie diese Antwort: https://stackoverflow.com/a/36054679/6681462 an UILabel, das Sie erstellt haben
  3. Geben Sie ihnen die gleichen Einschränkungen und Schriftarten
  4. Setze ihnen den gleichen Text;

Die Höhe Ihrer Zelle wird anhand des Inhalts von UILabel berechnet, der gesamte Text wird jedoch von TextField angezeigt.

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

Ich denke, auf diese Weise können Sie die Höhe Ihrer Textansicht zählen und dann die Größe Ihrer Tabellenansichtszelle entsprechend dieser Höhe ändern, sodass Sie den vollständigen Text in der Zelle anzeigen können

D-eptdeveloper
quelle
0

Schnelle Version

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
quelle
0

Wenn Sie die UITableViewCellHöhe automatisch an die Höhe der inneren UITextViewHöhe anpassen möchten . Siehe meine Antwort hier: https://stackoverflow.com/a/45890087/1245231

Die Lösung ist ganz einfach und sollte sicher seit iOS 7. funktioniert , dass die Scrolling EnabledOption aktiviert ist ausgeschaltet für die UITextViewinnerhalb der UITableViewCellim Storyboard.

Dann setzen Sie in viewDidLoad () Ihres UITableViewControllers das tableView.rowHeight = UITableViewAutomaticDimensionund tableView.estimatedRowHeight > 0wie:

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 44.0
}

Das ist es. UITableViewCellDie Höhe wird automatisch an die UITextViewHöhe des Innenraums angepasst .

petrsyn
quelle
-2

Für iOS 8 und höher können Sie einfach verwenden

your_tablview.estimatedrowheight= minheight Sie wollen

your_tableview.rowheight=UItableviewautomaticDimension
Sandig
quelle