Подтвердить что ты не робот

ContentView не отступы в iOS 6 Ячейка прототипа UITableViewCell

Я настраиваю пользовательский UITableViewCell, используя ячейку прототипа в Storyboard. Однако все элементы UILabel (и другие элементы пользовательского интерфейса), похоже, не добавляются в ячейку contentView, а добавляются непосредственно в представление UITableViewCell. Это создает проблемы, когда ячейка помещается в режим редактирования, поскольку содержимое не изменяется автоматически/отступом (что бы оно делало, если они находились внутри contentView).

Есть ли способ добавить элементы пользовательского интерфейса в contentView при прокладке ячейки с помощью элементов интерфейса Builder/Storyboard/prototype? Единственный способ, который я нашел, - создать все в коде и использовать [cell.contentView addSubView:labelOne], что было бы не очень удобно, так как гораздо проще компоновать ячейку графически.

4b9b3361

Ответ 1

В ходе дальнейшего исследования (просмотр иерархии subview ячейки) Interface Builder помещает subviews в ячейку contentView, он просто не похож на него.

Основной причиной проблемы стало автозапуск iOS 6. Когда ячейка находится в режиме редактирования (и отступом), contentView также имеет отступы, поэтому вполне разумно, что все подпункты в contentView будут перемещаться (отступ) из-за того, что они находятся в пределах contentView. Однако все ограничения автоопределения, применяемые Interface Builder, по-видимому, относятся к самому UITableViewCell, а не к contentView. Это означает, что даже несмотря на то, что отступы contentView, вложенные в него объекты не содержат ограничений, берут на себя ответственность.

Например, когда я поместил a UILabel в ячейку (и положил ее на 10 точек с левой стороны ячейки), IB автоматически применил ограничение "Горизонтальное пространство (10)". Однако это ограничение относится к UITableViewCell NOT contentView. Это означает, что когда ячейка с отступом и движение contentView перемещается, метка остается помещенной, поскольку она соблюдает ограничение, чтобы оставаться 10 точек с левой стороны UITableViewCell.

К сожалению (насколько мне известно), нет способа удалить эти созданные IB ограничения изнутри самой IB, так вот как я решил проблему.

В подклассе UITableViewCell для ячейки я создал IBOutlet для этого ограничения, называемого cellLabelHSpaceConstraint. Вам также понадобится IBOutlet для самой метки, которую я назвал cellLabel. Затем я реализовал метод -awakeFromNib, как показано ниже:

- (void)awakeFromNib {

    // -------------------------------------------------------------------
    // We need to create our own constraint which is effective against the
    // contentView, so the UI elements indent when the cell is put into
    // editing mode
    // -------------------------------------------------------------------

    // Remove the IB added horizontal constraint, as that effective
    // against the cell not the contentView
    [self removeConstraint:self.cellLabelHSpaceConstraint];

    // Create a dictionary to represent the view being positioned
    NSDictionary *labelViewDictionary = NSDictionaryOfVariableBindings(_cellLabel);   

    // Create the new constraint
    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[_cellLabel]" options:0 metrics:nil views:labelViewDictionary];

    // Add the constraint against the contentView
    [self.contentView addConstraints:constraints];

}

Таким образом, вышесказанное удалит ограничение горизонтального интервала, которое IB автоматически добавит (как эффективно против UITableViewCell, а не contentView), и затем мы определяем и добавляем наше собственное ограничение к contentView.

В моем случае все остальные UILabels в ячейке были расположены в зависимости от положения cellLabel, поэтому, когда я исправил ограничение/позиционирование этого элемента, все остальные последовали примеру и правильно позиционировали. Однако, если у вас более сложный макет, вам может понадобиться сделать это и для других подзапросов.

Ответ 2

Как уже упоминалось, XCode Interface Builder скрывает UITableViewCell contentView. В действительности все элементы пользовательского интерфейса, добавленные в UITableViewCell, на самом деле являются областями содержимого.

На данный момент IB не делает того же магия для ограничений макета, что означает, что все они выражены на уровне UITableViewCell.

Обходной путь находится в подклассе awakeFromNib, чтобы переместить все NSAutoLayoutConstrains из UITableViewCell в него contentView и выразить их с точки зрения contentView:

-(void)awakeFromNib{
  [super awakeFromNib];
  for(NSLayoutConstraint *cellConstraint in self.constraints){
    [self removeConstraint:cellConstraint];
    id firstItem = cellConstraint.firstItem == self ? self.contentView : cellConstraint.firstItem;
    id seccondItem = cellConstraint.secondItem == self ? self.contentView : cellConstraint.secondItem;
    NSLayoutConstraint* contentViewConstraint =
    [NSLayoutConstraint constraintWithItem:firstItem
                                 attribute:cellConstraint.firstAttribute
                                 relatedBy:cellConstraint.relation
                                    toItem:seccondItem
                                 attribute:cellConstraint.secondAttribute
                                multiplier:cellConstraint.multiplier
                                  constant:cellConstraint.constant];
    [self.contentView addConstraint:contentViewConstraint];
  }
}

Ответ 3

Вот подкласс, основанный на других идеях ответов, я собираюсь настроить свои пользовательские ячейки на:

@interface FixedTableViewCell ()

- (void)initFixedTableViewCell;

@end

@interface FixedTableViewCell : UITableViewCell

@end

@implementation FixedTableViewCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    if (nil != (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) {
        [self initFixedTableViewCell];
    }
    return self;
}

- (void)awakeFromNib {
    [super awakeFromNib];

    [self initFixedTableViewCell];
}

- (void)initFixedTableViewCell {
    for (NSInteger i = self.constraints.count - 1; i >= 0; i--) {
        NSLayoutConstraint *constraint = [self.constraints objectAtIndex:i];

        id firstItem = constraint.firstItem;
        id secondItem = constraint.secondItem;

        BOOL shouldMoveToContentView = YES;

        if ([firstItem isDescendantOfView:self.contentView]) {
            if (NO == [secondItem isDescendantOfView:self.contentView]) {
                secondItem = self.contentView;
            }
        }
        else if ([secondItem isDescendantOfView:self.contentView]) {
            if (NO == [firstItem isDescendantOfView:self.contentView]) {
                firstItem = self.contentView;
            }
        }
        else {
            shouldMoveToContentView = NO;
        }

        if (shouldMoveToContentView) {
            [self removeConstraint:constraint];
            NSLayoutConstraint *contentViewConstraint = [NSLayoutConstraint constraintWithItem:firstItem
                                                                                     attribute:constraint.firstAttribute
                                                                                     relatedBy:constraint.relation
                                                                                        toItem:secondItem
                                                                                     attribute:constraint.secondAttribute
                                                                                    multiplier:constraint.multiplier
                                                                                      constant:constraint.constant];
            [self.contentView addConstraint:contentViewConstraint];
        }
    }
}

@end

Ответ 4

Альтернативой подклассу является пересмотр ограничений в cellForRowAtIndexPath.

Вставить все содержимое ячейки в представление контейнера. Затем укажите ведущие и конечные ограничения для cell.contentView, а не ячейки представления таблицы.

  UIView *containerView = [cell viewWithTag:999];
  UIView *contentView = [cell contentView];

  //remove existing leading and trailing constraints
  for(NSLayoutConstraint *c in [cell constraints]){
    if(c.firstItem==containerView && (c.firstAttribute==NSLayoutAttributeLeading || c.firstAttribute==NSLayoutAttributeTrailing)){
      [cell removeConstraint:c];
    }
  }

  NSLayoutConstraint *trailing = [NSLayoutConstraint
                                 constraintWithItem:containerView
                                 attribute:NSLayoutAttributeTrailing
                                 relatedBy:NSLayoutRelationEqual
                                 toItem:contentView
                                 attribute:NSLayoutAttributeTrailing
                                 multiplier:1
                                 constant:0];

  NSLayoutConstraint *leading = [NSLayoutConstraint
                                 constraintWithItem:containerView
                                 attribute:NSLayoutAttributeLeading
                                 relatedBy:NSLayoutRelationEqual
                                 toItem:contentView
                                 attribute:NSLayoutAttributeLeading
                                 multiplier:1
                                 constant:0];

  [cell addConstraint:trailing];
  [cell addConstraint:leading];

Ответ 5

Я думаю, что это исправлено в iOS 7 beta 3, что делает ненужные обходные пути с этой точки (но, вероятно, безвредными, поскольку в большинстве случаев они станут пустыми операциями).

Ответ 6

Основанный на коде Skoota (я новичок, не знаю многое из того, что вы сделали, но отличная работа), мое предложение состоит в том, чтобы поместить все ваши вещи в представление контейнера от края до края и добавить следующее

В файле заголовка ячейки у меня есть следующие IBOutlets:

@property (weak, nonatomic) IBOutlet UIView *container;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *leftConstrain;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *rightConstrain;

В файле реализации у меня есть следующее в awakeFromNib:

// Remove the IB added horizontal constraint, as that effective gainst the cell not the contentView
[self removeConstraint:self.leftConstrain];
[self removeConstraint:self.rightConstrain];

// Create a dictionary to represent the view being positioned
NSDictionary *containerViewDictionary = NSDictionaryOfVariableBindings(_container);

// Create the new left constraint (0 spacing because of the edge-to-edge view 'container')
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-0-[_container]" options:0 metrics:nil views:containerViewDictionary];
// Add the left constraint against the contentView
[self.contentView addConstraints:constraints];

// Create the new constraint right (will fix the 'Delete' button as well)
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"[_container]-0-|" options:0 metrics:nil views:containerViewDictionary];
// Add the right constraint against the contentView
[self.contentView addConstraints:constraints];

Опять же, вышеизложенное стало возможным благодаря Skoota. Благодарю!!! Аль-кредиты идут к нему.