Question

UIView et ses sous-classes ont toutes les propriétés frame et bounds . Quelle est la différence?

Était-ce utile?

La solution

Les bornes d'un UIView est le rectangle , exprimé en emplacement (x, y) et en taille (largeur, hauteur) par rapport à son propre système de coordonnées (0,0).

Le cadre d'un UIView est le rectangle , exprimé sous la forme d'un emplacement (x, y) et d'une taille (largeur, hauteur) par rapport à la vue d'ensemble dans laquelle il est contenu.

Alors, imaginez une vue ayant une taille de 100x100 (largeur x hauteur) positionnée à 25,25 (x, y) de son aperçu. Le code suivant imprime les limites et le cadre de cette vue:

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

Et la sortie de ce code est:

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

Ainsi, nous pouvons constater que dans les deux cas, la largeur et la hauteur de la vue sont les mêmes, que nous examinions les limites ou le cadre. Ce qui est différent, c’est le positionnement x, y de la vue. Dans le cas des limites, les coordonnées x et y sont à 0,0 car ces coordonnées sont relatives à la vue elle-même. Cependant, les coordonnées x et y du cadre sont relatives à la position de la vue dans la vue parente (ce que nous avions dit précédemment était 25,25).

Il existe également une présentation géniale qui couvre UIViews. Voir les diapositives 1 à 20 qui expliquent non seulement la différence entre les cadres et les limites, mais également des exemples visuels.

Autres conseils

Réponse courte

cadre = l'emplacement et la taille d'une vue à l'aide du système de coordonnées de la vue parent

  • Important pour: placer la vue dans le parent

bornes = l'emplacement et la taille d'une vue à l'aide de son propre système de coordonnées

  • Important pour: placer le contenu ou les sous-vues de la vue en lui-même

Réponse détaillée

Pour m'aider à mémoriser cadre , je pense à un cadre photo sur un mur . Le cadre photo ressemble à la bordure d'une vue. Je peux accrocher la photo n'importe où sur le mur. De la même manière, je peux placer une vue n'importe où dans une vue parent (également appelée superview). La vue parent est comme le mur. L'origine du système de coordonnées dans iOS est en haut à gauche. Nous pouvons placer notre vue à l'origine de la vue d'ensemble en définissant les coordonnées x-y du cadre de vue sur (0, 0), ce qui revient à suspendre notre image dans le coin tout à fait à gauche du mur. Pour le déplacer vers la droite, augmentez x, pour le diminuer, augmentez y.

Pour m'aider à me souvenir des limites , je pense à un terrain de basket où parfois le basket-ball est mis hors de portée . Vous dribblez la balle sur tout le terrain de basket, mais vous ne vous souciez pas vraiment de savoir où se trouve le terrain. Cela peut se faire dans un gymnase, à l’extérieur dans un lycée ou devant votre maison. Ça n'a pas d'importance. Vous voulez juste jouer au basket. De la même manière, le système de coordonnées pour les limites d'une vue ne concerne que la vue elle-même. Il ne sait rien de l'emplacement de la vue dans la vue parent. L'origine des limites (le point (0, 0) par défaut) correspond au coin supérieur gauche de la vue. Toutes les sous-vues associées à cette vue sont présentées par rapport à ce point. C'est comme si on emmenait le ballon de basket dans le coin avant gauche du terrain.

Maintenant, la confusion survient lorsque vous essayez de comparer le cadre et les limites. En réalité, ce n'est pas aussi grave qu'il y paraît au début. Utilisons quelques images pour nous aider à comprendre.

Cadre vs limites

Dans la première image à gauche, nous avons une vue située en haut à gauche de la vue parent. Le rectangle jaune représente le cadre de la vue. À droite, nous voyons à nouveau la vue, mais cette fois, la vue parent n'est pas affichée. C'est parce que les limites ne connaissent pas la vue parent. Le rectangle vert représente les limites de la vue. Le point rouge des deux images représente la origine du cadre ou des limites.

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

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

entrer la description de l'image ici

Le cadre et les limites étaient donc exactement les mêmes dans cette image. Regardons un exemple où ils sont différents.

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

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

entrer la description de l'image ici

Ainsi, vous pouvez constater que le fait de changer les coordonnées x-y du cadre le déplace dans la vue parent. Mais le contenu de la vue elle-même est toujours identique. Les limites n'ont aucune idée que quelque chose est différent.

Jusqu'à présent, la largeur et la hauteur du cadre et des limites étaient exactement les mêmes. Ce n'est pas toujours vrai, cependant. Regardez ce qui se passe si nous faisons pivoter la vue de 20 degrés dans le sens des aiguilles d'une montre. (La rotation est effectuée à l'aide de transformations. Consultez la documentation et ces afficher et exemples de couches pour plus d'informations.)

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

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

entrer la description de l'image ici

Vous pouvez voir que les limites sont toujours les mêmes. Ils ne savent toujours pas que rien ne s'est passé! Les valeurs du cadre ont toutes changé, cependant.

Maintenant, il est un peu plus facile de voir la différence entre frame et bounds, n'est-ce pas? L'article Vous ne comprenez probablement pas les cadres et les limites définit un cadre de vue comme

  

... la plus petite boîte englobante de ce point de vue par rapport à ses parents   Système de coordonnées, y compris les transformations appliquées à cette vue.

Il est important de noter que si vous transformez une vue, le cadre devient indéfini. Donc, en fait, le cadre jaune que j'ai dessiné autour des limites vertes pivotées dans l'image ci-dessus n'existe jamais. Cela signifie que si vous faites pivoter, redimensionnez ou effectuez une autre transformation, vous ne devriez plus utiliser les valeurs d'image. Vous pouvez toujours utiliser les valeurs des limites, cependant. Les documents Apple avertissent:

  

Important: Si la propriété Transformation de la vue ne contient pas la transformation d'identité, le cadre de cette vue n'est pas défini.   résultats de ses comportements autoresizing.

Plutôt malheureux à propos de la réduction automatique de la tension .... Vous pouvez toutefois faire quelque chose.

État des documents Apple:

  

Lors de la modification de la propriété transformation de votre vue, tous   les transformations sont effectuées par rapport au centre de la   vue.

Ainsi, si vous avez besoin de déplacer une vue dans le parent après une transformation, vous pouvez le faire en modifiant les coordonnées view.center . Comme image , centre utilise le système de coordonnées de la vue parent.

Ok, supprimons notre rotation et concentrons-nous sur les limites. Jusqu'à présent, l'origine des limites est toujours restée à (0, 0). Ce n'est pas nécessaire, cependant. Que se passe-t-il si notre vue a une grande sous-vue qui est trop grande pour tout afficher en même temps? Nous allons en faire un UIImageView avec une grande image. Voici notre deuxième photo d'en haut, mais cette fois, nous pouvons voir à quoi ressemblerait le contenu de la sous-vue de notre vue.

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

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

entrer la description de l'image ici

Seul le coin supérieur gauche de l'image peut s'insérer dans les limites de la vue. Maintenant, regardez ce qui se passe si nous changeons les coordonnées d'origine des bornes.

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

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

entrer la description de l'image ici

Le cadre n'a pas bougé dans la vue d'ensemble, mais son contenu a été modifié car l'origine du rectangle de délimitation commence à une autre partie de la vue. C'est l'idée même derrière UIScrollView et ses sous-classes (par exemple, un UITableView ). Voir Présentation de UIScrollView pour plus d'explications.

Quand utiliser un cadre et quand utiliser des limites

Etant donné que cadre associe la position d'une vue à sa vue parente, vous l'utilisez pour effectuer des modifications externes , comme pour modifier sa largeur ou pour déterminer la distance en haut de sa vue parente.

Utilisez les bornes pour effectuer des modifications internes , par exemple pour dessiner ou organiser des sous-vues dans la vue. Utilisez également les limites pour obtenir la taille de la vue si vous avez effectué une transformation.

Articles pour des recherches ultérieures:

Documents Apple

Questions connexes sur StackOverflow

Autres ressources

Entraînez-vous

En plus de lire les articles ci-dessus, cela m’aide beaucoup de faire une application test. Vous voudrez peut-être essayer de faire quelque chose de similaire. (J'ai eu l'idée de cette cours vidéo mais malheureusement ce n’est pas gratuit.)

entrer la description de l'image ici

Voici le code pour votre référence:

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

    }

}

essayez d'exécuter le code ci-dessous

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

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

la sortie de ce code est:

l’orientation du périphérique est Portrait

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

l’orientation de l’appareil dans l’affaire est Paysage

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

évidemment, vous pouvez voir la différence entre frame et bounds

Le cadre est le rectangle qui définit UIView avec le respect de sa vue d'ensemble .

Le borns rect correspond à la plage de valeurs définissant le système de coordonnées de ce système de NSView.

i.e. quoi que ce soit dans ce rectangle sera réellement affiché dans UIView.

cadre est l'origine (coin supérieur gauche) et la taille de la vue dans le système de coordonnées de sa super vue, ce qui signifie que vous traduisez la vue dans sa super vue en modifiant l'origine du cadre, bounds , quant à lui, est la taille et l'origine dans son propre système de coordonnées. Par conséquent, l'origine des limites est (0,0).

la plupart du temps, le cadre et les limites sont congruents, mais si vous avez une vue du cadre ((140,65), (200,250)) et des bornes ((0,0), (200,250)), par exemple, et le La vue a été inclinée de manière à ce qu'elle se trouve dans son coin inférieur droit. Les limites seront toujours ((0,0), (200,250)), mais le cadre ne l'est pas.

entrer la description de l'image ici

le cadre sera le plus petit rectangle qui encapsule / entoure la vue, ainsi le cadre (comme sur la photo) sera ((140,65), (320 320)).

une autre différence est par exemple si vous avez une superView dont les bornes sont ((0,0), (200,200)) et que cette superView a une sous-vue dont le cadre est ((20,20), (100,100)) et que vous avez modifié. la superView est liée à ((20,20), (200,200)), puis le cadre de sous-vue sera immobile ((20,20), (100,100)) mais décalé de (20,20) car son système de coordonnées supérieur est décalé de (20,20).

J'espère que cela aide quelqu'un.

Définissez son rapport par rapport à son SuperView, alors que Limites par rapport à son NSView.

Exemple: X = 40, Y = 60.Comprend également 3 vues.Ce diagramme montre une idée claire.

FRAME

BOUNDS

Les réponses ci-dessus ont très bien expliqué la différence entre Bounds et Frames.

  

Limites: une taille et un emplacement de vue selon son propre système de coordonnées.

     

Cadre: taille et emplacement de la vue par rapport à son SuperView.

Ensuite, il y a une confusion qui fait que dans le cas de Bounds le X, Y sera toujours "0". Ce n'est pas vrai . Ceci peut également être compris dans UIScrollView et UICollectionView.

Lorsque les bornes 'x, y ne sont pas égales à 0.
Supposons que nous avons un UIScrollView. Nous avons mis en place la pagination. UIScrollView a 3 pages et la largeur de ContentSize est trois fois la largeur de l'écran (supposons que la largeur de l'écran est de 320). La hauteur est constante (supposons 200).

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

Ajoutez trois UIImageViews en tant que sous-vues et observez de près la valeur x du cadre

.
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. Page 0: Quand le ScrollView est à 0 page les limites seront (x: 0, y: 0, largeur: 320, hauteur: 200)

  2. Page 1: Faites défiler et aller à la page 1.
    Les limites seront désormais (x: 320, y: 0, largeur: 320, hauteur: 200) N'oubliez pas que nous avons dit à propos de son propre système de coordonnées. Alors maintenant, la " Partie visible " de notre ScrollView a son " x " en 320. Regardez le cadre de imageView1.

  3. Page 2: Faites défiler et aller à la page 2 Limites: (x: 640, y: 0, largeur: 320, hauteur: 200) Encore une fois, jetez un oeil à l'image de imageView2

Idem pour le cas de UICollectionView. Le moyen le plus simple de consulter collectionView consiste à le faire défiler, à imprimer / consigner ses limites et vous aurez l’idée.

Toutes les réponses ci-dessus sont correctes et voici mon point de vue:

Pour différencier les cadres et les limites, le développeur CONCEPTS doit lire:

  
      
  1. par rapport à la vue principale (une vue parent), il est contenu dans = FRAME
  2.   
  3. par rapport à son propre système de coordonnées, détermine son emplacement de sous-vue = BOUNDS
  4.   

" bounds " est déroutant car cela donne l’impression que les coordonnées sont la position de la vue pour laquelle elle est définie. Mais ceux-ci sont en relations et ajustés en fonction des constantes de la trame.

 écran iPhone

frame = l'emplacement et la taille d'une vue à l'aide du système de coordonnées de la vue parent

bounds = l'emplacement et la taille d'une vue à l'aide de son propre système de coordonnées

Une vue suit sa taille et son emplacement à l'aide de deux rectangles: un rectangle à cadre et un rectangle à limites. Le rectangle du cadre définit l'emplacement et la taille de la vue dans la vue d'ensemble à l'aide de son système de coordonnées. Le rectangle de délimitation définit le système de coordonnées intérieur utilisé pour dessiner le contenu de la vue, y compris l'origine et la mise à l'échelle. La figure 2-1 illustre la relation entre le rectangle du cadre, à gauche, et le rectangle des limites, à droite. "

En bref, le cadre est l’idée de vue de Superview, et les limites sont sa propre idée. Avoir plusieurs systèmes de coordonnées, un pour chaque vue, fait partie de la hiérarchie des vues.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top