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 UITableView
heightForRowAtIndexPath
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.
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:
und unter iOS8 ist diese Funktionalität im SDK enthalten
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.
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;
}
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.
self.tblVIew.estimatedRowHeight = 500.0; // put max you expect here.
self.tblVIew.rowHeight = UITableViewAutomaticDimension;
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.
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;
}
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
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;
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 ).
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;
}
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;}
In Swift 4+ können Sie es dinamic einstellen
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}