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

Проблема с AutoLayout на UITableViewCell

У меня возникли проблемы с автозапуском в проекте xcode 5. Я использую контроллер открытого вида внутри с навигационным контроллером. У меня есть MKMapView в верхней половине и UITableView в нижней половине. Я использую storyboards и настроил прототип UITableViewCell, но я добавляю ограничения через код. Я дважды проверял каждый элемент управления в прототипе и не вижу никаких ограничений, настроенных там. Моя проблема возникает, когда я добавляю ограничения для UITableViewCell. У меня есть следующий код в ячейках:

-(void)updateConstraints {
    [super updateConstraints];
    //first remove old constraints
    [self removeConstraints:self.constraints];
    [self.nameLabel removeConstraints:self.nameLabel.constraints];
    [self.addressLabel removeConstraints:self.nameLabel.constraints];
    [self.rentableSquareFeetLabel removeConstraints:self.rentableSquareFeetLabel.constraints];
    [self.lastSaleAmountLabel removeConstraints:self.lastSaleAmountLabel.constraints];
    [self.lastSaleDateLabel removeConstraints:self.lastSaleAmountLabel.constraints];
    [self.thumbnailImageView removeConstraints:self.thumbnailImageView.constraints];

    //then set up constraints
    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_thumbnailImageView, _nameLabel, _rentableSquareFeetLabel, _lastSaleAmountLabel, _addressLabel, _lastSaleDateLabel);
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_thumbnailImageView(60)]-[_nameLabel(<=200)]-(>=8)-[_rentableSquareFeetLabel]-(>=8)-[_lastSaleAmountLabel]|" options:0 metrics:nil views:viewsDictionary]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_nameLabel]-(-4)-[_addressLabel]" options:NSLayoutFormatAlignAllLeading metrics:nil views:viewsDictionary]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_lastSaleAmountLabel]-(-4)-[_lastSaleDateLabel]" options:NSLayoutFormatAlignAllLeading metrics:nil views:viewsDictionary]];
}

Я получаю следующее в консоли отладки. Исключение запускается первой линией addConstraints. Если я просто продолжу их, то в конечном итоге все будет выглядеть так, как должно быть, так как выглядит так, как xcode выбирает разбить правильное ограничение:

2013-09-25 15:07:14.169 PECProperties[32381:a0b] Unable to simultaneously satisfy constraints.  Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)  (
    "<NSIBPrototypingLayoutConstraint:0x9d56c70 'IB auto generated at build time for view with fixed frame' H:|-(0)-[UIImageView:0x9d558f0](LTR)   (Names: '|':UITableViewCellContentView:0x9d55620 )>",
    "<NSIBPrototypingLayoutConstraint:0x9d56d20 'IB auto generated at build time for view with fixed frame' H:[UIImageView:0x9d558f0(60)]>",
    "<NSIBPrototypingLayoutConstraint:0x9d56d80 'IB auto generated at build time for view with fixed frame' H:|-(78)-[UILabel:0x9d559e0](LTR)   (Names: '|':UITableViewCellContentView:0x9d55620 )>",
    "<NSLayoutConstraint:0x9d53830 H:[UIImageView:0x9d558f0]-(NSSpace(8))-[UILabel:0x9d559e0]>" )

Will attempt to recover by breaking constraint  <NSIBPrototypingLayoutConstraint:0x9d56d80 'IB auto generated at build time for view with fixed frame' H:|-(78)-[UILabel:0x9d559e0](LTR)   (Names: '|':UITableViewCellContentView:0x9d55620 )>

Break on objc_exception_throw to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

Третий NSIBPrototypingLayoutConstraint показывает 78 точек между краем представления и меткой. Вот где прототип позиционируется грубо (и если я его перемещаю в прототипе, я вижу изменение ограничения в консоли отладки), но это противоречит моему собственному ограничению "стандартного" расстояния между представлением изображения и меткой,

Я попытался установить translatesAutoresizingMaskIntoConstraints=NO в контроллере представления cellForRowAtIndexPath, но это, похоже, не помогает. Как я могу исправить макет?

4b9b3361

Ответ 1

Несколько вещей, которые можно здесь затронуть:

  • Ограничения NSIBPrototypingLayoutConstraint, с которыми вы работаете (и которые вызывают исключения), автоматически генерируются с помощью Interface Builder, чтобы сделать раскладку раскадровки или XIB-представление недвусмысленным. Это довольно сложно сделать, но оно автоматически добавляет минимальные ограничения, необходимые для полного определения положения и размера каждого неоднозначного представления. Это изменение от Xcode 4, потому что в Xcode 4 вы не могли бы иметь двусмысленные макеты в Interface Builder. С Xcode 5 и более поздними версиями вы можете, однако, IB будет автоматически генерировать эти ограничения для вас, если ваш макет неоднозначен во время компиляции.

    Способ устранения этой проблемы заключается в том, чтобы добавить минимальные требуемые ограничения в Interface Builder, чтобы полностью определить каждую позицию и размер представления, затем выберите каждое из этих нежелательных ограничений, перейдите в инспектор атрибутов правой боковой панели и установите флажок рядом с Заполнитель - Удалить во время сборки.

    Screenshot of the constraint Placeholder checkbox in Xcode 6.

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

    В чем разница между ограничением Placeholder и неустановленным ограничением? Здесь слайд из моего Адаптивный автоматический макет (видео) (PDF слайды), сравнивая два:

    Comparison between Placeholder constraints and Uninstalled constraints.

  • В updateConstraints вы не хотите удалять ограничения и повторно добавлять их, как у вас там. Почему нет? По сути, это ужасно для производительности, и я подтвердил инженерам Apple, что это не очень хорошая идея. См. <Вопрос/ответ который я разместил здесь, для получения более подробной информации, а также ответа . Чтобы предотвратить добавление ограничений более одного раза, используйте флаг boolean (например, hasSetupConstraints), который вы установили в YES, когда вы впервые установили свои ограничения, и если updateConstraints вызывается снова, вы можете сразу вернуться если у вас нет новых ограничений для добавления. См. этот вопрос для дальнейшего обсуждения.

  • Код, который вы используете для удаления ограничений, может работать не полностью. Это связано с тем, что [view removeConstraints:view.constraints] будет удалять только те ограничения, которые были добавлены в view, - помните, что ограничения могут быть добавлены в любой общий просмотр представлений, которые они ограничивают, и ограничения, добавленные в view, могут быть не единственными которые влияют на расположение view! Если вам нужно удалить несколько ограничений, вы должны сохранить ссылку на каждое из этих ограничений в свойстве (например, свойство NSArray, содержащее экземпляры NSLayoutConstraint), а затем деактивировать/удалить эти ограничения с помощью API в NSLayoutConstraint или библиотека с открытым исходным кодом PureLayout. Вы должны только деактивировать/удалить как можно меньше ограничений, потому что это дорого стоит вычислить. С другой стороны, изменение constant любого ограничения очень эффективно и рекомендуется, и вам не нужно удалять или повторно добавлять ограничение для этого.