UIView marco, límites y centro

Me gustaría saber cómo usar estas properties de la manera correcta.

Según tengo entendido, el frame se puede usar desde el contenedor de la vista que estoy creando. Establece la position de la vista en relación con la vista del contenedor. También establece el tamaño de esa vista.

El center también se puede usar desde el contenedor de la vista que estoy creando. Esta propiedad cambia la position de la vista en relación con su contenedor.

Finalmente, los bounds son relativos a la vista misma. Cambia el área dibujable para la vista.

¿Puedes dar más información sobre la relación entre frame y bounds ? ¿Qué pasa con las properties clipsToBounds y masksToBounds ?

Como la pregunta que hice se ha visto muchas veces, le proporcionaré una respuesta detallada. No dude en modificarlo si desea agregar más contenido correcto.

Primero una recapitulación de la pregunta: marco, límites y centro y sus relaciones.

Marco El marco de una vista ( CGRect ) es la position de su rectángulo en el sistema de coorderadas de la vista. De forma pnetworkingeterminada, comienza en la parte superior izquierda.

Límites Los límites de una vista ( CGRect ) expresan un rectángulo de vista en su propio sistema de coorderadas.

Centro Un center es un CGPoint expresado en términos del sistema de coorderadas de la superview y determina la position del punto central exacto de la vista.

Tomado de la position UIView + estas son las relaciones (no funcionan en el código ya que son ecuaciones informales) entre las properties anteriores:

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

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

  • frame.size = bounds.size

NOTA: Estas relaciones no se aplican si las vistas se rotan. Para más información, le sugiero que mire la siguiente image tomada de The Kitchen Drawer basada en el curso Stanford CS193p . Los créditos van a @Rhubarb .

Marco, límites y centro

El uso del frame permite reposicionar y / o cambiar el tamaño de una vista dentro de su superview . Por lo general, se puede usar desde una vista de superview , por ejemplo, cuando crea una subvista específica. Por ejemplo:

 // 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 networkingColor]; [[self view] addSubview:view1]; 

Cuando necesita las coorderadas para dibujar dentro de una view , generalmente se refiere a los bounds . Un ejemplo típico podría ser dibujar dentro de una view una subvista como un recuadro del primero. Dibujar la subvista requiere conocer los bounds de la supervisión. Por ejemplo:

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

Diferentes comportamientos suceden cuando cambia los bounds de una vista. Por ejemplo, si cambia el size los bounds , el frame cambia (y viceversa). El cambio ocurre alnetworkingedor del center de la vista. Use el código a continuación y vea lo que sucede:

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

Además, si cambia el origin bounds , cambiará el origin de su sistema de coorderadas interno. Por defecto, el origin está en (0.0, 0.0) (esquina superior izquierda). Por ejemplo, si cambia el origin de la view1 , puede ver (comente el código anterior si lo desea) que ahora la esquina superior izquierda de la view1 toca la view1 1. La motivación es bastante simple. Dices para view1 que su esquina superior izquierda ahora está en la position (20.0, 20.0) pero desde frame origin frame view2 comienza desde (20.0, 20.0) , coincidirán.

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

El origin representa la position de la view dentro de su superview pero describe la position del centro de bounds .

Finalmente, los bounds y el origin no son conceptos relacionados. Ambos permiten derivar el frame de una vista (ver ecuaciones anteriores).

El estudio de caso de View1

Esto es lo que sucede cuando se usa el siguiente fragment.

 UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(30.0f, 20.0f, 400.0f, 400.0f)]; view1.backgroundColor = [UIColor networkingColor]; [[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])); 

La image relativa

introduzca la descripción de la imagen aquí

Esto, en cambio, sucede si cambio los límites de [self view] como los siguientes.

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

La image relativa

introduzca la descripción de la imagen aquí

Aquí dices a [self view] que su esquina superior izquierda ahora está en la position (30.0, 20.0) pero desde el origen del marco de view1 comienza desde (30.0, 20.0), coincidirán.

Referencias adicionales (para actualizar con otras references si lo desea)

  • UIView Geometry
  • UIView Marcos y límites

Acerca de clipsToBounds (fuente de Apple doc)

Establecer este valor en SÍ hace que las subvistas se recorten a los límites del receptor. Si se establece en NO, las sub venciones cuyos frameworks se extienden más allá de los límites visibles del receptor no se recortan. El valor pnetworkingeterminado es no.

En otras palabras, si el frame una vista es (0, 0, 100, 100) y su subvista es (90, 90, 30, 30) , verá solo una parte de esa subvista. Este último no excederá los límites de la vista principal.

masksToBounds es equivalente a clipsToBounds . En lugar de una UIView , esta propiedad se aplica a un CALayer . Debajo del capó, clipsToBounds llama a masksToBounds . Para más references, vea ¿Cómo está la relación entre los clipsToBounds de UIView y las máscaras de CALayer? .

Esta pregunta ya tiene una buena respuesta, pero quiero complementarla con algunas más imágenes. Mi respuesta completa está aquí.

Para ayudarme a recordar el marco , pienso en un marco de image en una panetworking . Al igual que una image se puede mover a cualquier lugar en la panetworking, el sistema de coorderadas del marco de una vista es la vista de supervisión. (muro = supervista, marco = vista)

Para ayudarme a recordar límites , pienso en los límites de una cancha de baloncesto . El baloncesto está en algún lugar dentro de la cancha al igual que el sistema de coorderadas de los límites de la vista está dentro de la vista misma. (court = view, basketball / players = contenido dentro de la vista)

Al igual que el marco, view.center también está en las coorderadas de la vista de supervisión.

Frame vs Bounds – Ejemplo 1

El rectángulo amarillo representa el marco de la vista. El rectángulo verde representa los límites de la vista. El punto rojo en ambas imágenes representa el origen del marco o los límites dentro de sus sistemas de coorderadas.

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

introduzca la descripción de la imagen aquí


Ejemplo 2

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

introduzca la descripción de la imagen aquí


Ejemplo 3

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

introduzca la descripción de la imagen aquí


Ejemplo 4

Esto es lo mismo que el ejemplo 2, excepto que esta vez se muestra todo el contenido de la vista, ya que se vería como si no estuviera recortada a los límites de la vista.

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

introduzca la descripción de la imagen aquí


Ejemplo 5

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

introduzca la descripción de la imagen aquí

Nuevamente, vea aquí mi respuesta con más detalles.

Encontré esta image más útil para comprender el marco, los límites, etc.

introduzca la descripción de la imagen aquí

También tenga en count que frame.size != bounds.size cuando la image se gira.

  • La propiedad frame contiene el rectángulo de marco, que especifica el tamaño y la location de la vista en el sistema de coorderadas de su supervisor.
  • La propiedad de límites contiene el rectángulo de límites, que especifica el tamaño de la vista (y su origen de contenido) en el sistema de coorderadas local propio de la vista.
  • La propiedad del centro contiene el punto central conocido de la vista en el sistema de coorderadas de la supervisión.

Creo que si lo crees desde el punto de CALayer , todo está más claro.

El marco no es realmente una propiedad distinta de la vista o capa, es una propiedad virtual, calculada desde los límites, la position (centro de UIView ) y transformada.

Entonces, básicamente, cómo los layouts de capa / vista realmente se deciden con estas tres properties (y anchorPoint), y cualquiera de estas tres properties no cambiará ninguna otra propiedad, como cambiar transformar no cambia límites.

Hay muy buenas respuestas con explicaciones detalladas para esta publicación. Solo quisiera referirme que hay otra explicación con representación visual para el significado de Frame, Bounds, Center, Transform, Bounds Origin en el video de WWDC 2011 Comprender la representación de UIKit a partir de @ 4: 22 hasta las 20:10

Después de leer las respuestas anteriores, aquí agregando mis interpretaciones.

Supongamos que navegar en línea, browser web es su frame que decide dónde y qué tan grande para mostrar la página web. Scroller del browser es su bounds.origin que decide qué parte de la página web se mostrará. bounds.origin es difícil de entender. La mejor manera de aprender es crear la aplicación Single View, intentando modificar estos parameters y ver cómo cambian las subvistas.

 - (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 networkingColor]]; 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)); 
    Intereting Posts