indentationLevelForRowAtIndexPath non rientra nella cella personalizzata

Ho sovrascritto il metodo tableView:indentationLevelForRowAtIndexPath nella mia class derivata UITableViewController come segue:

 - (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath { NSDictionary* item = [self.projects objectAtIndex:indexPath.row]; int indentationLevel = [[item objectForKey:@"indent"] intValue]; DLog (@"Indentation Level for Row %d : %d", indexPath.row, indentationLevel); return indentationLevel; } 

Inizialmente pensavo che questo non veniva chiamato ma che era un errore dell’operatore (err, mio) e non avevo definito il simbolo DEBUG = 1.

Tuttavia, viene chiamato (duh me!) E questo è l’output del registro:

  -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 0 : 1 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 1 : 1 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 2 : 2 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 3 : 2 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 4 : 2 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 5 : 1 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 6 : 2 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 7 : 2 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 8 : 1 

Ma questo non influisce sul layout delle celle. Nessuna indentazione

Questa è la mia implementazione itemCellForRowAtIndexPath , se questo fa alcuna differenza:

 -(UITableViewCell*)tableView:(UITableView *)tableView itemCellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString* cellIdentifier = @"projectItemCell"; ProjectItemTableViewCell* cell = (ProjectItemTableViewCell*)[tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (cell == nil) { NSArray* nib = [[NSBundle mainBundle] loadNibNamed:@"ProjectItemTableViewCell" owner:self options:nil]; for (id oneObject in nib) { if ([oneObject isKindOfClass:[ProjectItemTableViewCell class]]) { cell = (ProjectItemTableViewCell*)oneObject; } } } NSDictionary* item = [self.projects objectAtIndex:indexPath.row]; cell.projectDescLabel.text = [item objectForKey:@"name"]; cell.itemCountlabel.text = [NSString stringWithFormat:@"%d", [[item objectForKey:@"cache_count"] intValue]]; cell.itemCountlabel.backgroundColor = [UIColor colorForHex:[item objectForKey:@"color"]]; cell.indentationWidth = 20; return cell; } 

Come faccio a indentare un UITableViewCell personalizzato che ho definito in Interface Builder?

Se cambio itemCellForRowAtIndexPath per usare un UITableViewCell predefinito con il codice sotto, allora fa rientrare bene.

 static NSString* cellIdentifier = @"projectItemCell"; UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease]; } NSDictionary* item = [self.projects objectAtIndex:indexPath.row]; cell.textLabel.text = [item objectForKey:@"name"]; cell.indentationWidth = 40; return cell; 

Sì, sembra che le celle della tabella personalizzate non lo facciano automaticamente? È necessario sovrascrivere il metodo layoutSubviews nella class della cella della tabella. Vedi questa domanda per come farlo.

Questo codice ha funzionato perfettamente per me (anche se fai attenzione se stai impostando un’altezza personalizzata con il delegato, sembrano interferire tra loro):

 - (void)layoutSubviews { [super layoutSubviews]; float indentPoints = self.indentationLevel * self.indentationWidth; self.contentView.frame = CGRectMake( indentPoints, self.contentView.frame.origin.y, self.contentView.frame.size.width - indentPoints, self.contentView.frame.size.height ); } 

Modifica per iOS8 e versioni successive

Quanto sopra funziona per me su iOS, ma causa errori sottili durante il tentativo di autovalorizzare l’altezza della cella. C’è n soluzione più semplice: se hai impostato automaticamente l’autolayout per la cella, imposta il margine sinistro di contentView:

 override func layoutSubviews() { super.layoutSubviews() self.contentView.layoutMargins.left = CGFloat(self.indentationLevel) * self.indentationWidth self.contentView.layoutIfNeeded() } 

Hai aggiunto le sottoview di ProjectItemTableViewCell al contentView della cella? Inoltre, è necessario impostare le maschere di autoresizzazione delle sottoview in modo che vengano riposizionate quando cambia la dimensione di contentView.

Simile alla risposta accettata, questo è il modo in cui può essere fatto in iOS 8, mentre invece usa ancora layoutSubviews con layoutSubviews .

Con _viewConstraints come un NSMutableArray ivar e _imageView come la vista più vicina sul lato sinistro della vista del contenuto della cella.

 - (void)layoutSubviews { float indentPoints = indentationLevel * [self indentationWidth]; [self removeConstraints:_viewConstraints]; [_viewConstraints removeAllObjects]; NSDictionary *views = NSDictionaryOfVariableBindings(imageView); [_viewConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|-(%[email protected])-[_imageView]", indentPoints] options:0 metrics:nil views:views]]; [self addConstraints:_viewConstraints]; } 

Se si dispone di vincoli di AutoLayout che definiscono tutto il resto nella vista, questo dovrebbe spingere l’intera vista sull’importo di indentazione desiderato.

NOTA se si utilizza il pennino: è necessario definire il vincolo (in questo caso tra _imageView e la sua _imageView ) come >= un numero (nel mio caso era 20). Quindi il vincolo originale e quello che viene aggiunto / rimosso in layoutSubviews non sono in conflitto tra loro.

Dovresti anche considerare di chiamare quanto segue in awakeFromNib

 [_imageView setTranslatesAutoresizingMaskIntoConstraints:NO] 

Questo è così che le vecchie “molle e montanti” non interferiscono con i vincoli che state aggiungendo.

In alcuni casi, la risposta accettata potrebbe portare a un ciclo infinito su iOS8. Quindi è meglio ignorare setFrame del tuo UITableViewCell personalizzato e regolare il frame lì.

 -(void)setFrame:(CGRect)frame { float inset = self.indentationLevel * self.indentationWidth; frame.origin.x += inset; frame.size.width -= inset; [ super setFrame:frame ]; } 

Se si utilizza una cella personalizzata con vincoli, il modo più conveniente consiste nell’impostare un vincolo che sposterebbe tutto il contenuto dal bordo sinistro e quindi aggiornarlo in base al livello di rientro nella sottoclass della cella.

Supponendo che indentationWidth sia già impostato per la cella:

 override var indentationLevel: Int { didSet { self.leftConstraint.constant = CGFloat(self.indentationLevel) * self.indentationWidth } } 

Hai accidentalmente ignorato shouldIndentWhileEditing: to NO nella tua class di celle di tabella personalizzate?

Il livello di indentazione è una proprietà di UITableViewCell stesso. Prova a impostarlo sulla cella al momento della creazione e restituire questo valore in tableView:indentationLevelForRowAtIndexPath:

Vincola al bordo principale della vista del contenuto della cella di tabella personalizzata che hai nel builder dell’interfaccia. Per un semplice margine, questo sembra essere sufficiente. Se è necessario modificare il rientro a livello di codice, vedere la risposta di Dean. O https://stackoverflow.com/a/7321461/5000071 .

Ho usato questo codice per indentare la mia cella tableView. Inizialmente ha funzionato bene, ma in seguito questo ha causato qualche problema (ad esempio, interferendo con il mio aggiornamento di altezza dinamico UITextView quando rientrato, che è una sottoview della mia cella TableView. In qualche modo il mio UITextView pensa che la larghezza sia ancora la larghezza del contenuto originale).

 float indentPoints = self.indentationLevel * self.indentationWidth; self.contentView.frame = CGRectMake( indentPoints, self.contentView.frame.origin.y, self.contentView.frame.size.width - indentPoints, self.contentView.frame.size.height ) 

Quindi non consiglio il codice qui sopra, invece utilizzo il metodo di layout automatico come risposta di Dean con una piccola differenza (versione Swift):

 override func awakeFromNib() { super.awakeFromNib() self.indentationWidth = 20.0 self.indentationLevel = 0 } override func layoutSubviews() { super.layoutSubviews() let margin: CGFloat = 20.0 let indentPoints = CGFloat(self.indentationLevel) * self.indentationWidth indentConstraint.constant = margin + indentPoints } 

“IndentConstraint” è un IBOutlet (vincolo principale con contentView) e il codice è scritto in una sottoclass tableViewCell personalizzata, ha funzionato perfettamente e non è necessario rimuovere o aggiungere alcun vincolo, che è più costoso. Penso che il metodo di layout automatico sia il modo migliore per indentare la cella tableView.