Festlegen der benutzerdefinierten UITableViewCells-Höhe

222

Ich verwende eine benutzerdefinierte UITableViewCell, in der einige Beschriftungen, Schaltflächen und Bildansichten angezeigt werden sollen. In der Zelle befindet sich eine Bezeichnung, deren Text ein NSStringObjekt ist und deren Länge variabel sein kann. Aus diesem Grund kann ich in der Methode von UITableView's keine konstante Höhe für die Zelle festlegen heightForCellAtIndex. Die Höhe der Zelle hängt von der Höhe des Etiketts ab, die mit der Methode von NSString's sizeWithFontbestimmt werden kann. Ich habe versucht, es zu benutzen, aber es sieht so aus, als würde ich irgendwo falsch liegen. Wie kann es behoben werden?

Hier ist der Code, der zum Initialisieren der Zelle verwendet wird.

if (self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier])
{
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    UIImage *image = [UIImage imageNamed:@"dot.png"];
    imageView = [[UIImageView alloc] initWithImage:image];
    imageView.frame = CGRectMake(45.0,10.0,10,10);

    headingTxt = [[UILabel alloc] initWithFrame:   CGRectMake(60.0,0.0,150.0,post_hdg_ht)];
    [headingTxt setContentMode: UIViewContentModeCenter];
    headingTxt.text = postData.user_f_name;
    headingTxt.font = [UIFont boldSystemFontOfSize:13];
    headingTxt.textAlignment = UITextAlignmentLeft;
    headingTxt.textColor = [UIColor blackColor];

    dateTxt = [[UILabel alloc] initWithFrame:CGRectMake(55.0,23.0,150.0,post_date_ht)];
    dateTxt.text = postData.created_dtm;
    dateTxt.font = [UIFont italicSystemFontOfSize:11];
    dateTxt.textAlignment = UITextAlignmentLeft;
    dateTxt.textColor = [UIColor grayColor];

    NSString * text1 = postData.post_body;
    NSLog(@"text length = %d",[text1 length]);
    CGRect bounds = [UIScreen mainScreen].bounds;
    CGFloat tableViewWidth;
    CGFloat width = 0;
    tableViewWidth = bounds.size.width/2;
    width = tableViewWidth - 40; //fudge factor
    //CGSize textSize = {width, 20000.0f}; //width and height of text area
    CGSize textSize = {245.0, 20000.0f}; //width and height of text area
    CGSize size1 = [text1 sizeWithFont:[UIFont systemFontOfSize:11.0f]
                        constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];

    CGFloat ht = MAX(size1.height, 28);
    textView = [[UILabel alloc] initWithFrame:CGRectMake(55.0,42.0,245.0,ht)];
    textView.text = postData.post_body;
    textView.font = [UIFont systemFontOfSize:11];
    textView.textAlignment = UITextAlignmentLeft;
    textView.textColor = [UIColor blackColor];
    textView.lineBreakMode = UILineBreakModeWordWrap;
    textView.numberOfLines = 3;
    textView.autoresizesSubviews = YES;

    [self.contentView addSubview:imageView];
    [self.contentView addSubview:textView];
    [self.contentView addSubview:webView];
    [self.contentView addSubview:dateTxt];
    [self.contentView addSubview:headingTxt];
    [self.contentView sizeToFit];

    [imageView release];
    [textView release];
    [webView release];
    [dateTxt release];
    [headingTxt release];
}

Dies ist das Etikett, dessen Höhe und Breite falsch sind:

textView = [[UILabel alloc] initWithFrame:CGRectMake(55.0,42.0,245.0,ht)];
Vijayeta
quelle

Antworten:

499

Sie UITableViewDelegatesollten implementierentableView:heightForRowAtIndexPath:

Ziel c

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return [indexPath row] * 20;
}

Swift 5

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return indexPath.row * 20
}

Sie wollen wahrscheinlich verwenden NSString‚s sizeWithFont:constrainedToSize:lineBreakMode:Methode , um Ihre Zeilenhöhe zu berechnen , anstatt nur auf dem indexPath einige dumme Mathe Durchführung :)

rpetrich
quelle
1
Meinst du nicht [indexPath row] + 20?
Fulvio
11
Fulvio: Nein, es ging darum, dass die Reihen offensichtlich unterschiedliche Höhen haben.
rpetrich
5
So stellen Sie eine bestimmte Höhe ein (z. B. 44 Pixel): return 44;
mpemburn
Können Sie ein paar weitere Details zur Verwendung dieser Größe angeben? WithFont: ConstrainedToSize: lineBreakMode :? Ich habe eine Textansicht in meiner Zelle und möchte ihre Höhe in heightForRowAtIndexPath abrufen: um die Höhe der Zeile festzulegen, aber ich weiß nicht, wie ich sie erhalten soll! Danke
rdurand
Wenn Sie "[Indexzeile] * (ein Wert)" zurückgeben, ist die erste Zelle möglicherweise nicht sichtbar, da der erste zurückgegebene Wert Null ist. Daher ist es besser, die benötigte Zellenhöhe zu berechnen und den berechneten Wert hier zurückzugeben, um alle Zellen sichtbar zu machen
Vinayak GH
134

Wenn alle Ihre Zeilen dieselbe Höhe haben, legen Sie einfach die rowHeightEigenschaft von UITableView fest, anstatt die zu implementieren heightForRowAtIndexPath. Apple Docs:

Die Verwendung von tableView: heightForRowAtIndexPath: anstelle von rowHeight hat Auswirkungen auf die Leistung. Jedes Mal, wenn eine Tabellenansicht angezeigt wird, ruft sie tableView: heightForRowAtIndexPath: für den Delegaten für jede seiner Zeilen auf, was zu einem erheblichen Leistungsproblem bei Tabellenansichten mit einer großen Anzahl von Zeilen (ungefähr 1000 oder mehr) führen kann.

jokkedk
quelle
5
Dies funktioniert einwandfrei, wenn alle Reihen die gleiche Höhe haben. Das Originalplakat weist diese Situation jedoch nicht auf, sodass die Antwort an sich nicht falsch ist, aber die ursprüngliche Frage nicht beantwortet. JEDOCH finde ich es wichtig , dass Einstellung rowHeight höchstwahrscheinliche Erträge beachten bessere Leistung als zwingende heightForRowAtIndexPath weil Dinge wie die Berechnung die Scrollbar Dimensionen ist O (1) anstelle von O (n) in diesem Fall.
Daniel Albuschat
2
Beachten Sie auch (aus offensichtlichen Gründen), dass wenn tableView.rowHeightgesetzt ist, heightForRowAtIndexPathnicht aufgerufen wird, falls Sie versuchen herauszufinden, warum (wie ich).
Devios1
25

Fügen Sie dies in einem benutzerdefinierten UITableViewCell-Controller hinzu

-(void)layoutSubviews {  

    CGRect newCellSubViewsFrame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
    CGRect newCellViewFrame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height);

    self.contentView.frame = self.contentView.bounds = self.backgroundView.frame = self.accessoryView.frame = newCellSubViewsFrame;
    self.frame = newCellViewFrame;

    [super layoutSubviews];
}

Fügen Sie dies im UITableView-Controller hinzu

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return [indexPath row] * 1.5; // your dynamic height...
}
hfossli
quelle
CGRect newCellSubViewsFrame = self.bounds; CGRect newCellViewFrame = self.frame;
Pizzaiola Gorgonzola
17
#define FONT_SIZE 14.0f
#define CELL_CONTENT_WIDTH 300.0f
#define CELL_CONTENT_MARGIN 10.0f

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath      *)indexPath;
{
   /// Here you can set also height according to your section and row
   if(indexPath.section==0 && indexPath.row==0)
   {
     text=@"pass here your dynamic data";

     CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);

     CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE]      constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

     CGFloat height = MAX(size.height, 44.0f);

     return height + (CELL_CONTENT_MARGIN * 2);
   }
   else
   {
      return 44;
   }
}

- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell;
    UILabel *label = nil;

    cell = [tv dequeueReusableCellWithIdentifier:@"Cell"];
    if (cell == nil)
    {
       cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"];
    }
    ********Here you can set also height according to your section and row*********
    if(indexPath.section==0 && indexPath.row==0)
    {
        label = [[UILabel alloc] initWithFrame:CGRectZero];
        [label setLineBreakMode:UILineBreakModeWordWrap];
        [label setMinimumFontSize:FONT_SIZE];
        [label setNumberOfLines:0];
        label.backgroundColor=[UIColor clearColor];
        [label setFont:[UIFont systemFontOfSize:FONT_SIZE]];
        [label setTag:1];

        // NSString *text1 =[NSString stringWithFormat:@"%@",text];

        CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);

        CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

        if (!label)
        label = (UILabel*)[cell viewWithTag:1];


        label.text=[NSString stringWithFormat:@"%@",text];
        [label setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH          - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 44.0f))];
        [cell.contentView addSubview:label];
    }
return cell;
}
ravinder521986
quelle
8
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
    CGSize constraintSize = {245.0, 20000}
    CGSize neededSize = [ yourText sizeWithFont:[UIfont systemFontOfSize:14.0f] constrainedToSize:constraintSize  lineBreakMode:UILineBreakModeCharacterWrap]
if ( neededSize.height <= 18) 

   return 45
else return neededSize.height + 45 
//18 is the size of your text with the requested font (systemFontOfSize 14). if you change fonts you have a different number to use  
// 45 is what is required to have a nice cell as the neededSize.height is the "text"'s height only
//not the cell.

}
Alice
quelle
8

Ich habe viele Lösungen gesehen, aber alles war falsch oder unvollständig. Sie können alle Probleme mit 5 Zeilen in viewDidLoad und Autolayout lösen. Dies für Ziel C:

_tableView.delegate = self;
_tableView.dataSource = self;
self.tableView.estimatedRowHeight = 80;//the estimatedRowHeight but if is more this autoincremented with autolayout
self.tableView.rowHeight = UITableViewAutomaticDimension;
[self.tableView setNeedsLayout];
[self.tableView layoutIfNeeded];
self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0) ;

Für schnelle 2.0:

 self.tableView.estimatedRowHeight = 80
 self.tableView.rowHeight = UITableViewAutomaticDimension      
 self.tableView.setNeedsLayout()
 self.tableView.layoutIfNeeded()
 self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0)

Erstellen Sie jetzt Ihre Zelle mit xib oder in der Tabellenansicht in Ihrem Storyboard. Damit müssen Sie nichts mehr implementieren oder überschreiben. (Vergessen Sie nicht die Anzahl der Zeilen 0) und das untere Etikett (Einschränkung) stufen "Content Hugging Priority - Vertical to 250" herab.

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Sie können den Code in der nächsten URL herunterladen: https://github.com/jposes22/exampleTableCellCustomHeight

Jose Pose S.
quelle
1
In 2 Tagen werde ich mehr Bilder mit derselben Zelle mit Zeichen ImageView und anderen Untertabellenansichten einfügen. Diese Methode funktioniert immer. Danke für +1 wirklich.
Jose Pose S
Das ist großartig!! Es wird auch anderen helfen. Danke :)
jagdish
Wie versprochen haben Sie hier neuen Code und ein neues Image.
Jose Pose S
Vielen Dank ... weiter so ...- :)
jagdish
Diese Lösung funktioniert nicht, wenn Sie die UITableViewCell programmgesteuert erstellen, z. B. ohne Interface Builder
MB_iOSDeveloper
6

Stellen Sie zum Festlegen der automatischen Bemaßung für die Zeilenhöhe und der geschätzten Zeilenhöhe die folgenden Schritte sicher, damit die automatische Bemaßung für das Layout der Zellen- / Zeilenhöhe wirksam wird.

  • Zuweisen und Implementieren von tableview dataSource und Delegieren
  • Zuweisen UITableViewAutomaticDimensionzu rowHeight & geschätzteRowHeight
  • Implementieren Sie delegate / dataSource-Methoden (dh heightForRowAtgeben Sie einen Wert zurück UITableViewAutomaticDimension)

- -

Ziel c:

// in ViewController.h
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

  @property IBOutlet UITableView * table;

@end

// in ViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    self.table.dataSource = self;
    self.table.delegate = self;

    self.table.rowHeight = UITableViewAutomaticDimension;
    self.table.estimatedRowHeight = UITableViewAutomaticDimension;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    return UITableViewAutomaticDimension;
}

Schnell:

@IBOutlet weak var table: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Don't forget to set dataSource and delegate for table
    table.dataSource = self
    table.delegate = self

    // Set automatic dimensions for row height
    table.rowHeight = UITableViewAutomaticDimension
    table.estimatedRowHeight = UITableViewAutomaticDimension
}



// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Für Label-Instanz in UITableviewCell

  • Stellen Sie die Anzahl der Zeilen auf 0 ein (& Zeilenumbruchmodus = Schwanz abschneiden)
  • Legen Sie alle Einschränkungen (oben, unten, rechts links) in Bezug auf die Übersicht / den Zellencontainer fest.
  • Optional : Legen Sie die Mindesthöhe für das Etikett fest, wenn Sie möchten, dass der vertikale Mindestbereich vom Etikett abgedeckt wird, auch wenn keine Daten vorhanden sind.

Geben Sie hier die Bildbeschreibung ein

Hinweis : Wenn Sie mehr als ein Etikett (UIElements) mit dynamischer Länge haben, das entsprechend seiner Inhaltsgröße angepasst werden sollte: Passen Sie die Priorität "Inhaltsumarmung und Kompressionswiderstand" für Etiketten an, die Sie mit höherer Priorität erweitern / komprimieren möchten.

Hier in diesem Beispiel habe ich eine niedrige Priorität für Umarmung und hohe Kompressionsbeständigkeit festgelegt, was dazu führt, dass für den Inhalt des zweiten (gelben) Etiketts mehr Priorität / Wichtigkeit festgelegt wird.

Geben Sie hier die Bildbeschreibung ein

Krunal
quelle
5

Dank aller Beiträge zu diesem Thema gibt es einige wirklich hilfreiche Möglichkeiten, die Zeilenhöhe einer UITableViewCell anzupassen.

Hier ist eine Zusammenstellung einiger Konzepte von allen anderen, die beim Erstellen für das iPhone und iPad wirklich hilfreich sind. Sie können auch auf verschiedene Abschnitte zugreifen und diese an die unterschiedlichen Größen der Ansichten anpassen.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
    int cellHeight = 0;

    if ([indexPath section] == 0) 
    {
        cellHeight = 16;
        settingsTable.rowHeight = cellHeight;
    }
    else if ([indexPath section] == 1)
    {
        cellHeight = 20;
        settingsTable.rowHeight = cellHeight;
    }

    return cellHeight;
}
else
{
    int cellHeight = 0;

    if ([indexPath section] == 0) 
    {
        cellHeight = 24;
        settingsTable.rowHeight = cellHeight;
    }
    else if ([indexPath section] == 1)
    {
        cellHeight = 40;
        settingsTable.rowHeight = cellHeight;
    }

    return cellHeight;
}
return 0;
} 
Whyoz
quelle
Bei der Analyse in XCode wird die Zeile "int cellHeight" angezeigt. hat einen logischen Fehler erstellt: "Undefinierter oder an den Aufrufer zurückgegebener Garbage-Wert." Durch Setzen von cellHeight auf 0 wurde der Fehler behoben. Dieser Fehler wird auch angezeigt, wenn Sie in einer switch-Anweisung, die der obigen if / else if-Anweisung ähnelt, keinen NSString auf nil setzen.
Whyoz
3

Um die dynamische -heightForRowAtIndexPathZellenhöhe mit zunehmendem Text von Label zu erhalten, müssen Sie zuerst die Höhe berechnen, die der Text in der Delegate-Methode verwenden wird, und sie mit den zusätzlichen Höhen anderer Etiketten und Bilder zurückgeben (maximale Höhe des Texts + Höhe anderer statischer Elemente) Komponenten) und verwenden die gleiche Höhe bei der Zellenerstellung.

#define FONT_SIZE 14.0f
#define CELL_CONTENT_WIDTH 300.0f  
#define CELL_CONTENT_MARGIN 10.0f

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

    if (indexPath.row == 2) {  // the cell you want to be dynamic

        NSString *text = dynamic text for your label;

        CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
        CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

        CGFloat height = MAX(size.height, 44.0f);

        return height + (CELL_CONTENT_MARGIN * 2);
    }
    else {
        return 44; // return normal cell height
    }
}

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

    static NSString *CellIdentifier = @"Cell";

    UILabel *label;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] ;
    }

    label = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, 280, 34)];

    [label setNumberOfLines:2];

    label.backgroundColor = [UIColor clearColor];

    [label setFont:[UIFont systemFontOfSize:FONT_SIZE]];

    label.adjustsFontSizeToFitWidth = NO;

    [[cell contentView] addSubview:label];


    NSString *text = dynamic text fro your label;

    [label setText:text];

    if (indexPath.row == 2) {// the cell which needs to be dynamic 

        [label setNumberOfLines:0];

        CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);

        CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

        [label setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 44.0f))];

    }
    return  cell;
}
Samir Jwarchan
quelle
@Tisho Hast du es getestet, Tisho bro, um die Abstimmung abzustimmen? Teste sorgfältig, es funktioniert, Bruder !!!!
Samir Jwarchan
1
Ich habe Ihre Antwort nicht abgelehnt. Ich habe gerade die Formatierung verbessert.
Tisho