objective c - UIView marco, límites y centro
objective-c ios (7)
Me gustaría saber cómo usar estas propiedades de la manera correcta.
Según tengo entendido, el frame
se puede utilizar desde el contenedor de la vista que estoy creando. Establece la posición de la vista en relación con la vista del contenedor. También establece el tamaño de esa vista.
También se puede usar el center
desde el contenedor de la vista que estoy creando. Esta propiedad cambia la posición de la vista relativa a su contenedor.
Finalmente, los bounds
son relativos a la vista en sí. Cambia el área de dibujo para la vista.
¿Puedes dar más información sobre la relación entre frame
y bounds
? ¿Qué pasa con las propiedades clipsToBounds
y masksToBounds
?
Creo que si lo piensas 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 posición (centro de UIView
) y la transformación.
Básicamente, la forma en que los diseños de capa / vista se deciden realmente por estas tres propiedades (y anchorPoint), y cualquiera de estas tres propiedades no cambiará ninguna otra propiedad, como cambiar la transformación no cambia los límites.
Dado que la pregunta que formulé se ha visto muchas veces, le daré una respuesta detallada. Siéntase libre de modificarlo si desea agregar más contenido correcto.
Primero un resumen de la pregunta: marco, límites y centro y sus relaciones.
Marco El marco de una vista ( CGRect
) es la posición de su rectángulo en el sistema de coordenadas de la vista superview
. Por defecto 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 coordenadas.
Centro Un center
es un CGPoint
expresado en términos del sistema de coordenadas de la vista y determina la posición del punto central exacto de la vista.
Tomadas de UIView + position, estas son las relaciones (no funcionan en código, ya que son ecuaciones informales) entre las propiedades 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 se giran las vistas. Para obtener más información, sugeriré que eche un vistazo a la siguiente imagen tomada de The Kitchen Drawer basada en el curso Stanford CS193p . Los créditos van para @Rhubarb .
El uso del frame
permite reposicionar y / o redimensionar una vista dentro de su superview
. Por lo general, se puede usar desde una 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 redColor];
[[self view] addSubview:view1];
Cuando necesita las coordenadas para dibujar dentro de una view
, usualmente se refiere a los bounds
. Un ejemplo típico podría ser dibujar dentro de una view
una subvista como un recuadro de la primera. 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 redColor];
UIView* view2 = [[UIView alloc] initWithFrame:CGRectInset(view1.bounds, 20.0f, 20.0f)];
view2.backgroundColor = [UIColor yellowColor];
[view1 addSubview:view2];
Diferentes comportamientos suceden cuando cambias los bounds
de una vista. Por ejemplo, si cambia el size
los bounds
, el frame
cambia (y viceversa). El cambio ocurre alrededor del center
de la vista. Usa el código de abajo y mira qué pasa:
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
, cambia el origin
de su sistema de coordenadas 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 (comentar el código anterior si lo desea) que ahora la esquina superior izquierda de la view1
toca la view1
. La motivación es bastante simple. Usted dice a view1
que su esquina superior izquierda ahora está en la posición (20.0, 20.0)
pero que el origin
frame
view2
comienza en (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 posición de la view
dentro de su superview
pero describe la posición del centro de los bounds
.
Finalmente, los bounds
y el origin
no son conceptos relacionados. Ambos permiten derivar el frame
de una vista (ver ecuaciones anteriores).
Caso de estudio de View1
Esto es lo que sucede cuando se utiliza el siguiente fragmento de código.
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]));
La imagen relativa.
Esto, en cambio, qué sucede si cambio los límites de [self view]
como el siguiente.
// previous code here...
CGRect rect = [[self view] bounds];
rect.origin.x += 30.0f;
rect.origin.y += 20.0f;
[[self view] setBounds:rect];
La imagen relativa.
Aquí le dice a [self view]
que su esquina superior izquierda ahora está en la posición (30.0, 20.0) pero que el origen del marco de view1
comienza en (30.0, 20.0), coincidirán.
Referencias adicionales (para actualizar con otras referencias si lo desea)
Acerca de clipsToBounds
(fuente 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 subvistas cuyos fotogramas se extienden más allá de los límites visibles del receptor no se recortan. El valor predeterminado es no.
En otras palabras, si el frame
una vista es (0, 0, 100, 100)
y su subvista es (90, 90, 30, 30)
, solo verá una parte de esa subvista. Este último no excederá los límites de la vista principal.
masksToBounds
es equivalente a clipsToBounds
. En lugar de a UIView
, esta propiedad se aplica a un CALayer
. Bajo el capó, clipsToBounds
llama a masksToBounds
. Para obtener más referencias, consulte ¿Cómo es la relación entre los clips ToBounds de UIView y las máscaras ToBounds de CALayer? .
Después de leer las respuestas anteriores, aquí agregando mis interpretaciones.
Supongamos que navegando en línea, el navegador web es su frame
que decide dónde y qué tamaño mostrar la página web. La bounds.origin
del navegador son sus bounds.origin
. El bounds.origin
determina qué parte de la página web se mostrará. bounds.origin
son difíciles de entender. La mejor manera de aprender es crear una aplicación de vista única, intentando modificar estos parámetros 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 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));
Encontré esta imagen más útil para entender el marco, los límites, etc.
También tenga en cuenta que frame.size != bounds.size
cuando se gira la imagen.
Esta pregunta ya tiene una buena respuesta, pero quiero complementarla con algunas fotos más. Mi respuesta completa está aquí.
Para ayudarme a recordar el marco , pienso en un marco de imagen en una pared . Al igual que una imagen se puede mover a cualquier lugar de la pared, el sistema de coordenadas del marco de una vista es la vista de supervisión. (wall = superview, frame = view)
Para ayudarme a recordar límites , pienso en los límites de una cancha de básquetbol . El baloncesto está en algún lugar dentro de la cancha al igual que el sistema de coordenadas de los límites de la vista está dentro de la vista misma. (corte = vista, baloncesto / jugadores = contenido dentro de la vista)
Al igual que el marco, view.center también se encuentra en las coordenadas de la vista de supervisión.
Cuadro vs límites - 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 coordenadas.
Frame
origin = (0, 0)
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
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
Ejemplo 3
Frame
origin = (20, 52) // These are just rough estimates.
width = 118
height = 187
Bounds
origin = (0, 0)
width = 80
height = 130
Ejemplo 4
Esto es lo mismo que en el ejemplo 2, excepto que esta vez se muestra todo el contenido de la vista, tal como se vería si no se recortara a los límites de la vista.
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Ejemplo 5
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (280, 70)
width = 80
height = 130
Una vez más, ver aquí para mi respuesta con más detalles.
Hay muy buenas respuestas con una explicación detallada de este post. Solo quisiera referirme a que hay otra explicación con representación visual para el significado de Frame, Bounds, Center, Transform, Bounds Origin en WWDC 2011 Comprendiendo el UIKit Rendering a partir de @ 4: 22 hasta 20:10
- La propiedad de marco contiene el rectángulo de marco, que especifica el tamaño y la ubicación de la vista en el sistema de coordenadas de su supervisión.
- 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 propio sistema de coordenadas local de la vista.
- La propiedad central contiene el punto central conocido de la vista en el sistema de coordenadas de la vista previa.