webentwicklung-frage-antwort-db.com.de

Dynamische UITableView-Zellenhöhe basierend auf Inhalt

Ich habe eine UITableView, die mit benutzerdefinierten Zellen gefüllt ist (geerbt von UITableViewCell). Jede Zelle enthält eine UIWebView, deren Größe sich automatisch an den Inhalt anpasst. Wie kann ich die Höhe der UITableView-Zellen basierend auf ihrem Inhalt (Variable webView) ändern?.

Die Lösung muss dynamisch sein, da der zum Auffüllen der UIWebViews verwendete HTML-Code aus einem sich ständig ändernden Feed analysiert wird.

Ich habe das Gefühl, dass ich die Delegatenmethode UITableViewheightForRowAtIndexPath verwenden muss, aber aus ihrer Definition:

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ;//This needs to be variable
}

Ich kann nicht auf die Zelle oder deren Inhalt zugreifen. Kann ich die Höhe der Zelle in cellForRowAtIndexPath ändern?

Jede Hilfe wäre großartig. Vielen Dank.

Hinweis

Ich habe diese Frage vor über 2 Jahren gestellt. Mit dem Intro des automatischen Layouts kann die beste Lösung für iOS7 gefunden werden:

http://t.co/PdUywcTjhu

und unter iOS8 ist diese Funktionalität im SDK enthalten

21
Adam Waite

Die beste Methode, die ich für die dynamische Höhe gefunden habe, besteht darin, die Höhe im Voraus zu berechnen und in einer Art Sammlung (wahrscheinlich in einem Array) zu speichern. Wenn die Zelle hauptsächlich Text enthält, können Sie mit -[NSString sizeWithFont:constrainedToSize:lineBreakMode:] die Höhe berechnen und dann den entsprechenden Wert in heightForRowAtIndexPath: zurückgeben

[BEARBEITEN] Wenn sich der Inhalt ständig ändert, können Sie eine Methode implementieren, mit der das Höhenfeld aktualisiert wird, wenn neue Daten bereitgestellt wurden.

19
Nyth

Das funktioniert normalerweise ziemlich gut:

Ziel c:

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

Schnell:

override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
    return UITableViewAutomaticDimension;
}
23
Santa Claus

Ich habe viele Lösungen ausprobiert, aber die, die funktionierte, war folgende, vorgeschlagen von einem Freund

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

    int height = [StringUtils findHeightForText:yourLabel havingWidth:yourWidth andFont:[UIFont systemFontOfSize:17.0f]];

    height += [StringUtils findHeightForText:yourOtherLabel havingWidth:yourWidth andFont:[UIFont systemFontOfSize:14.0f]];

    return height + CELL_SIZE_WITHOUT_LABELS; //important to know the size of your custom cell without the height of the variable labels
}

Die StringUtils.h-Klasse:

#import <Foundation/Foundation.h>

@interface StringUtils : NSObject

+ (CGFloat)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font;

@end

StringUtils.m-Klasse:

#import "StringUtils.h"

@implementation StringUtils

+ (CGFloat)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font {
    CGFloat result = font.pointSize+4;
    if (text) {
        CGSize size;

        CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX)
                                          options:NSStringDrawingUsesLineFragmentOrigin
                                       attributes:@{NSFontAttributeName:font}
                                          context:nil];
        size = CGSizeMake(frame.size.width, frame.size.height+1);
        result = MAX(size.height, result); //At least one row
    }
    return result;
}

@end

Es hat perfekt für mich funktioniert. Ich hatte eine benutzerdefinierte Zelle mit 3 Bildern mit festen Größen, 2 Etiketten mit festen Größen und 2 variablen Etiketten. Lief wie am Schnürchen. Ich hoffe es funktioniert auch für dich.

Viele Grüße, Alexandre.

5
Alexandre
self.tblVIew.estimatedRowHeight = 500.0; // put max you expect here.
self.tblVIew.rowHeight = UITableViewAutomaticDimension;
5
user3693546

Das große Problem bei Zellen mit dynamischer Höhe in iOS ist, dass die Tabelle vc die Höhe jeder Zelle berechnen und zurückgeben muss, bevor die Zellen gezeichnet werden. Bevor eine Zelle gezeichnet wird, hat sie jedoch keinen Rahmen und somit keine Breite. Dies führt zu einem Problem, wenn die Höhe der Zelle in der Zelle beispielsweise anhand der Textmenge im textLabel geändert werden soll, da deren Breite nicht bekannt ist.

Eine häufige Lösung, die ich gesehen habe, ist, dass Leute einen numerischen Wert für die Zellenbreite definieren. Dies ist ein schlechter Ansatz, da Tabellen einfach oder gruppiert sein können, das iOS 7- oder iOS 6-Styling verwenden, auf einem iPhone oder iPad angezeigt werden können, im Quer- oder Hochformat usw.

Ich hatte Probleme mit diesen Problemen in einer meiner iOS-Apps, die iOS5 + und sowohl iPhone als auch iPad mit mehreren Ausrichtungen unterstützt. Ich brauchte eine bequeme Möglichkeit, dies zu automatisieren und die Logik aus dem View-Controller herauszulassen. Das Ergebnis wurde zu einer UITableViewController-Unterklasse (damit sie den Status halten kann), die Standardzellen (Standard- und Untertitelstil) sowie benutzerdefinierte Zellen unterstützt.

Sie können es unter GitHub ( https://github.com/danielsaidi/AutoSizeTableView ) herunterladen. Ich hoffe, es hilft denjenigen von Ihnen, die sich noch mit diesem Problem zu kämpfen haben. Wenn Sie es überprüfen, würde ich gerne hören, was Sie denken und ob es für Sie geklappt hat.

3
Daniel Saidi

Hier der Code, den ich für die dynamische Zellenhöhe verwendet habe, als er Tweets von Twitter abruft und sie dann zum Offline-Lesen in CoreData speichert.

Dies zeigt nicht nur, wie der Zell- und Dateninhalt abgerufen wird, sondern auch, wie ein UILabel dynamisch mit Padding an den Inhalt angepasst wird

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

    Tweet *Tweet = [self.fetchedResultsController objectAtIndexPath:indexPath];

    NSString* text = Tweet.Text;

    TweetTableViewCell *cell = (TweetTableViewCell*)[self tableView:tableView cellForRowAtIndexPath:indexPath];

    //Set the maximum size
    CGSize maximumLabelSize = cell.tweetLabel.frame.size;
    CGPoint originalLocation = cell.tweetLabel.frame.Origin;

    //Calculate the new size based on the text
    CGSize expectedLabelSize = [text sizeWithFont:cell.tweetLabel.font constrainedToSize:maximumLabelSize lineBreakMode:cell.tweetLabel.lineBreakMode];


    //Dynamically figure out the padding for the cell
    CGFloat topPadding = cell.tweetLabel.frame.Origin.y - cell.frame.Origin.y;


    CGFloat bottomOfLabel = cell.tweetLabel.frame.Origin.y + cell.tweetLabel.frame.size.height;
    CGFloat bottomPadding = cell.frame.size.height - bottomOfLabel;


    CGFloat padding = topPadding + bottomPadding;


    CGFloat topPaddingForImage = cell.profileImage.frame.Origin.y - cell.frame.Origin.y;
    CGFloat minimumHeight = cell.profileImage.frame.size.height + topPaddingForImage + bottomPadding;

    //adjust to the new size
    cell.tweetLabel.frame = CGRectMake(originalLocation.x, originalLocation.y, cell.tweetLabel.frame.size.width, expectedLabelSize.height);


    CGFloat cellHeight = expectedLabelSize.height + padding;

    if (cellHeight < minimumHeight) {

        cellHeight = minimumHeight;
    }

    return cellHeight;
}
3
Joseph DeCarlo

Ich denke auch, dass ein solcher Algorithmus zu Ihnen passt:

1) In cellForrowAtIndexPath aktivieren Sie Ihre Webviews zum Laden und geben ihnen Tags gleich indexPath.row

2) In webViewDidFinishLoading berechnen Sie die Höhe des Inhalts in der Zelle und erstellen ein Wörterbuch mit Schlüsseln und Werten wie folgt: key = indexPath.row value = height

3) Aufruf [tableview reloadData] 

4) Legen Sie in [tableview cellForRowAtIndexPath: indexPath] die korrekten Höhen für entsprechende Zellen fest

3
alex

Dies ist eine meiner schönen Lösungen. es hat für mich gearbeitet.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    cell.textLabel.text = [_nameArray objectAtIndex:indexPath.row];
    cell.textLabel.numberOfLines = 0;
    cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
}

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

Wir müssen diese 2 Änderungen anwenden.

1)cell.textLabel.numberOfLines = 0;
  cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;

2)return UITableViewAutomaticDimension;
1
iOS

Ich implementiere dies immer in allen meinen Zellen in einer Superzellklasse, weil UITableViewAutomaticDimension aus irgendeinem Grund nicht so gut funktioniert.

-(CGFloat)cellHeightWithData:(id)data{
    CGFloat height = [[self contentView] systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
    [self fillCellWithData:data]; //set the label's text or anything that may affect the size of the cell
    [self layoutIfNeeded];
    height = [[self contentView] systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
    return height+1; //must add one because of the cell separator
}

rufen Sie diese Methode einfach auf Ihrer -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath mit einer Dummy-Zelle auf.

hinweis: Dies funktioniert nur mit Autolayout, aber auch mit iOS 7 und höher.

pd: Vergessen Sie nicht, das Kontrollkästchen im Xib oder Storyboard auf "bevorzugte Breite explizit" zu setzen und die statische Breite festzulegen (im Menü cmd + Alt + 5 ). 

0
user2387149

Swift Verwenden Sie benutzerdefinierte Zellen und Beschriftungen. Richten Sie die Einschränkungen für das UILabel ein. (oben, links, unten, rechts) Setzen Sie die Zeilen der UILabel auf 0

Fügen Sie in der viewDidLoad-Methode des ViewControllers den folgenden Code hinzu:

tableView.estimatedRowHeight = 68.0
tableView.rowHeight = UITableViewAutomaticDimension

// Delegieren und Datenquelle

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension;
}
0
user7587085

Ich hatte einen sehr großen Test in UILabel. Vor allem nicht funktionieren, dann erstelle ich eine Kategorie für String wie unten und bekam die genaue Höhe

- (CGFloat)heightStringWithEmojifontType:(UIFont *)uiFont ForWidth:(CGFloat)width {

// Get text
CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), (CFStringRef) self );
CFIndex stringLength = CFStringGetLength((CFStringRef) attrString);

// Change font
CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef) uiFont.fontName, uiFont.pointSize, NULL);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, stringLength), kCTFontAttributeName, ctFont);

// Calc the size
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString);
CFRange fitRange;
CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(width, CGFLOAT_MAX), &fitRange);

CFRelease(ctFont);
CFRelease(framesetter);
CFRelease(attrString);

return frameSize.height + 10;}
0
GSK

In Swift 4+ können Sie es dinamic einstellen

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableView.automaticDimension
}
0
Diego Carrera