2014-09-21 12 views
5

Próbuję utworzyć UIView (A) zawierający 2 niestandardowe widoki (b) w nimDodawanie podklasy UIView do stalówka z jego ograniczeniami auto układ

View B jest ustawiony za pomocą wiązań autoLayout i wykonane w konstruktorze Interface , w tym ograniczenia. A dodano do końcówki piszącej viewController

B - UIImageView (Główny = 10, ciągnąc = 10 AlignVertically) - UITextField (Główny = 10, ciągnąc = 10 AlignVertically)

ViewController A (300x300, AlignHorizontally, AlignVertically)

W ViewController mam być ustalona na 300x300 i B1 i B2 ma początku, na końcu, górny i dolny przypięte na 0. (która powinna uczynić B1 i B2 być 300x150, wybacz mi, jeśli coś przegapię)

Wkładając Zobacz BI użyć następującego kodu, aby załadować swój stalówka:

override func awakeAfterUsingCoder(aDecoder: NSCoder!) -> AnyObject! { 
    if self.subviews.count == 0 { 
     let bundle = NSBundle(forClass: self.dynamicType) 
     var view = bundle.loadNibNamed("B", owner: nil, options: nil)[0] as B 
     view.setTranslatesAutoresizingMaskIntoConstraints(false) 
     let constraints = self.constraints() 
     self.removeConstraints(constraints) 
     view.addConstraints(constraints) 
     return view 
    } 
    return self 
} 

Ale gdy próbuję uruchomić to pojawia się następujące ostrzeżenie w tym wypadku:

The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x7f897ad1acc0 V:[TestProject.B:0x7f897af73840(300)]> 
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. 

Próbowałem również dodawanie widok jako własność View B i użyć następującego kodu, aby go dodać do B

NSBundle.mainBundle().loadNibNamed("B", owner: self, options: nil) 
self.addSubview(self.viewOfB); 

wynikiem jest to widok jest dodawany do viewController, ale nie jest przyjęcie dowolnej z opcji AutoLayoutConstraints z własnej końcówki.

W tej chwili nie mam pojęcia, jak dodać ten widok do widoku viewController, w tym ograniczenia. Co ja robię źle? Czy jest lepszy sposób to zrobić?

PS: Widok A był również niestandardowy.

PPS: Używam Swift, aby to zrobić, ale jestem pewien, że rozwiązania w Objective-C działają również.

+0

spojrzeć na tym kursie powinny być pomocne w celu wykorzystania programowo stworzony ograniczenie w swift http://makeapppie.com/2014/07/26/the-swift-swift-tutorial-how-to-use-uiviews- with-auto-layout-programme/ – Signo

Odpowiedz

4

Problem: constraints pobrane z self odnoszą się do self.

Zamiast tego należy wprowadzić nowe ograniczenia odnoszące się do view i takie same inne właściwości. tak:

NSMutableArray *constraints = [NSMutableArray array]; 
for(NSLayoutConstraint *constraint in self.constraints) { 
    id firstItem = constraint.firstItem; 
    id secondItem = constraint.secondItem; 
    if(firstItem == self) firstItem = view; 
    if(secondItem == self) secondItem = view; 
    [constraints addObject:[NSLayoutConstraint constraintWithItem:firstItem 
                 attribute:constraint.firstAttribute 
                 relatedBy:constraint.relation 
                  toItem:secondItem 
                 attribute:constraint.secondAttribute 
                 multiplier:constraint.multiplier 
                 constant:constraint.constant]]; 
} 

/* if you also have to move subviews into `view`. 
for(UIView *subview in self.subviews) { 
    [view addSubview:subview]; 
} 
*/ 

[view addConstraints:constraints]; 

I myślę, że powinieneś skopiować jeszcze kilka właściwości z self.

view.frame = self.frame; 
view.autoresizingMask = self.autoresizingMask; 
view.translatesAutoresizingMaskIntoConstraints = self.translatesAutoresizingMaskIntoConstraints; 

Niestety dla kodu Obj-C, I kopiowane z this answer :)

+0

Brilliant. Nigdy nie odkryłbym, jak poprawnie skopiować te ograniczenia z siebie prawidłowo. – zmonteca

5

Przede wszystkim błędem otrzymujesz dlatego

  • nie można zamienić lub przenieść swoje ograniczenia między widoki
  • widoki muszą być już dodane w hierarchii przed dodaniem nowych ograniczeń
  • więzy są zwykle dodawane widok nadrzędny, który przechowuje widoki (lub wspólny przodek).

    (po więcej szczegółów patrz AutoLayout Guide)

Proponuję o widok A (CustomView: UIView) ładuje zawartość (B wyświetleń) z pliku nib i dodanie ich jako to subviews.

Main View with CustomView A

Sztuką jest to, że trzeba układ, B widoki wewnątrz widokiem zawartości tak, że plik stalówka ma tylko jeden obiekt główny w nim.

W ten sposób, po dodaniu widoku treści jako widoku A podgląd, wszystkie więzy zostaną przeniesione (podobne do tego, jak UITableViewCell używają ich contentView).

ContentView xib

Ważna uwaga: Widok treść powinna NIE być typu klasy CustomView CustomView. Jeśli chcesz przeciągać rynki i akcje, po prostu zadeklaruj obiekt właściciela pliku 10 klasy CustomView i połącz je tam.

Twój ostateczny hierarchia widok powinien wyglądać następująco:

MainView (ViewController's view) 
    View A 
    Content View 
     B1 View 
     B2 View 

ten sposób widok A ma to układ skonfigurowane w ViewController w serii ujęć/XIb i B widoki użyje ograniczeń z pliku nib związanych z treścią widok.

Jedyne więc let jest, aby upewnić się, że widok treść będzie zawsze mają tę samą wielkość i widokiem A.

class CustomView: UIView 
{ 
@IBOutlet var _b1Label: UILabel! 
@IBOutlet var _b2Button: UIButton! 

func loadContentView() 
{ 
    let contentNib = UINib(nibName: "CustomView", bundle: nil) 

    if let contentView = contentNib.instantiateWithOwner(self, options: nil).first as? UIView 
    { 
     self.addSubview(contentView) 

     // We could use autoresizing or manually setting some constraints here for the content view 
     contentView.translatesAutoresizingMaskIntoConstraints = true 
     contentView.autoresizingMask = [.FlexibleHeight, .FlexibleWidth] 
     contentView.frame = self.bounds 
    } 
} 

override init(frame: CGRect) 
{ 
    super.init(frame: frame) 

    loadContentView() 
} 

required init(coder aDecoder: NSCoder) 
{ 
    super.init(coder: aDecoder); 

    loadContentView() 
} 

} 
+0

Próbowałem kilka sposobów ręcznego dodawania ograniczeń dla osadzonego widoku, ale nic nie działało tak niezawodnie jak to podejście - translacja masztu i włączanie translatesAutoresizingMaskIntoConstraints .. –

Powiązane problemy