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 .
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
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
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)
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.
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
Frame origin = (40, 60) // That is, x=40 and y=60 width = 80 height = 130 Bounds origin = (0, 0) width = 80 height = 130
Frame origin = (20, 52) // These are just rough estimates. width = 118 height = 187 Bounds origin = (0, 0) width = 80 height = 130
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
Frame origin = (40, 60) width = 80 height = 130 Bounds origin = (280, 70) width = 80 height = 130
Nuevamente, vea aquí mi respuesta con más detalles.
Encontré esta image más útil para comprender el marco, los límites, etc.
También tenga en count que frame.size != bounds.size
cuando la image se gira.
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));