UIView marco, límites y centro

320

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

Según tengo entendido, framese puede usar 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 centerse puede usar desde el contenedor de la vista que estoy creando. Esta propiedad cambia la posición de la vista en relación con su contenedor.

Finalmente, boundses relativo a la vista en sí. Cambia el área dibujable para la vista.

¿Puedes dar más información sobre la relación entre framey bounds? ¿Qué pasa con el clipsToBoundsy las masksToBoundspropiedades?

Lorenzo B
fuente
1
Esta discusión ya está resuelta aquí. así que por favor mírelo aquí o podría ver la Documentación del desarrollador dada aquí developer.apple.com/library/ios/#documentation/uikit/reference/… stackoverflow.com/questions/1210047/… slideshare.net/onoaonoa/cs193p-lecture-5 -view-animation
Splendid

Respuestas:

577

Como la pregunta que hice se ha visto muchas veces, proporcionaré 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.

El marco de una vista frame( CGRect) es la posición de su rectángulo en el superviewsistema de coordenadas. Por defecto comienza en la esquina superior izquierda.

Límites Una vista bounds( CGRect) expresa un rectángulo de vista en su propio sistema de coordenadas.

El Centro A centerse CGPointexpresa en términos del superviewsistema de coordenadas del 's y determina la posición del punto central exacto de la vista.

Tomados de la posición UIView +, 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 las vistas se giran. Para más información, le sugiero que eche un vistazo a la siguiente imagen tomada de The Kitchen Drawer basada en el curso Stanford CS193p . Los créditos van a @Rhubarb .

Marco, límites y centro

El uso de le framepermite reposicionar y / o cambiar el tamaño de una vista dentro de ella superview. Por lo general, se puede usar desde 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 un view, generalmente se refiere bounds. Un ejemplo típico podría ser dibujar dentro de viewuna subvista como una inserción de la primera. Dibujar la subvista requiere conocer la boundsde la supervista. 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];

Se producen diferentes comportamientos cuando cambia la boundsvista. Por ejemplo, si cambia el bounds size, los framecambios (y viceversa). El cambio ocurre alrededor centerde la vista. Use el código a continuación y vea qué 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 bounds origin, cambia el originde su sistema de coordenadas interno. Por defecto, originestá en (0.0, 0.0)(esquina superior izquierda). Por ejemplo, si cambia el originpara view1, puede ver (comente el código anterior si lo desea) que ahora la esquina superior izquierda view2toca el view1. La motivación es bastante simple. Usted dice a view1que su esquina superior izquierda ahora está en la posición (20.0, 20.0)pero ya que view2's frame originse inicia a partir (20.0, 20.0), ellos coinciden.

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

El originrepresenta la viewposición del 's dentro de su superviewpero describe la posición delbounds centro.

Finalmente, boundsy originno son conceptos relacionados. Ambos permiten derivar el framede una vista (Ver ecuaciones anteriores).

Estudio de caso de View1

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

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.

ingrese la descripción de la imagen aquí

Esto, en cambio, es lo que sucede si cambio [self view]límites 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.

ingrese la descripción de la imagen aquí

Aquí dices [self view]que su esquina superior izquierda ahora está en la posición (30.0, 20.0) pero desdeview1 el origen del cuadro comienza desde (30.0, 20.0), coincidirán.

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

Acerca de clipsToBounds(fuente de Apple doc)

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

En otras palabras, si una vista framees (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.

masksToBoundses equivalente a clipsToBounds. En lugar de a UIView, esta propiedad se aplica a a CALayer. Debajo del capó, clipsToBoundsllamadas masksToBounds. Para más referencias eche un vistazo a ¿Cómo es la relación entre los clipsToBounds de UIView y las máscarasToBounds de CALayer? .

Lorenzo Boaro
fuente
@ Ruibarbo Tienes toda la razón. Lo señalaré en mi respuesta. Gracias.
Lorenzo B
No sé si obtendré una respuesta, pero ¿por qué la subvista se mueve en la dirección negativa cuando se cambian los orígenes de los límites? Parece que no puedo entenderlo un poco. ¡¡Gracias!!
nimgrg
@nimgrg Parece que la vista se mueve en la dirección negativa, pero no lo es. Se cambian las coordenadas internas de la supervista.
Lorenzo B
perdona mis habilidades geométricas, si las coordenadas internas de la supervista se cambian a origen (30.0, 20.0), el punto (0,0) se encuentra dentro del cuadrado azul o fuera de él. Solo estoy tratando de rastrear los cambios y darle sentido. Gracias por tomarse el tiempo de responder.
nimgrg
@flexaddicted: Hola, la diapositiva que agregó dice: "Ver el centro de B en su propio espacio de coordenadas es: limits.size.width / 2 + origin.x" - ¿por qué es este el caso? Como el título dice en su propio espacio de coordenadas, yo diría que es: limits.size.width / 2 + limits.origin.x ?? ¿No es así?
134

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 en una pared . Al igual que una imagen se puede mover a cualquier parte de la pared, el sistema de coordenadas del marco de una vista es la supervista. (pared = supervista, marco = vista)

Para ayudarme a recordar los límites , pienso en los límites de una cancha de baloncesto . La pelota de 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. (cancha = vista, baloncesto / jugadores = contenido dentro de la vista)

Al igual que el marco, view.center también está en las coordenadas de la supervista.

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 límites dentro de sus sistemas de coordenadas.

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

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

ingrese 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

ingrese 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

ingrese la descripción de la imagen aquí


Ejemplo 4

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

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

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

ingrese 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

ingrese la descripción de la imagen aquí

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

Suragch
fuente
2
Gracias Suragch Es realmente una imagen muy clara del marco y la diferencia de límite. Yo realmente aprecio tu esfuerzo.
Mohd Haider
Todo lo que quiero ver en una respuesta breve y concisa. ¡Gracias!
Matt Chuang el
¡Increíble! Para el ejemplo 3: no lo entiendo. solo moviste un poco el origen de tu marco, ¿cómo cambia eso la rotación de tu imagen?
Miel
@ asma22, en el ejemplo 3, solo intentaba mostrar que cuando gira una imagen, el marco cambia pero los límites no. Ver mi respuesta más completa .
Suragch
89

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

ingrese la descripción de la imagen aquí

También tenga en cuenta que frame.size != bounds.sizecuando se gira la imagen.

Erben Mo
fuente
14
Una imagen que vale más que mil palabras.
Narendra Kamma
3
La mejor explicación posible
Ratikanta Patra
@ Erben Mo: Hola, la diapositiva que agregaste dice: "Ver el centro de B en su propio espacio de coordenadas es: limits.size.width / 2 + origin.x" - ¿por qué es este el caso? Como el título dice en su propio espacio de coordenadas, yo diría que es: limits.size.width / 2 + limits.origin.x ?? ¿No es así?
1
¿Cuál es la fuente de esta imagen? ¿Enlace?
David
1
@David Es del curso CS193p de Stanford en iTunesU que se encuentra aquí: www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2013-fall
preynolds
3

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

El marco no es realmente una propiedad distinta de la vista o capa, es una propiedad virtual, calculada a partir de los límites, la posición (UIView centro de ') y la transformación.

Entonces, básicamente, cómo los diseños de capa / vista realmente se deciden 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.

remolacha
fuente
2

Hay muy buenas respuestas con una explicación detallada de esta publicación. Solo me gustaría referirme a que hay otra explicación con representación visual para el significado de Frame, Bounds, Center, Transform, Bounds Origin en el video WWDC 2011 Comprensión de la representación UIKit a partir de las 4: 22 hasta las 20:10

Wael Showair
fuente
0

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

Supongamos que navega en línea, su navegador web es el frameque decide dónde y qué tan grande mostrar la página web. El desplazador del navegador es el bounds.originque decide qué parte de la página web se mostrará. bounds.originEs dificil de entender. La mejor manera de aprender es creando 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));
NSTNF
fuente