2013-06-30 13 views
13

Sto cercando di capire meglio come funzionano le visualizzazioni contenitore nello storyboard. Il comportamento sembra essere che la vista del contenitore costringerà la sua sottoview a ridimensionarsi per riempire il contenitore.Che cosa causa Container View per mantenere il frame della sua vista figlia in modo che corrisponda ai propri limiti?

storyboard relationships

vedo vincoli che spiegano, e non c'è alcuna menzione di quale classe si tratta. Sembra una magia da storyboard.

constraints

Suppongo che la vista contenitore deve essere una sottoclasse di UIView, e avrò un ipotesi e ne assume la chiamata UIContainerView, ma la ricerca attraverso le rese di documentazione solo due risultati.

search results

Quindi, come funziona?

+0

Non penso sia una sottoclasse, penso che sia solo un UIView, e dietro le quinte, Xcode imposta il frame del controller incorporato per essere uguale ai limiti della vista del contenitore. – rdelmar

risposta

25

L'editor storyboard (Interface Builder) mantiene la vista incorporata frame impostata nella vista contenitore bounds durante la modifica. Pertanto, quando lo storyboard viene scritto su un file, le dimensioni serializzate delle viste sono identiche. Ciò accade indipendentemente dal fatto che lo storyboard abbia abilitato il layout automatico.

La vista di livello superiore di ciascun controller di visualizzazione nello storyboard ha anche la sua maschera di autoresizzazione impostata su UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight, anche se lo storyboard ha abilitato il layout automatico.

Se il layout automatico è abilitato, ciascuna vista di livello superiore ha il suo translatesAutoresizingMaskToConstraints impostato su YES. Questo è diverso da tutti i discendenti di quelle viste di primo livello. Tutti i discendenti hanno translatesAutoresizingMaskToConstraints impostato su NO.

La relazione di incorporamento è rappresentata come un passaggio della classe UIStoryboardEmbedSegue. (Questa è una classe privata, non parte dell'API pubblica.)

Quando UIStoryboardEmbedSegue riceve il messaggio perform, carica la vista del controller della vista di destinazione e la aggiunge come vista secondaria della vista Contenitore. Quindi imposta la vista incorporata autoresizingMask su UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight. Questo è ridondante, poiché Interface Builder lo ha già impostato nello storyboard.

Quindi -[UIStoryboardEmbedSegue perform] controlla la vista incorporata translatesAutoresizingMaskToConstraints. Anche questo è ridondante, perché Interface Builder lo imposta su YES.

Se del translatesAutoresizingMaskToConstraints vista incorporata è YES, perform imposta del frame al contenitore vista di bounds vista incorporata. Di nuovo, ridondante.

Se del translatesAutoresizingMaskToConstraints vista incorporata è NO, perform aggiunge vincoli H:|[childView]| e V:|[childView]|, costringendo così la vista incorporata per riempire la vista contenitore. (Sì, in realtà utilizza il linguaggio del formato visivo.) Questo ramo non dovrebbe essere raggiunto.

Quando per una vista translatesAutoresizingMaskToConstraints insieme a YES, il layout automatico aggiunge automaticamente i vincoli di tipo NSAutoresizingMaskLayoutConstraint e li mantiene fino alla data in cui si cambia il frame vista. Per esempio, la vista radice di una finestra è fatto per riempire la finestra utilizzando i vincoli ridimensionamento automatico:

<NSAutoresizingMaskLayoutConstraint:0x7555d00 h=-&- v=-&- UIView:0x7671780.midX == UIWindow:0x7551010.midX>, 
<NSAutoresizingMaskLayoutConstraint:0x7555de0 h=-&- v=-&- UIView:0x7671780.width == UIWindow:0x7551010.width>, 
<NSAutoresizingMaskLayoutConstraint:0x7555eb0 h=-&- v=-&- UIView:0x7671780.midY == UIWindow:0x7551010.midY + 10>, 
<NSAutoresizingMaskLayoutConstraint:0x7555ef0 h=-&- v=-&- UIView:0x7671780.height == UIWindow:0x7551010.height - 20> 

Ecco, questo è ciò che “fa sì Container View per tenere telaio del suo punto di vista del bambino per abbinare i suoi limiti”.

L'ho capito osservando il file .storyboard (è un XML sorprendentemente leggibile) e guardando -[UIStoryboardEmbedSegue perform] in Hopper.

Per quanto riguarda il motivo per cui hanno i controlli ridondanti, mi viene in mente un paio di probabili motivi:

  1. IB (forse in versioni pre-release) non sempre impostare le proprietà di visualizzazione del modo in cui fa ora, quindi il codice non è ridondante quando si caricano i vecchi storyboard.

  2. Apple ha strumenti interni che generano storyboard in modo diverso da IB.

  3. Il codice è disponibile per la compatibilità diretta con le versioni future di IB che consentono visualizzazioni dello storyboard di livello superiore con proprietà diverse.

+3

Ottima spiegazione! Significa anche che, quando si utilizza uno storyboard, non è possibile avere il contenuto di una vista contenitore per decidere l'altezza della vista del contenitore (a cui sono applicati i vincoli che centrano la vista nella vista in cui è incorporato)? –

+1

@Scott Sembra che dovresti leggere la mia risposta a [questa domanda] (http://stackoverflow.com/q/17376240/77567). –

+0

risposta perfetta e uso eccellente di Hopper – malhal

0

L'impostazione di un progetto di test e l'introduzione del codice forniscono un'idea abbastanza chiara di come viene implementato. La vista contenitore stessa è un semplice UIView. Come parte del processo loadView dei controller, la vista del contenitore viene creata con l'impostazione dei vincoli nello storyboard. Viene quindi eseguito il follow-up del controller incorporato. Questo crea il controller della vista figlio, che ha la sua vista aggiunta come vista secondaria della vista del contenitore e l'impostazione dei vincoli di layout appropriata in modo che la vista secondaria riempia il contenitore. Questo è davvero.

+0

Sì, ma ovviamente non funziona. Dopo aver resettato un ContainerView, le viste secondarie non si adattano al nuovo limite. –

Problemi correlati