Cornice, limiti e centro UIView


320

Vorrei sapere come usare queste proprietà nel modo giusto.

A quanto ho capito, framepuò essere utilizzato dal contenitore della vista che sto creando. Imposta la posizione della vista rispetto alla vista del contenitore. Imposta anche la dimensione di quella vista.

Inoltre centerpuò essere utilizzato dal contenitore della vista che sto creando. Questa proprietà cambia la posizione della vista rispetto al suo contenitore.

Infine, boundsè relativo alla vista stessa. Cambia l'area di disegno per la vista.

Puoi fornire maggiori informazioni sulla relazione tra framee bounds? Che dire delle proprietà clipsToBoundse masksToBounds?


1
Questa discussione è già stata risolta qui. quindi per favore guardalo qui o potresti vedere la documentazione per gli sviluppatori fornita qui developer.apple.com/library/ios/#documentation/uikit/reference/… stackoverflow.com/questions/1210047/… slideshare.net/onoaonoa/cs193p-lecture-5 -view-animazione
Splendido

Risposte:


577

Poiché la domanda che ho posto è stata vista molte volte, fornirò una risposta dettagliata. Sentiti libero di modificarlo se vuoi aggiungere altro contenuto corretto.

Innanzitutto un riassunto della domanda: cornice, limiti e centro e le loro relazioni.

Frame Una vista frame( CGRect) è la posizione del suo rettangolo nel superviewsistema di coordinate. Di default inizia in alto a sinistra.

Limiti Una vista bounds( CGRect) esprime un rettangolo vista nel proprio sistema di coordinate.

Il centro A centerè CGPointespresso in termini di superviewsistema di coordinate del e determina la posizione del punto centrale esatto della vista.

Tratte da UIView + position, queste sono le relazioni (non funzionano nel codice poiché sono equazioni informali) tra le proprietà precedenti:

  • frame.origin = center - (bounds.size / 2.0)

  • center = frame.origin + (bounds.size / 2.0)

  • frame.size = bounds.size

NOTA: queste relazioni non si applicano se le viste sono ruotate. Per ulteriori informazioni, ti suggerirò di dare un'occhiata alla seguente immagine tratta da The Kitchen Drawer basata sul corso Stanford CS193p . I crediti vanno a @Rhubarb .

Cornice, limiti e centro

L'uso di frameconsente di riposizionare e / o ridimensionare una vista al suo interno superview. Di solito può essere utilizzato da un superview, ad esempio, quando si crea una vista secondaria specifica. Per esempio:

// view1 will be positioned at x = 30, y = 20 starting the top left corner of [self view]
// [self view] could be the view managed by a UIViewController
UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(30.0f, 20.0f, 400.0f, 400.0f)];    
view1.backgroundColor = [UIColor redColor];

[[self view] addSubview:view1];

Quando hai bisogno delle coordinate per disegnare all'interno di una a viewcui di solito ti riferisci bounds. Un esempio tipico potrebbe essere quello di disegnare all'interno di viewuna sottoview come un inserto del primo. Disegnare la sottoview richiede di conoscere boundsla superview. Per esempio:

UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(50.0f, 50.0f, 400.0f, 400.0f)];    
view1.backgroundColor = [UIColor redColor];

UIView* view2 = [[UIView alloc] initWithFrame:CGRectInset(view1.bounds, 20.0f, 20.0f)];    
view2.backgroundColor = [UIColor yellowColor];

[view1 addSubview:view2];

Si verificano comportamenti diversi quando si cambia la boundsvista. Ad esempio, se si cambiano le bounds size, le framemodifiche (e viceversa). Il cambiamento avviene attorno centeralla vista. Usa il codice qui sotto e guarda cosa succede:

NSLog(@"Old Frame %@", NSStringFromCGRect(view2.frame));
NSLog(@"Old Center %@", NSStringFromCGPoint(view2.center));    

CGRect frame = view2.bounds;
frame.size.height += 20.0f;
frame.size.width += 20.0f;
view2.bounds = frame;

NSLog(@"New Frame %@", NSStringFromCGRect(view2.frame));
NSLog(@"New Center %@", NSStringFromCGPoint(view2.center));

Inoltre, se si cambia, bounds originsi modifica il originrelativo sistema di coordinate interno. Di default originè a (0.0, 0.0)(angolo in alto a sinistra). Ad esempio, se cambi il originper view1puoi vedere (commenta il codice precedente se vuoi) che ora l'angolo in alto a sinistra view2tocca view1quello. La motivazione è abbastanza semplice. Tu dici a view1che il suo angolo in alto a sinistra è ora nella posizione (20.0, 20.0), ma dal momento che view2's frame originparte da (20.0, 20.0), essi coincidono.

CGRect frame = view1.bounds;
frame.origin.x += 20.0f;
frame.origin.y += 20.0f;
view1.bounds = frame; 

Il originrappresenta la viewposizione del suo superviewma descrive la posizione delbounds centro.

Infine, boundse originnon sono concetti correlati. Entrambi consentono di derivare la framevista (Vedi equazioni precedenti).

Caso di studio di View1

Ecco cosa succede quando si utilizza il seguente frammento.

UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(30.0f, 20.0f, 400.0f, 400.0f)];
view1.backgroundColor = [UIColor redColor];

[[self view] addSubview:view1];

NSLog(@"view1's frame is: %@", NSStringFromCGRect([view1 frame]));
NSLog(@"view1's bounds is: %@", NSStringFromCGRect([view1 bounds]));
NSLog(@"view1's center is: %@", NSStringFromCGPoint([view1 center]));

L'immagine relativa.

inserisci qui la descrizione dell'immagine

Questo invece cosa succede se cambio [self view]limiti come il seguente.

// previous code here...
CGRect rect = [[self view] bounds];
rect.origin.x += 30.0f;
rect.origin.y += 20.0f;
[[self view] setBounds:rect];

L'immagine relativa.

inserisci qui la descrizione dell'immagine

Qui dici [self view]che il suo angolo in alto a sinistra ora è nella posizione (30.0, 20.0) ma poiché view1l'origine del frame inizia da (30.0, 20.0), coincideranno.

Riferimenti aggiuntivi (da aggiornare con altri riferimenti se lo si desidera)

Informazioni clipsToBounds(fonte Apple doc)

Impostando questo valore su SÌ, i sottoview vengono ritagliati ai limiti del ricevitore. Se impostato su NO, le visualizzazioni secondarie i cui frame si estendono oltre i limiti visibili del ricevitore non vengono ritagliate. Il valore predefinito è no.

In altre parole, se la vista frameè (0, 0, 100, 100)e la sua vista secondaria è (90, 90, 30, 30), vedrai solo una parte di quella vista secondaria. Quest'ultimo non supererà i limiti della vista padre.

masksToBoundsè equivalente a clipsToBounds. Invece a a UIView, questa proprietà viene applicata a CALayer. Sotto il cofano, clipsToBoundschiama masksToBounds. Per ulteriori riferimenti, dai un'occhiata a Come è la relazione tra i clip di UIViewToBounds e le maschere di CALayerToBounds? .


@Rhubarb Hai perfettamente ragione. Lo sottolineo nella mia risposta. Grazie.
Lorenzo B,

Non so se otterrò una risposta, ma perché la sottoview si sposta nella direzione negativa quando cambiano le origini dei limiti. Non riesco proprio a farmi girare la testa. Grazie!!
nimgrg,

@nimgrg Sembra che la vista si sposti nella direzione negativa ma non lo è. Le coordinate interne della superview vengono modificate.
Lorenzo B,

perdona le mie capacità geometriche, se le coordinate interne della superview vengono cambiate in origine (30.0, 20.0), il punto (0,0) si trova all'interno del quadrato blu o all'esterno di esso. Sto solo cercando di rintracciare i cambiamenti e dargli un senso. Grazie per il tempo dedicato a rispondere.
nimgrg

@flexaddicted: Salve, la diapositiva che hai aggiunto dice: "Visualizza il centro di B nel suo spazio di coordinate è: bounds.size.width / 2 + origin.x" - perché è così? Dal momento che il titolo dice nel suo spazio di coordinate, direi che è: bounds.size.width / 2 + bounds.origin.x ?? Non è vero ??

134

Questa domanda ha già una buona risposta, ma voglio completarla con qualche altra foto. La mia risposta completa è qui.

Per aiutarmi a ricordare la cornice , penso a una cornice su un muro . Proprio come un'immagine può essere spostata ovunque sul muro, il sistema di coordinate della cornice di una vista è la superview. (wall = superview, frame = view)

Per aiutarmi a ricordare i limiti , penso ai limiti di un campo da basket . Il basket è da qualche parte all'interno del campo, proprio come il sistema di coordinate dei limiti della vista è all'interno della vista stessa. (campo = vista, pallacanestro / giocatori = contenuto all'interno della vista)

Come il frame, view.center è anche nelle coordinate della superview.

Frame vs Bounds - Esempio 1

Il rettangolo giallo rappresenta la cornice della vista. Il rettangolo verde rappresenta i limiti della vista. Il punto rosso in entrambe le immagini rappresenta l'origine della cornice o dei limiti all'interno dei loro sistemi di coordinate.

Frame
    origin = (0, 0)
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

inserisci qui la descrizione dell'immagine


Esempio 2

Frame
    origin = (40, 60)  // That is, x=40 and y=60
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

inserisci qui la descrizione dell'immagine


Esempio 3

Frame
    origin = (20, 52)  // These are just rough estimates.
    width = 118
    height = 187

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

inserisci qui la descrizione dell'immagine


Esempio 4

È lo stesso dell'esempio 2, tranne che questa volta viene mostrato l'intero contenuto della vista come apparirebbe se non fosse tagliato ai limiti della vista.

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

inserisci qui la descrizione dell'immagine


Esempio 5

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds 
    origin = (280, 70)
    width = 80
    height = 130

inserisci qui la descrizione dell'immagine

Ancora una volta, vedi qui per la mia risposta con maggiori dettagli.


2
Grazie Suragch. È un'immagine molto chiara del frame e della differenza legata. Apprezzo molto il tuo impegno.
Mohd Haider,

Tutte le cose che voglio vedere in una risposta breve e concisa. Grazie!
Matt Chuang,

Eccezionale! Per esempio 3: non capisco. hai spostato solo leggermente l'origine della cornice, come cambia la rotazione dell'immagine?
Miele

@ asma22, nell'esempio 3 stavo solo cercando di mostrare che quando si ruota un'immagine la cornice cambia ma i limiti no. Vedi la mia risposta più completa .
Suragch,

89

Ho trovato questa immagine molto utile per comprendere frame, limiti, ecc.

inserisci qui la descrizione dell'immagine

Si noti inoltre che frame.size != bounds.sizequando l'immagine viene ruotata.


14
Un'immagine che vale più di mille parole.
Narendra Kamma,

3
La migliore spiegazione possibile
Ratikanta Patra,

@Erben Mo: Ciao, la diapositiva che hai aggiunto dice: "Visualizza il centro di B nel suo spazio di coordinate è: bounds.size.width / 2 + origin.x" - perché è così? Dal momento che il titolo dice nel suo spazio di coordinate, direi che è: bounds.size.width / 2 + bounds.origin.x ?? Non è vero ??

1
Qual è la fonte di questa immagine? Link?
David,

1
@David È del corso CS193p di Stanford su iTunesU trovato qui: www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2013-fall
preynolds

3

Penso che se lo pensi dal punto di vista CALayer, tutto è più chiaro.

Frame non è affatto una proprietà distinta della vista o del livello, è una proprietà virtuale, calcolata dai limiti, dalla posizione ( UIViewal centro) e dalla trasformazione.

Quindi sostanzialmente come il layout layer / view è davvero deciso da queste tre proprietà (e anchorPoint), e una di queste tre proprietà non cambierà nessun'altra proprietà, come cambiare la trasformazione non cambia i limiti.


2

Ci sono ottime risposte con spiegazioni dettagliate a questo post. Vorrei solo fare riferimento al fatto che esiste un'altra spiegazione con rappresentazione visiva del significato di Frame, Bounds, Center, Transform, Bounds Origin nel video di WWDC 2011 Comprensione del rendering UIKit a partire da @ 4: 22 fino alle 20:10


0

Dopo aver letto le risposte sopra, qui aggiungo le mie interpretazioni.

Supponiamo che la navigazione online sia il tuo browserframe che decide dove e quanto grande mostrare la pagina web. Lo scroller del browser è il tuo bounds.originche decide quale parte della pagina web verrà mostrata. bounds.originè difficile da capire. Il modo migliore per imparare è creare un'applicazione a vista singola, provare a modificare questi parametri e vedere come cambiano le visualizzazioni secondarie.

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(100.0f, 200.0f, 200.0f, 400.0f)];
[view1 setBackgroundColor:[UIColor redColor]];

UIView *view2 = [[UIView alloc] initWithFrame:CGRectInset(view1.bounds, 20.0f, 20.0f)];
[view2 setBackgroundColor:[UIColor yellowColor]];
[view1 addSubview:view2];

[[self view] addSubview:view1];

NSLog(@"Old view1 frame %@, bounds %@, center %@", NSStringFromCGRect(view1.frame), NSStringFromCGRect(view1.bounds), NSStringFromCGPoint(view1.center));
NSLog(@"Old view2 frame %@, bounds %@, center %@", NSStringFromCGRect(view2.frame), NSStringFromCGRect(view2.bounds), NSStringFromCGPoint(view2.center));

// Modify this part.
CGRect bounds = view1.bounds;
bounds.origin.x += 10.0f;
bounds.origin.y += 10.0f;

// incase you need width, height
//bounds.size.height += 20.0f;
//bounds.size.width += 20.0f;

view1.bounds = bounds;

NSLog(@"New view1 frame %@, bounds %@, center %@", NSStringFromCGRect(view1.frame), NSStringFromCGRect(view1.bounds), NSStringFromCGPoint(view1.center));
NSLog(@"New view2 frame %@, bounds %@, center %@", NSStringFromCGRect(view2.frame), NSStringFromCGRect(view2.bounds), NSStringFromCGPoint(view2.center));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.