Otomatik düzen içinde merkezleme alt görünümünün X'i "kısıtlamaya hazır değil"


82

Bir uç aracılığıyla başlatılan özel bir UIView alt sınıfım var.

İçinde -awakeFromNib, bir alt görünüm oluşturuyorum ve onu denetim görünümünde ortalamaya çalışıyorum.

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

Bu kırılır ve aşağıdaki çıktıya neden olur:

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

Yanıtlar:


95

Hatanın belirttiği gibi, kısıtlamaya dahil olan görünümler onu eklediğiniz görünüm veya o görünümün bir alt görünümü olacak şekilde bir görünüme kısıtlamayı eklemelisiniz. Yukarıdaki kodunuz durumunda, bu kısıtlamayı selfyerine eklemeniz gerekir [self internalView]. Yazıldığı gibi çalışmamasının nedeni, kısıtlamada ( self) yer alan görüşlerden biri, yalnızca [self internalView]ve altını dikkate alırsanız görünüm hiyerarşisinde olmamasıdır ).

Daha fazla ayrıntı için, yöntemle ilgili belgelerin tartışma bölümüne bakınaddConstraint: .

İşte önerdiğim gibi düzeltilen kod satırınız:

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]];

Bu bana iddia Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want.ederken hata veriyor Ve sonra kırılıyor<NSLayoutConstraint:0x126ad4c0 UIView:0xadd2e20.centerX == MyView:0xadd19b0.centerX>
Patrick Perini

1
Büyük olasılıkla, otomatik yeniden boyutlandırma maskesinin kısıtlamalara dönüştürülmesini devre dışı bırakmadığınız için. Bunu yapmak için yukarıdaki kodumu güncelleyeceğim. Görünür olması için muhtemelen genişlik / yükseklik kısıtlamaları eklemeniz gerekecek ve düzeni iyi tanımlayabilmek için merkez Y'ye bir sınırlama veya kendine bir tür üst / alt sınırlama eklemenizi tavsiye ederim.
Charles A.

: böylece gibi düzen olamaz @"V:|[v]|"? bu bir süpervizyona atıfta bulunacağı için?
Sam

1
@Sam Bu geçerli bir kısıtlamadır, ancak temsil ettiği görünümü ortalamayacaktır [v], size [v]üst ve alt kenarları ile üst ve alt kenarları ile üst görünümü arasındaki standart boyutun üst ve alt kısıtlamalarını verecektir . Sanırım bunu süpervizyona da eklemeniz gerekecek.
Charles A.

8
Basit bir pratik kural: Bir görünümün boyutuyla ilgili tüm kısıtlamalar aynı görünüme eklenmeli ve konumuyla ilgili tüm kısıtlamalar üst öğeye eklenmelidir.
Deepak GM

117

Buraya gelenler için: Bu hatayı aldım, çünkü alt görünümleri hiyerarşiye eklemeden önce kısıtlamaları ekledim.


Teşekkürler, bana çok zaman kazandırdın!
Stas

Şimdiye kadar fark ettiğim bu başarısızlığın en yaygın nedeni budur.
Ayan Sengupta

tam olarak ve bunu yaptığınızda constraintWithItem: youViewöğe onun içinde mevcut değildir!
Nazir

36

Kısa cevap : takas Üst ve alt görünümü. Üst görünüm olduğunu
varsayarsak self:

  • kötü :[subview addConstraint [NSLayoutConstraint constraintWithItem:self...

  • iyi :[self addConstraint [NSLayoutConstraint constraintWithItem:subview...


Swift

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

Obj-C


10

Ek İpuçları:

İOS7'de iyi çalışan ancak iOS8'de "Görünüm hiyerarşisi kısıtlamaya hazır değil" hatası alan yeni geliştirilmiş bir Uygulamam var.

Diğer bazı gönderileri okuyun, kısıtlamalar oluşturmadan önce (alt) görünümlerin eklenmesi gerektiğini söyledi. Bunu yaptım ama yine de hatayı alıyorum.

Sonra, viewDidLoad yerine - (void) viewDidAppear altında kısıtlamalar oluşturmam gerektiğini anladım.


2
Çağrıldığında viewDidAppear(), görünüm zaten kullanıcı tarafından görülebilir. Kısıtlamalar değiştiriliyorsa, ondan önce olmalıdır viewWillLayoutSubviews(). Yaşam
maganap

6

Bu eski bir soru, ancak bu satırı dokümanlardan belirtmek istiyorum:

İOS 8.0 veya sonraki sürümler için geliştirme yaparken, addConstraint (_ :) yöntemini doğrudan çağırmak yerine kısıtlamanın isActive özelliğini true olarak ayarlayın. İsActive özelliği, kısıtlamayı doğru görünüme otomatik olarak ekler ve kaldırır.

Artık addConstraint'i yanlış görünümde çağırma konusunda endişelenmenize gerek olmadığından, bu en azından bir hata noktasını ortadan kaldıracaktır.


2

Benim durumumda, halihazırda oluşturulmuş bir görünüm yerine kök görünümü bir kısıtlama kabı olarak kullanarak çözüldü.

Yani, viewController'ın içinden kullanın

view.addConstraints([leftConstraintImage, topConstraintImage]) onun yerine imageView.addConstraints...


1

@CharlesA'nın cevabında belirttiği gibi sorun, eklediğiniz görünümün doğru görünüm hiyerarşisinde olmamasıdır. Cevabı güzel, ancak benim için bu soruna neden olan belirli bir kullanım durumu için biraz ayrıntı vereceğim:

Görünüm denetleyicisini kullanarak somutlaştırdığım bir görünüme kısıtlamalar eklemeye çalışırken bunu yaşadım instantiateViewControllerWithIdentifier. Sorunu çözmek için kullandım [childViewController didMoveToParentViewController:self]. Bu, benim kısıtlamam tarafından referans verilen görünüm hiyerarşisine görünümü ekledi.


0

Önce alt görünümünüzü ekleyin ve ardından bunun gibi kısıtlamalarınızı ekleyin

addSubview(yourSubViewHere)
yourSubViewHere.translatesAutoresizingMaskIntoConstraints = false

addConstraint(NSLayoutConstraint(....
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.