Pregunta

UIView y sus subclases tienen todas las propiedades frame y límites . ¿Cuál es la diferencia?

¿Fue útil?

Solución

Los límites de un UIView es el rectángulo , expresado como una ubicación (x, y) y tamaño (ancho, alto) en relación con su propio sistema de coordenadas (0,0).

El marco de un UIView es el rectángulo , expresado como una ubicación (x, y) y tamaño (ancho, alto) en relación con la supervista que contiene.

Entonces, imagine una vista que tenga un tamaño de 100x100 (ancho x alto) posicionada en 25,25 (x, y) de su supervista. El siguiente código imprime los límites y el marco de esta vista:

// This method is in the view controller of the superview
- (void)viewDidLoad {
    [super viewDidLoad];

    NSLog(@"bounds.origin.x: %f", label.bounds.origin.x);
    NSLog(@"bounds.origin.y: %f", label.bounds.origin.y);
    NSLog(@"bounds.size.width: %f", label.bounds.size.width);
    NSLog(@"bounds.size.height: %f", label.bounds.size.height);

    NSLog(@"frame.origin.x: %f", label.frame.origin.x);
    NSLog(@"frame.origin.y: %f", label.frame.origin.y);
    NSLog(@"frame.size.width: %f", label.frame.size.width);
    NSLog(@"frame.size.height: %f", label.frame.size.height);
}

Y la salida de este código es:

bounds.origin.x: 0
bounds.origin.y: 0
bounds.size.width: 100
bounds.size.height: 100

frame.origin.x: 25
frame.origin.y: 25
frame.size.width: 100
frame.size.height: 100

Entonces, podemos ver que en ambos casos, el ancho y el alto de la vista son los mismos, independientemente de si estamos mirando los límites o el marco. Lo que es diferente es el posicionamiento x, y de la vista. En el caso de los límites, las coordenadas xey están en 0,0 ya que estas coordenadas son relativas a la vista en sí. Sin embargo, las coordenadas X e Y del marco son relativas a la posición de la vista dentro de la vista principal (que anteriormente dijimos que estaba en 25,25).

También hay una gran presentación que cubre UIViews. Vea las diapositivas 1-20 que no solo explican la diferencia entre marcos y límites, sino que también muestran ejemplos visuales.

Otros consejos

Respuesta corta

marco = ubicación y tamaño de una vista utilizando el sistema de coordenadas de la vista principal

  • Importante para: colocar la vista en el padre

límites = ubicación y tamaño de una vista usando su propio sistema de coordenadas

  • Importante para: colocar el contenido o las subvistas de la vista dentro de sí mismo

Respuesta detallada

Para ayudarme a recordar el marco , pienso en un marco de imagen en una pared . El marco de la imagen es como el borde de una vista. Puedo colgar la foto en cualquier lugar que quiera en la pared. De la misma manera, puedo poner una vista en cualquier lugar que desee dentro de una vista principal (también llamada supervista). La vista principal es como el muro. El origen del sistema de coordenadas en iOS es la esquina superior izquierda. Podemos poner nuestra vista en el origen de la supervista configurando las coordenadas x-y del marco de vista en (0, 0), que es como colgar nuestra imagen en la esquina superior izquierda de la pared. Para moverlo hacia la derecha, aumente x, para moverlo hacia abajo aumente y.

Para ayudarme a recordar límites , pienso en una cancha de baloncesto donde a veces el baloncesto queda fuera de límites . Estás botando la pelota por toda la cancha de baloncesto, pero realmente no te importa dónde está la cancha. Podría ser en un gimnasio, o afuera en una escuela secundaria, o en frente de su casa. No importa. Solo quieres jugar baloncesto. Del mismo modo, el sistema de coordenadas para los límites de una vista solo se preocupa por la vista misma. No sabe nada acerca de dónde se encuentra la vista en la vista principal. El origen de los límites (punto (0, 0) por defecto) es la esquina superior izquierda de la vista. Cualquier subvista que tenga esta vista se presenta en relación con este punto. Es como llevar el baloncesto a la esquina delantera izquierda de la cancha.

Ahora la confusión surge cuando intentas comparar marcos y límites. Sin embargo, en realidad no es tan malo como parece al principio. Usemos algunas imágenes para ayudarnos a entender.

Marco vs Límites

En la primera imagen a la izquierda tenemos una vista que se encuentra en la parte superior izquierda de su vista principal. El rectángulo amarillo representa el marco de la vista. A la derecha vemos la vista nuevamente, pero esta vez no se muestra la vista principal. Esto se debe a que los límites no conocen la vista principal. 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.

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

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

ingrese la descripción de la imagen aquí

Entonces, el marco y los límites eran exactamente los mismos en esa imagen. Veamos un ejemplo en el que son diferentes.

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í

Para que pueda ver que al cambiar las coordenadas x-y del marco, se mueve en la vista principal. Pero el contenido de la vista en sí todavía se ve exactamente igual. Los límites no tienen idea de que algo es diferente.

Hasta ahora, el ancho y la altura del marco y los límites han sido exactamente los mismos. Sin embargo, eso no siempre es cierto. Mira lo que sucede si giramos la vista 20 grados en sentido horario. (La rotación se realiza mediante transformaciones. Consulte el documentación y estas ver y ejemplos de capa para obtener más información.

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í

Puedes ver que los límites siguen siendo los mismos. ¡Todavía no saben que ha sucedido nada! Sin embargo, los valores del marco han cambiado.

Ahora es un poco más fácil ver la diferencia entre marco y límites, ¿no? El artículo Probablemente no comprenda los marcos y límites define un marco de vista como

  

... el cuadro delimitador más pequeño de esa vista con respecto a sus padres   sistema de coordenadas, incluidas las transformaciones aplicadas a esa vista.

Es importante tener en cuenta que si transforma una vista, el marco queda indefinido. Entonces, en realidad, el marco amarillo que dibujé alrededor de los límites verdes rotados en la imagen de arriba nunca existe. Eso significa que si gira, escala o realiza alguna otra transformación, ya no debería usar los valores del marco. Sin embargo, aún puede usar los valores de límites. Los documentos de Apple advierten:

  

Importante: Si la propiedad transform de una vista no contiene la transformación de identidad, el marco de esa vista es indefinido y también lo son   resultados de sus comportamientos de autoresizing.

Más bien desafortunado con el autoresizing ... Sin embargo, hay algo que puede hacer.

El estado de los documentos de Apple:

  

Al modificar la propiedad transform de su vista, todos   las transformaciones se realizan en relación con el punto central de la   ver.

Entonces, si necesita mover una vista en el elemento primario después de que se haya realizado una transformación, puede hacerlo cambiando las coordenadas view.center . Al igual que frame , center usa el sistema de coordenadas de la vista principal.

Ok, eliminemos nuestra rotación y centrémonos en los límites. Hasta ahora, el origen de los límites siempre se ha mantenido en (0, 0). Sin embargo, no tiene que hacerlo. ¿Qué pasa si nuestra vista tiene una gran subvista que es demasiado grande para mostrarla de una vez? Lo haremos un UIImageView con una imagen grande. Aquí está nuestra segunda imagen desde arriba nuevamente, pero esta vez podemos ver cómo se vería todo el contenido de la subvista de nuestra 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í

Solo la esquina superior izquierda de la imagen puede caber dentro de los límites de la vista. Ahora mira lo que sucede si cambiamos las coordenadas de origen de los límites.

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

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

ingrese la descripción de la imagen aquí

El marco no se ha movido en la supervista, pero el contenido dentro del marco ha cambiado porque el origen del rectángulo de límites comienza en una parte diferente de la vista. Esta es toda la idea detrás de un UIScrollView y sus subclases (por ejemplo, un UITableView ). Consulte Comprensión de UIScrollView para obtener más explicaciones.

Cuándo usar marco y cuándo usar límites

Dado que frame relaciona la ubicación de una vista en su vista principal, la usa cuando realiza cambios externos , como cambiar su ancho o encontrar la distancia entre la vista y la parte superior de su vista principal.

Utilice los límites cuando realice cambios internos , como dibujar cosas u organizar subvistas dentro de la vista. También use los límites para obtener el tamaño de la vista si ha realizado alguna transformación en ella.

Artículos para futuras investigaciones:

Documentos de Apple

Preguntas relacionadas de StackOverflow

Otros recursos

Practícate

Además de leer los artículos anteriores, me ayuda mucho hacer una aplicación de prueba. Es posible que desee intentar hacer algo similar. (Se me ocurrió la idea de esto video curso pero desafortunadamente no es gratis.

ingrese la descripción de la imagen aquí

Aquí está el código para su referencia:

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var myView: UIView!

    // Labels
    @IBOutlet weak var frameX: UILabel!
    @IBOutlet weak var frameY: UILabel!
    @IBOutlet weak var frameWidth: UILabel!
    @IBOutlet weak var frameHeight: UILabel!
    @IBOutlet weak var boundsX: UILabel!
    @IBOutlet weak var boundsY: UILabel!
    @IBOutlet weak var boundsWidth: UILabel!
    @IBOutlet weak var boundsHeight: UILabel!
    @IBOutlet weak var centerX: UILabel!
    @IBOutlet weak var centerY: UILabel!
    @IBOutlet weak var rotation: UILabel!

    // Sliders
    @IBOutlet weak var frameXSlider: UISlider!
    @IBOutlet weak var frameYSlider: UISlider!
    @IBOutlet weak var frameWidthSlider: UISlider!
    @IBOutlet weak var frameHeightSlider: UISlider!
    @IBOutlet weak var boundsXSlider: UISlider!
    @IBOutlet weak var boundsYSlider: UISlider!
    @IBOutlet weak var boundsWidthSlider: UISlider!
    @IBOutlet weak var boundsHeightSlider: UISlider!
    @IBOutlet weak var centerXSlider: UISlider!
    @IBOutlet weak var centerYSlider: UISlider!
    @IBOutlet weak var rotationSlider: UISlider!

    // Slider actions
    @IBAction func frameXSliderChanged(sender: AnyObject) {
        myView.frame.origin.x = CGFloat(frameXSlider.value)
        updateLabels()
    }
    @IBAction func frameYSliderChanged(sender: AnyObject) {
        myView.frame.origin.y = CGFloat(frameYSlider.value)
        updateLabels()
    }
    @IBAction func frameWidthSliderChanged(sender: AnyObject) {
        myView.frame.size.width = CGFloat(frameWidthSlider.value)
        updateLabels()
    }
    @IBAction func frameHeightSliderChanged(sender: AnyObject) {
        myView.frame.size.height = CGFloat(frameHeightSlider.value)
        updateLabels()
    }
    @IBAction func boundsXSliderChanged(sender: AnyObject) {
        myView.bounds.origin.x = CGFloat(boundsXSlider.value)
        updateLabels()
    }
    @IBAction func boundsYSliderChanged(sender: AnyObject) {
        myView.bounds.origin.y = CGFloat(boundsYSlider.value)
        updateLabels()
    }
    @IBAction func boundsWidthSliderChanged(sender: AnyObject) {
        myView.bounds.size.width = CGFloat(boundsWidthSlider.value)
        updateLabels()
    }
    @IBAction func boundsHeightSliderChanged(sender: AnyObject) {
        myView.bounds.size.height = CGFloat(boundsHeightSlider.value)
        updateLabels()
    }
    @IBAction func centerXSliderChanged(sender: AnyObject) {
        myView.center.x = CGFloat(centerXSlider.value)
        updateLabels()
    }
    @IBAction func centerYSliderChanged(sender: AnyObject) {
        myView.center.y = CGFloat(centerYSlider.value)
        updateLabels()
    }
    @IBAction func rotationSliderChanged(sender: AnyObject) {
        let rotation = CGAffineTransform(rotationAngle: CGFloat(rotationSlider.value))
        myView.transform = rotation
        updateLabels()
    }

    private func updateLabels() {

        frameX.text = "frame x = \(Int(myView.frame.origin.x))"
        frameY.text = "frame y = \(Int(myView.frame.origin.y))"
        frameWidth.text = "frame width = \(Int(myView.frame.width))"
        frameHeight.text = "frame height = \(Int(myView.frame.height))"
        boundsX.text = "bounds x = \(Int(myView.bounds.origin.x))"
        boundsY.text = "bounds y = \(Int(myView.bounds.origin.y))"
        boundsWidth.text = "bounds width = \(Int(myView.bounds.width))"
        boundsHeight.text = "bounds height = \(Int(myView.bounds.height))"
        centerX.text = "center x = \(Int(myView.center.x))"
        centerY.text = "center y = \(Int(myView.center.y))"
        rotation.text = "rotation = \((rotationSlider.value))"

    }

}

intenta ejecutar el siguiente código

- (void)viewDidLoad {
    [super viewDidLoad];
    UIWindow *w = [[UIApplication sharedApplication] keyWindow];
    UIView *v = [w.subviews objectAtIndex:0];

    NSLog(@"%@", NSStringFromCGRect(v.frame));
    NSLog(@"%@", NSStringFromCGRect(v.bounds));
}

la salida de este código es:

la orientación del dispositivo de la carcasa es Vertical

{{0, 0}, {768, 1024}}
{{0, 0}, {768, 1024}}

la orientación del dispositivo de la carcasa es Horizontal

{{0, 0}, {768, 1024}}
{{0, 0}, {1024, 768}}

obviamente, puede ver la diferencia entre marco y límites

El marco es el rectángulo que define la UIView con respeto a su supervista .

Los límites rect son el rango de valores que definen ese sistema de coordenadas de NSView.

es decir cualquier cosa en este rectángulo se mostrará en la vista UIView.

frame es el origen (esquina superior izquierda) y el tamaño de la vista en el sistema de coordenadas de su super vista, esto significa que traduce la vista en su super vista cambiando el origen del marco, límites por otro lado es el tamaño y el origen en su propio sistema de coordenadas, por lo que, de forma predeterminada, el origen de los límites es (0,0).

la mayoría de las veces el marco y los límites son congruentes, pero si tiene una vista del marco ((140,65), (200,250)) y los límites ((0,0), (200,250)) por ejemplo y la vista se inclinó para que quede en su esquina inferior derecha, entonces los límites seguirán siendo ((0,0), (200,250)), pero el marco no lo está.

ingrese la descripción de la imagen aquí

el marco será el rectángulo más pequeño que encapsula / rodea la vista, por lo que el marco (como en la foto) será ((140,65), (320,320)).

otra diferencia es, por ejemplo, si tiene un superView cuyos límites son ((0,0), (200,200)) y este superView tiene un subView cuyo marco es ((20,20), (100,100)) y cambió el superView se limita a ((20,20), (200,200)), entonces el marco subView seguirá siendo ((20,20), (100,100)) pero compensado por (20,20) porque su sistema de coordenadas de supervista fue desplazado por (20,20).

Espero que esto ayude a alguien.

Enmarca su relativo a su SuperView mientras que los límites relativos a su NSView.

Ejemplo: X = 40, Y = 60. También contiene 3 vistas. Este diagrama muestra una idea clara.

MARCO

BOUNDS

Las respuestas anteriores han explicado muy bien la diferencia entre Bounds y Frames.

  

Límites: una vista Tamaño y ubicación según su propio sistema de coordenadas.

     

Marco: un tamaño de vista y ubicación relativa a su SuperView.

Entonces existe la confusión de que en el caso de Bounds the X, Y siempre será "0". Esto no es cierto . Esto también se puede entender en UIScrollView y UICollectionView.

Cuando los límites 'x, y no son 0.
Supongamos que tenemos un UIScrollView. Hemos implementado la paginación. El UIScrollView tiene 3 páginas y el ancho de su ContentSize es tres veces el ancho de la pantalla (suponga que ScreenWidth es 320). La altura es constante (suponga 200).

scrollView.contentSize = CGSize(x:320*3, y : 200)

Agregue tres UIImageViews como subViews y observe de cerca el valor x del marco

let imageView0 = UIImageView.init(frame: CGRect(x:0, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView1 :  UIImageView.init( frame: CGRect(x:320, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView2 :  UIImageView.init(frame: CGRect(x:640, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
  1. Página 0: Cuando el ScrollView está en la página 0, los límites serán (x: 0, y: 0, ancho: 320, altura: 200)

  2. Página 1: Desplácese y muévase a la página 1.
    Ahora los límites serán (x: 320, y: 0, ancho: 320, altura: 200) Recuerde que dijimos con respecto a su propio sistema de coordenadas. Así que ahora la "Parte visible" de nuestro ScrollView tiene su " x " en 320. Mire el marco de imageView1.

  3. Página 2: Desplázate y ve a la página 2 Límites: (x: 640, y: 0, ancho: 320, altura: 200) Nuevamente eche un vistazo al marco de imageView2

Lo mismo para el caso de UICollectionView. La forma más fácil de ver collectionView es desplazándolo e imprimiendo / registrando sus límites y obtendrá la idea.

Todas las respuestas anteriores son correctas y esta es mi opinión sobre esto:

Para diferenciar entre el marco y los límites, el desarrollador de CONCEPTOS debería leer:

  
      
  1. en relación con la supervista (una vista principal) está contenida dentro de = MARCO
  2.   
  3. en relación con su propio sistema de coordenadas, determina su ubicación de subvista = BOUNDS
  4.   

" límites " es confuso porque da la impresión de que las coordenadas son la posición de la vista para la que está configurada. Pero estos están en relaciones y ajustados de acuerdo con las constantes de trama.

 pantalla del iPhone

frame = ubicación y tamaño de una vista usando el sistema de coordenadas de la vista padre

limits = ubicación y tamaño de una vista usando su propio sistema de coordenadas

Una vista rastrea su tamaño y ubicación usando dos rectángulos: un rectángulo de marco y un rectángulo de límites. El rectángulo del marco define la ubicación y el tamaño de la vista en la supervista utilizando el sistema de coordenadas de la supervista. El rectángulo de límites define el sistema de coordenadas interiores que se utiliza al dibujar el contenido de la vista, incluido el origen y la escala. La Figura 2-1 muestra la relación entre el rectángulo del marco, a la izquierda, y el rectángulo de límites, a la derecha. & # 8221;

En resumen, el marco es la idea de una vista de la supervista, y los límites son la idea de la vista. Tener múltiples sistemas de coordenadas, uno para cada vista, es parte de la jerarquía de vistas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top