indentationLevelForRowAtIndexPath не делает отступ в настраиваемой ячейке

Я переопределил метод tableView:indentationLevelForRowAtIndexPath в моем производном классе UITableViewController следующим образом:

- (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;
}

Сначала я подумал, что это не вызывается, но это была ошибка оператора (эээ, моя), и я не определил символ DEBUG = 1.

Однако он вызывается (черт возьми!), И это вывод журнала:

 -[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

Но это не влияет на расположение ячеек. Без отступов.

Это моя реализация itemCellForRowAtIndexPath, если это имеет значение:

-(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;
}

Как сделать отступ для пользовательского UITableViewCell, который я определил в Интерфейсном Разработчике?

Если я изменю itemCellForRowAtIndexPath, чтобы использовать UITableViewCell по умолчанию с приведенным ниже кодом, то отступы будут в порядке.

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;

person Xetius    schedule 23.03.2010    source источник


Ответы (9)


Да, кажется, пользовательские ячейки таблицы не делают этого автоматически? Вам необходимо переопределить метод layoutSubviews в классе ячейки таблицы. См. этот вопрос, чтобы узнать, как это сделать.

Этот код отлично работал у меня (хотя будьте осторожны, если вы также устанавливаете нестандартную высоту с делегатом, они, похоже, мешают друг другу):

- (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
    );
}

Редактировать для iOS8 и новее

Вышеупомянутое работает для меня на iOS, но также вызывает небольшие ошибки при попытке автоматического изменения высоты ячейки. Существует n более простое решение: если у вас включена автоматическая раскладка для ячейки, просто установите левое поле contentView:

override func layoutSubviews() {
    super.layoutSubviews()
    self.contentView.layoutMargins.left = CGFloat(self.indentationLevel) * self.indentationWidth
    self.contentView.layoutIfNeeded()
}
person Nathan    schedule 07.10.2010
comment
протестировано в ios9 и ios8, я могу подтвердить, что он работает .. Возможно, вам стоит проверить свои ограничения - person dreampowder; 23.10.2015
comment
Это могло привести к бесконечному циклу на iOS8; это будет вызывать layoutSubview снова и снова. Я исправил это, создав ведущее ограничение и обновив константу в функции updateConstraint в зависимости от indentationLevel. - person Dean; 03.02.2016
comment
Хорошее решение! Для тех, кто не хочет зависеть от полей макета и использовать автоматическое размещение в подклассе ячеек, попробуйте этот подход - stackoverflow.com/a / 47946688/3160561 - person maxkonovalov; 22.12.2017
comment
Я обнаружил, что мне нужно сместить layoutMargins.left на его текущее значение - я обновил решение. - person AW101; 13.07.2019

Если вы используете настраиваемую ячейку с ограничениями, наиболее удобный способ - установить ограничение, которое сдвигало бы все содержимое с левого края, а затем обновляло его в соответствии с уровнем отступа в подклассе ячейки.

Предполагая, что indentationWidth уже установлен для ячейки:

override var indentationLevel: Int {
    didSet {
        self.leftConstraint.constant = CGFloat(self.indentationLevel) * self.indentationWidth
    }
}
person maxkonovalov    schedule 22.12.2017
comment
Я сделал то же самое, но вместо этого обновил ограничение в updateConstraints. Я полагаю, это не имеет большого значения. - person Luke Rogers; 04.09.2018

Уровень отступа - это свойство самого UITableViewCell. Попробуйте установить его в ячейке при ее создании и вернуть это значение в tableView:indentationLevelForRowAtIndexPath:

person Don    schedule 23.03.2010
comment
Я добавил строки: cell.indentationLevel = [[item objectForKey: @indent] intValue]; cell.indentationWidth = 20; к созданию ячейки. Тоже не работает. - person Xetius; 23.03.2010

Вы добавили подпредставления вашего ProjectItemTableViewCell в contentView ячейки? Кроме того, вам необходимо установить маски автоизменения размеров подвидов, чтобы они перемещались при изменении размера contentView.

person Ole Begemann    schedule 23.03.2010
comment
Я добавил UITableViewCell к xib, представление к UITableViewCell и 2 UILabels к представлению. - person Xetius; 23.03.2010

Подобно принятому ответу, вот как это можно сделать в iOS 8, все еще используя вместо этого layoutSubviews с AutoLayout.

С _viewConstraints в качестве NSMutableArray ivar и _imageView в качестве ближайшего представления к левой стороне представления содержимого ячейки.

- (void)layoutSubviews
{
    float indentPoints = indentationLevel * [self indentationWidth];

    [self removeConstraints:_viewConstraints];
    [_viewConstraints removeAllObjects];

    NSDictionary *views = NSDictionaryOfVariableBindings(imageView);
    [_viewConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|-(%f@1000)-[_imageView]", indentPoints] options:0 metrics:nil views:views]];
    [self addConstraints:_viewConstraints];
}

Если у вас есть ограничения AutoLayout, определяющие все остальное в представлении, тогда это должно подтолкнуть все представление к желаемой величине отступа.

ПРИМЕЧАНИЕ при использовании Nib: вы должны определить ограничение (в данном случае между _imageView и его супервизором) как >= некоторое число (в моем случае это было 20). Тогда исходное ограничение и ограничение, добавляемое / удаляемое в layoutSubviews, не конфликтуют друг с другом.

Вам также следует рассмотреть возможность вызова следующих в awakeFromNib

[_imageView setTranslatesAutoresizingMaskIntoConstraints:NO]

Это сделано для того, чтобы старые «пружины и стойки» не мешали ограничениям, которые вы добавляете.

person Dean Kelly    schedule 22.09.2014

Принятый ответ в некоторых случаях может привести к бесконечному циклу на iOS8. Так что лучше просто переопределить setFrame вашего пользовательского UITableViewCell и настроить рамку там.

-(void)setFrame:(CGRect)frame {
    float inset = self.indentationLevel * self.indentationWidth;

    frame.origin.x += inset;
    frame.size.width -= inset;

    [ super setFrame:frame ];
}
person sim    schedule 24.02.2016

Вы случайно не заменили shouldIndentWhileEditing: на NO в пользовательском классе ячеек таблицы?

person Shaggy Frog    schedule 23.03.2010
comment
Отступ при редактировании отмечен в Интерфейсном Разработчике - person Xetius; 23.03.2010
comment
Я также добавил строку cell.shouldIndentWhileEditing = YES; в метод cellForRowAtIndexPath. Так казалось бы нет. - person Xetius; 23.03.2010

Ограничьтесь передним краем представления содержимого настраиваемой ячейки таблицы, которая есть в построителе интерфейса. Для простого запаса этого, кажется, достаточно. Если вам нужно программно изменить отступ, см. Ответ Дина. Или https://stackoverflow.com/a/7321461/5000071.

person yarp    schedule 02.07.2015

Я использовал этот код для отступа в ячейке tableView. Первоначально это работало хорошо, но позже это вызвало некоторые проблемы (например, вмешательство в мое обновление динамической высоты UITextView при отступе, которое является подвидом моей ячейки tableView. Каким-то образом мой UITextView считает, что ширина по-прежнему является исходной шириной contentView).

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
)

Поэтому я не рекомендую приведенный выше код, вместо этого я использую метод автоматической компоновки в качестве ответа Дина с небольшой разницей (версия 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» - это IBOutlet (ведущее ограничение с contentView), а код написан в настраиваемом подклассе tableViewCell, он работал отлично, и вам не нужно удалять или добавлять какие-либо ограничения, что дороже. Я думаю, что метод автоматической компоновки - лучший способ сделать отступ в ячейке tableView.

person Andres Wang    schedule 17.12.2015