Центрування X підзаголовка в автоматичному розкладі видає "не готовий до обмеження"


82

У мене є власний підклас UIView, який ініціалізується через перо.

У -awakeFromNib, я створюю підпрогляд і намагаюся відцентрувати його у своєму суперперегляді.

[self setInteralView: [[UIView alloc] init]];
[[self internalView] addConstraint: [NSLayoutConstraint constraintWithItem: [self internalView]
                                                                 attribute: NSLayoutAttributeCenterX
                                                                 relatedBy: NSLayoutRelationEqual
                                                                    toItem: self
                                                                 attribute: NSLayoutAttributeCenterX
                                                                multiplier: 1
                                                                  constant: 0]];

Це ламається і спричиняє такий результат:

2013-08-11 17:58:29.628 MyApp[32414:a0b] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0xc1dcc80 UIView:0xc132a40.centerX == MyView:0xc1315a0.centerX>
    When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2013-08-11 17:58:29.630 MyApp[32414:a0b] View hierarchy unprepared for constraint.
    Constraint: <NSLayoutConstraint:0xc1dcc80 UIView:0xc132a40.centerX == MyView:0xc1315a0.centerX>
    Container hierarchy: 
<UIView: 0xc132a40; frame = (0 0; 0 0); clipsToBounds = YES; layer = <CALayer: 0xc132bc0>>
    View not found in container hierarchy: <MyView: 0xc1315a0; frame = (-128 -118; 576 804); layer = <CALayer: 0xc131710>>
    That view's superview: <UIView: 0xc131a70; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0xc131b50>>

Відповіді:


95

Як зазначено в помилці, ви повинні додати обмеження до подання таким чином, щоб подання, що беруть участь у обмеженні, були поданням, до якого ви його додаєте, або підзаглядом цього подання. У випадку з вашим кодом вище, вам слід додати це обмеження self, а не [self internalView]. Причиною того, що він не працює в письмовому вигляді, є одне з переглядів, задіяних у обмеженні ( self), не в ієрархії перегляду, якщо врахувати лише [self internalView]та нижче).

Докладніше див. У розділі обговорення документації щодо addConstraint:методу.

Ось ваш рядок коду, виправлений, як я пропоную:

UIView* internalView = [[UIView alloc] initWithFrame:CGRectZero];
internalView.translatesAutoresizingMaskIntoConstraints = NO;
[self setInternalView:internalView];

[self addConstraint: [NSLayoutConstraint constraintWithItem: [self internalMapView]
                                         attribute: NSLayoutAttributeCenterX
                                         relatedBy: NSLayoutRelationEqual
                                         toItem: self
                                         attribute: NSLayoutAttributeCenterX
                                         multiplier: 1
                                         constant: 0]];

Це призводить до помилки, коли я заявляю, Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want.а потім це розбивається<NSLayoutConstraint:0x126ad4c0 UIView:0xadd2e20.centerX == MyView:0xadd19b0.centerX>
Патрік Періні,

1
Швидше за все тому, що ви не відключили переклад маски автоматичного зміни розміру в обмеження. Я оновлю свій код вище, щоб зробити це. Ймовірно, вам також доведеться додати обмеження ширини / висоти, щоб воно було видимим, і я б рекомендував додати обмеження на центр Y або якесь обмеження верхнього / нижнього для себе, щоб зробити макет чітко визначеним.
Charles A.

так що ви не можете мати такий макет, як @"V:|[v]|":? як це могло б стосуватися суперпрегляду?
Сем

1
@Sam Це допустиме обмеження, але воно не буде центрувати представлення, представлене [v], воно дасть вам верхні та нижні обмеження стандартного розміру між [v]верхнім та нижнім краями та його супервигляду. Вам також доведеться додати його до супервізу, я вважаю.
Чарльз А.

8
Просте правило великого пальця: Будь-які обмеження, які стосуються розміру подання, слід додавати до того самого подання, а будь-які обмеження, що стосуються його позиції, слід додавати до його батьківського елемента.
Deepak GM

117

Для інших, хто прийшов сюди: я отримав цю помилку, оскільки додав обмеження перед тим, як додати підвиди до ієрархії.


Дякую, ви заощадили мені багато часу!
Стас

Це найпоширеніша причина цієї невдачі, яку я помічав до цього часу.
Аян Сенгупта

точно і коли ви це зробите, що constraintWithItem: youViewпредмет у ньому не існує!
Назір,

36

Коротка відповідь : поміняйте батьківський та дочірній погляди місцями.
Припускаючи, що selfце батьківський погляд:

  • погано :[subview addConstraint [NSLayoutConstraint constraintWithItem:self...

  • добре :[self addConstraint [NSLayoutConstraint constraintWithItem:subview...


Стрімкий

subview.translatesAutoresizingMaskIntoConstraints = false
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
    "H:|-0-[subview]-0-|",
    options: .DirectionLeadingToTrailing,
    metrics: nil,
    views: ["subview":subview]))

Obj-C


10

Додаткові поради:

У мене є нещодавно розроблена програма, яка працює нормально на iOS7, але отримує помилку на iOS8 "Ієрархія подання не підготовлена ​​до обмеження".

Прочитайте інший допис, в якому сказано, що перед створенням обмежень потрібно (додавати) подання. Я зробив це, але все-таки отримав помилку.

Потім я зрозумів, що слід створювати обмеження під - (void) viewDidAppear замість viewDidLoad


2
Коли viewDidAppear()його викликають, користувачеві вже видно подання. Якщо змінюється обмеження, це має бути перед цим, у viewWillLayoutSubviews(). Більше про життєвий цикл тут: medium.com/@SergiGracia/…
maganap

6

Це старе запитання, але я хочу вказати на цей рядок із документів:

При розробці для iOS 8.0 або новішої версії встановіть для властивості isActive обмеження значення true, замість того, щоб безпосередньо викликати метод addConstraint (_ :). Властивість isActive автоматично додає та видаляє обмеження з правильного подання.

Принаймні, це усуне одну точку несправності, оскільки вам більше не потрібно турбуватися про виклик addConstraint на неправильний вигляд


2

У моєму випадку це було вирішено за допомогою використання кореневого подання як контейнера обмежень замість поточно створеного подання.

Я маю на увазі використання всередині viewController

view.addConstraints([leftConstraintImage, topConstraintImage]) замість imageView.addConstraints...


1

Як зазначає @CharlesA у своїй відповіді, проблема полягає в тому, що ви додаєте подання не в належній ієрархії подання. Його відповідь хороша, але я збираюся докласти деякі подробиці для конкретного випадку використання, який викликав у мене цю проблему:

У мене це сталося при спробі додати обмеження до подання, контролер подання якого я створив за допомогою екземпляра instantiateViewControllerWithIdentifier. Для вирішення проблеми я використав [childViewController didMoveToParentViewController:self]. Це додало подання до ієрархії подання, на яке посилалося моє обмеження.


0

Спочатку додайте свій subView, а потім додайте такі обмеження, як це

addSubview(yourSubViewHere)
yourSubViewHere.translatesAutoresizingMaskIntoConstraints = false

addConstraint(NSLayoutConstraint(....
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.