web-dev-qa-db-ger.com

Die Einstellung der benutzerdefinierten Zellenzeilenhöhe im Storyboard reagiert nicht

Ich versuche, die Zellenhöhe für eine der Zellen in meiner Tabellenansicht anzupassen. Ich stelle die Größe über die Einstellung "Zeilenhöhe" im "Größeninspektor" der betreffenden Zelle ein. Wenn ich die App auf meinem iPhone starte, hat die Zelle die Standardgröße, die in der Tabellenansicht als "Zeilengröße" festgelegt wurde.

Wenn ich die "Zeilengröße" der Tabellenansicht ändere, ändert sich die Größe aller Zellen. Ich möchte das nicht tun, da ich nur für eine Zelle eine benutzerdefinierte Größe haben möchte. Ich habe viele Beiträge gesehen, die eine programmatische Lösung für das Problem haben, aber ich würde es am liebsten über das Storyboard tun, wenn dies möglich ist.

205
zirinisp

Bei dynamic cells überschreibt rowHeight auf UITableView immer die rowHeight der einzelnen Zellen.

Auf static cells kann jedoch rowHeight auf einzelne Zellen gesetzt werden, die UITableView-Werte überschreiben können.

Nicht sicher, ob es sich um einen Fehler handelt, könnte Apple dies absichtlich tun?

287
pixelfreak

Wenn Sie UITableViewController verwenden, implementieren Sie diese Methode:

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

In der Funktion einer Reihe können Sie Höhe wählen. Zum Beispiel,

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 0) {
       return 100;
    } 
    else {
       return 60;
    }
}

In diesem Beispiel beträgt die erste Zeilenhöhe 100 Pixel und die anderen Zeilen 60 Pixel.

Ich hoffe das kann dir helfen.

82
Beber

Bei dynamischen Zellen überschreibt rowHeight auf UITableView immer die rowHeight der einzelnen Zellen. 

Dieses Verhalten ist IMO ein Fehler. Immer wenn Sie Ihre Benutzeroberfläche an zwei Stellen verwalten müssen, ist sie fehleranfällig. Wenn Sie beispielsweise die Zellengröße im Storyboard ändern, müssen Sie auch daran denken, sie im heightForRowAtIndexPath: zu ändern. Bis Apple den Fehler behebt, besteht die derzeit beste Lösung darin, heightForRowAtIndexPath: zu überschreiben. Verwenden Sie jedoch die Prototypzellen aus dem Storyboard, um die Höhe zu bestimmen, anstatt magische Zahlen zu verwenden. Hier ist ein Beispiel:

- (CGFloat)tableView:(UITableView *)tableView 
           heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    /* In this example, there is a different cell for
       the top, middle and bottom rows of the tableView.
       Each type of cell has a different height.
       self.model contains the data for the tableview 
    */
    static NSString *CellIdentifier;
    if (indexPath.row == 0) 
        CellIdentifier = @"CellTop";
    else if (indexPath.row + 1 == [self.model count] )
        CellIdentifier = @"CellBottom";
    else
        CellIdentifier = @"CellMiddle";

    UITableViewCell *cell = 
              [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    return cell.bounds.size.height;
}

Dadurch wird sichergestellt, dass Änderungen an den Prototypzellenhöhen automatisch zur Laufzeit erfasst werden und Sie müssen Ihre Benutzeroberfläche nur an einer Stelle verwalten: dem Storyboard.

34
memmons

Ich habe den Code mit den verschiedenen Antworten/Kommentaren versehen, so dass dies für Storyboards funktioniert, die Prototypzellen verwenden.

Dieser Code:

  • Erfordert nicht, dass die Zellenhöhe an einem anderen Ort als dem naheliegenden Ort im Storyboard festgelegt wird
  • Zwischenspeichert die Höhe aus Leistungsgründen
  • Verwendet eine allgemeine Funktion, um den Zellenbezeichner für einen Indexpfad abzurufen, um doppelte Logik zu vermeiden

Vielen Dank an Answerbot, Brennan und Lensovet.

- (NSString *)cellIdentifierForIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = nil;

    switch (indexPath.section)
    {
        case 0:
            cellIdentifier = @"ArtworkCell";
            break;
         <... and so on ...>
    }

    return cellIdentifier;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];
    static NSMutableDictionary *heightCache;
    if (!heightCache)
        heightCache = [[NSMutableDictionary alloc] init];
    NSNumber *cachedHeight = heightCache[cellIdentifier];
    if (cachedHeight)
        return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    <... configure cell as usual...>
22
JosephH

Es gibt zwei Stellen, an denen Sie die Zeilenhöhe ändern müssen, zuerst die Zelle (die Sie bereits geändert haben) Wählen Sie nun die Tabellenansicht aus und überprüfen Sie den Größeninspektor

19
Kristjan H.

Ich denke es ist ein Fehler.

Passen Sie die Höhe nicht mit dem Utility-Inspector an, sondern ziehen Sie sie direkt auf das Storyboard.

Ich habe dieses Problem mit dieser Methode gelöst.

11
Fogni

Wenn Sie Swift verwenden, verwenden Sie dies wie folgt. Verwenden Sie kein Storyboard, um die Zeilenhöhe auszuwählen. Programmgesteuerte Einstellung der Tabellenzeilenhöhe 

 func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    if indexPath.row == 0 || indexPath.row == 1{
        let cell = self.tableView.dequeueReusableCellWithIdentifier("section1", forIndexPath: indexPath) as! Section1TableViewCell
        self.tableView.rowHeight = 150
        cell.label1.text = "hiiiiii"
        cell.label2.text = "Huiiilllllll"
        return cell

    } else {

        let cell = self.tableView.dequeueReusableCellWithIdentifier("section2", forIndexPath: indexPath) as! Section2TableViewCell
        self.tableView.rowHeight = 60
        cell.label3.text = "llll"
        return cell
    }

}
9

Öffnen Sie das Storyboard in der XML-Ansicht und versuchen Sie, das rowHeight-Attribut des gewünschten Elements zu bearbeiten.

Es funktionierte für mich, als ich versuchte, custom rowHeight für meine Prototyp-Zeile festzulegen. Es funktioniert nicht über den Inspector, sondern über XML.

6
Shtirlic

Sie können die Höhe von UITableviewCell (in UITableviewController - statische Zellen) mit Hilfe der folgenden Zeilen vom Storyboard abrufen.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
   CGFloat height = [super tableView:tableView heightForRowAtIndexPath:indexPath];

    return height;
}
6
Hiren Panchal

Sie können den Prototyp cells mit einer benutzerdefinierten height verwenden und dann cellForRowAtIndexPath: aufrufen und seinen frame.height.: Zurückgeben.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [self tableView:tableView
                    cellForRowAtIndexPath:indexPath];
    return cell.frame.size.height;
}
5
Henrik Hartz

Ich habe kürzlich damit gerungen. Mein Problem war, dass die oben genannten Lösungen mit der heightForRowAtIndexPath:-Methode für iOS 7.1 im Simulator funktionieren würden, die Ergebnisse jedoch durch das Umschalten auf iOS 8.1 völlig fehlerhaft waren.

Ich fing an, mehr über sich selbst ändernde Zellen zu lesen (eingeführt in iOS 8, hier lesen ). Es war offensichtlich, dass die Verwendung von UITableViewAutomaticDimension in iOS 8 helfen würde. Ich habe diese Technik ausprobiert und die Verwendung von heightForRowAtIndexPath: und voila gestrichen. In iOS 8 funktionierte es jetzt perfekt. Aber dann war iOS 7 nicht. Was soll ich tun Ich brauchte heightForRowAtIndexPath: für iOS 7 und nicht für iOS 8.

Hier ist meine Lösung (aus Gründen der Kürze), die aus der Antwort von @JosephH stammt, die oben gepostet wurde:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.estimatedRowHeight = 50.;
    self.tableView.rowHeight = UITableViewAutomaticDimension;

    // ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
        return UITableViewAutomaticDimension;

    } else {
        NSString *cellIdentifier = [self reuseIdentifierForCellAtIndexPath:indexPath];
        static NSMutableDictionary *heightCache;
        if (!heightCache)
            heightCache = [[NSMutableDictionary alloc] init];
        NSNumber *cachedHeight = heightCache[cellIdentifier];
        if (cachedHeight)
            return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
    }
}

- (NSString *)reuseIdentifierForCellAtIndexPath:(NSIndexPath *)indexPath {
    NSString * reuseIdentifier;
    switch (indexPath.row) {
        case 0:
            reuseIdentifier = EventTitleCellIdentifier;
            break;
        case 2:
            reuseIdentifier = EventDateTimeCellIdentifier;
            break;
        case 4:
            reuseIdentifier = EventContactsCellIdentifier;
            break;
        case 6:
            reuseIdentifier = EventLocationCellIdentifier;
            break;
        case 8:
            reuseIdentifier = NotesCellIdentifier;
            break;
        default:
            reuseIdentifier = SeparatorCellIdentifier;
            break;
    }

    return reuseIdentifier;
}

SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO (@ "8.0") stammt eigentlich aus einer Reihe von Makrodefinitionen, die ich verwende und die ich irgendwo gefunden habe (sehr hilfreich). Sie sind definiert als:

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
4
speby

Wenn Sie eine statische Zeilenhöhe festlegen möchten, können Sie Folgendes tun:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 120;
}
4
Victor Palhares

Das gleiche Problem trat bei der Arbeit an XCode 9 mit Swift 4 auf.

AutoLayout hinzufügen für die Elemente der Benutzeroberfläche in der Zelle, und die Zeilenhöhe der benutzerdefinierten Zelle funktioniert wie angegeben.

1
Murari Varma

Bei dynamischen Zellen überschreibt rowHeight, das in UITableView festgelegt ist, immer rowHeight der einzelnen Zellen. Berechnen Sie einfach die dynamische Höhe des Inhalts innerhalb der Zeile.

1
Aks

Da ich mit Interface Builder keine Lösung für dieses Problem gefunden habe, entschied ich mich, eine programmatische Lösung für das Problem in Swift using zwei dynamische Zellen zu veröffentlichen, auch wenn die ursprüngliche Frage nach einer Lösung gefragt war Interface Builder. Unabhängig davon denke ich, dass es für die Stack Overflow-Community hilfreich sein könnte:

    import UIKit

    enum SignInUpMenuTableViewControllerCellIdentifier: String {
       case BigButtonCell = "BigButtonCell"
       case LabelCell = "LabelCell"
    }

    class SignInUpMenuTableViewController: UITableViewController {
            let heightCache = [SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell : CGFloat(50),
                              SignInUpMenuTableViewControllerCellIdentifier.LabelCell : CGFloat(115)]

    private func cellIdentifierForIndexPath(indexPath: NSIndexPath) -> SignInUpMenuTableViewControllerCellIdentifier {
        if indexPath.row == 2 {
            return SignInUpMenuTableViewControllerCellIdentifier.LabelCell
        } else {
            return SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell
        }
    }

   override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
       return self.heightCache[self.cellIdentifierForIndexPath(indexPath)]!
   }

   ...

  }
0
King-Wizard

Als Kommentar hinzugefügt, aber als Antwort auf Sichtbarkeit gepostet: 

Es scheint auch ein Problem zu sein, wenn Sie anfangs eine Tabellenansicht als "statische Zellen" einrichten und diese dann in "dynamische Prototypen" ändern. Ich hatte ein Problem, bei dem sogar die Delegat-Methode für heightForRowAtIndexPath ignoriert wurde. Ich habe es zuerst gelöst, indem ich das Storyboard-XML direkt editiert habe, und dann die Storyboard-Szene von Grund auf neu erstellt, wobei dynamische Prototypen von Anfang an verwendet wurden.

0
Eric Goldberg

Die einzige wirkliche Lösung, die ich finden konnte, ist diese

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = ...; // Instantiate with a "common" method you'll use again in cellForRowAtIndexPath:
    return cell.frame.size.height;
}

Dies funktioniert und erlaubt es nicht, einen schrecklichen Schalter zu haben, wenn die Logik bereits im StoryBoard kopiert wird. Ich bin nicht sicher, was die Leistung angeht, aber ich denke, wenn man in cellForRow: ankommt, ist die Zelle, die bereits initalisiert ist, genauso schnell. Natürlich gibt es hier wahrscheinlich Kollateralschäden, aber es sieht so aus, als ob es für mich hier gut funktioniert.

Ich habe dies auch hier gepostet: https://devforums.Apple.com/message/772464

EDIT: Ortwin Gentz ​​ erinnerte mich daran, dass heightForRowAtIndexPath: für all - Zellen der TableView aufgerufen wird, nicht nur für die sichtbaren. Klingt logisch, da iOS die Gesamthöhe kennen muss, um die rechten Bildlaufleisten anzeigen zu können. Dies bedeutet, dass es für kleine TableViews (z. B. 20 Zellen) wahrscheinlich in Ordnung ist, bei einer 1000-Zellen-TableView jedoch vergessen.

Auch der vorherige Trick mit XML: Gleich wie erster Kommentar für mich. Der richtige Wert war schon da.

0
StuFF mc

Sie können auch zu Ihrem Dokumententwurf gehen und die Tabellensicht auswählen, in der Ihre Prototypzelle verschachtelt ist. Ändern Sie anschließend im Größeninspektor die Zeilenhöhe der Tabellenansicht auf den gewünschten Wert und deaktivieren Sie das Kontrollkästchen Automatisch.

0
Amin Rezapour