Cacao: Quelle est la différence entre le cadre et les limites?

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

505
demandé sur mk12 2009-07-31 04:07:04
la source

7 ответов

le limite D'un uivi est le rectangle , exprimé en position (x,y) et taille (largeur,hauteur) par rapport à son propre système de coordonnées (0,0).

la frame d'un uivi est le" rectangle , exprimé comme un emplacement (x,y) et la taille (largeur,hauteur) relative à la superview qu'il contient.

ainsi, imaginez une vue qui a une taille de 100x100 (Largeur x hauteur) positionnée à 25,25 (x,y) de sa superview. Le code suivant imprime les limites et la trame 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 voir que dans les deux cas, la largeur et la hauteur de la vue est la même indépendamment de si nous regardons les limites ou le cadre. Ce qui est différent,c'est le positionnement x, y de la vue. Dans le cas des bornes, 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 mère (qui était auparavant à 25,25).

Il ya aussi un grande présentation qui couvre UIViews. Voir les diapositives 1-20 qui expliquent non seulement la différence entre les cadres et les bornes, mais montrent aussi des exemples visuels.

811
répondu shek 2012-05-28 23:36:47
la source

Réponse Courte

frame = emplacement et taille d'une vue utilisant le système de coordonnées de la vue mère

  • Important pour: placer la vue dans le parent

bornes = emplacement et taille d'une vue utilisant 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 à me souvenir cadre , je pense à un cadre d'image sur un mur . Le cadre est comme le bord d'une vue. Je peux accrocher la photo où je veux sur le mur. De la même manière, je peux placer une vue où je veux dans une vue parente (aussi appelée une superview). Le la vue des parents 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 superview en mettant les coordonnées x-y du cadre de vue à (0, 0), ce qui est comme accrocher notre image dans le coin supérieur gauche du mur. Pour le déplacer à droite, augmentez x, pour le déplacer vers le bas augmentez Y.

pour m'aider à me souvenir limites , je pense à un terrain de basket-ball où parfois le basket-ball est frappé en dehors des limites . Vous dribblez la balle partout sur le terrain de basket, mais vous ne vous souciez pas vraiment où le terrain lui-même est. Ça peut être dans un gymnase, ou dehors dans un lycée, ou devant votre maison. Il 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 se soucie que de la vue elle-même. Il ne sait rien de l'emplacement de la vue dans la vue mère. Les limites" origine (point (0, 0) par défaut) est le coin supérieur gauche de la vue. Tous les points de vue exprimés dans cette optique sont exposés en relation avec ce point de vue. C'est comme prendre le ballon au coin avant gauche du terrain.

maintenant la confusion vient quand vous essayez de comparer le cadre et les limites. En fait, ce n'est pas aussi mauvais que ça en a l'air au début. Utilisons quelques photos pour nous aider à comprendre.

Frame vs Bounds

dans le premier photo sur la gauche nous avons une vue qui est situé en haut à gauche de sa vue de parent. le rectangle jaune représente le cadre de la vue. sur la droite nous voyons à nouveau la vue mais cette fois la vue de parent n'est pas montrée. C'est parce que les limites ne connaissent pas le point de vue des parents. le rectangle vert représente les limites de la vue. le point rouge dans les deux images représente le origine de la cadre ou limites.

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

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

enter image description here

ainsi le cadre et les limites étaient 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

enter image description here

donc vous pouvez voir que changer les coordonnées x-y du cadre le déplace dans la vue parent. Mais le contenu de la vue elle-même semble toujours exactement la même. Le 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 bornes ont été exactement les mêmes. Ce n'est pas toujours vrai, cependant. Regardez ce qui se passe si on tourne la vue de 20 degrés dans le sens des aiguilles d'une montre. (La Rotation se fait en utilisant des transformes. Voir la "documentation 1519840920" et ces view 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

enter image description here

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

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

...le plus petit boîte englobante de ce point de vue à l'égard de ses parents système de coordonnées, y compris toute transformation appliquée à cette vue.

Il est important de noter que si vous transformez vue, le cadre devient indéfini. Donc en fait, le cadre jaune que j'ai dessiné autour des bornes vertes dans l'image ci-dessus n'existe jamais. Cela signifie que si vous faites une rotation, une échelle ou une autre transformation, alors vous ne devriez plus utiliser les valeurs du cadre. Vous pouvez utilisez toujours les valeurs limites. Les Docs Apple mettent en garde:

Important: résultats de ses comportements d'autorégression.

plutôt malchanceux à propos de l'auto-chavirement.... Mais il y a quelque chose que tu peux faire.

La Pomme les docs de l'état:

lors de la modification de la propriété transform de votre vue, tous les transformations sont effectuées par rapport au point central du vue.

donc si vous avez besoin de déplacer une vue dans le parent après une transformation, vous pouvez le faire en changeant les coordonnées view.center . Comme frame , center utilise le système de coordonnées de la vue mère.

OK, débarrassons-nous de notre rotation et concentrons-nous sur les limites. Jusqu'à présent l'origine des bornes est toujours restée à (0, 0). Il n'est pas nécessaire, cependant. Que se passe-t-il si notre vue a une grande sous-vue qui est trop grande pour être affichée en une seule fois? Nous en ferons un UIImageView avec une grande image. Voici notre deuxième image d'en haut à nouveau, mais cette fois nous pouvons voir à quoi ressemblerait tout le contenu de notre vue subview.

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

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

enter image description here

seul le coin supérieur gauche de l'image peut entrer dans les limites de la vue. Regardez ce qui se passe si on change les coordonnées d'origine des bornes.

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

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

enter image description here

le cadre n'a pas bougé dans la superview mais le contenu à l'intérieur du cadre a changé parce que l'origine du rectangle des bornes commence à une partie différente de la vue. C'est l'idée derrière une UIScrollView et c'est les sous-classes (par exemple, un UITableView ). Voir comprendre UIScrollView pour plus d'explications.

quand utiliser frame et quand utiliser bounds

depuis frame indique l'emplacement d'une vue dans sa vue mère, vous l'utilisez lorsque vous faites change vers l'extérieur , comme changer sa largeur ou trouver la distance entre la vue et le haut de sa vue mère.

Use le bounds quand vous faites change vers l'intérieur , comme dessiner des choses ou arranger des sous-vues dans la vue. Également utiliser le terrain pour obtenir la taille de la vue si vous avez fait quelques transfomation.

des Articles pour la recherche:

Apple docs

Related StackOverflow questions

autres ressources

exercez - vous

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

enter image description here

voici le code de 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))"

    }

}
512
répondu Suragch 2017-11-10 08:12:34
la source

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:

case l'orientation du dispositif est Portrait

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

cas de l'appareil orientation Paysage

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

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

43
répondu tristan 2013-01-04 05:44:21
la source

le frame est le rectangle qui définit L'uivi avec par rapport à son superview .

le limite rect est l'intervalle de valeurs qui définit le système de coordonnées de NSView.

c'est-à-dire que tout ce qui se trouve dans ce rectangle s'affichera effectivement dans L'uivi.

13
répondu jorik 2015-01-07 21:21:19
la source

frame est l'origine (coin supérieur gauche) et la taille de la vue dans le système de coordonnées de sa vue super , cela signifie que vous traduisez la vue dans sa vue super en changeant l'origine du cadre, limites d'autre part est la taille et l'origine dans son propre système de coordonnées , donc par défaut l'origine des limites est (0,0).

la plupart du temps, le cadre et les limites sont congruents , mais si vous avez un affichage de l'image ((140,65), (200,250)) et des bornes ((0,0), (200,250)) par exemple et la vue a été inclinée de sorte qu'elle se tient sur son coin inférieur droit , alors les bornes seront encore ((0,0),(200,250)) , mais le cadre ne l'est pas .

enter image description here

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

une autre différence est, par exemple, si vous avoir une superView dont les limites sont (0,0), (200,200)) et cette superView a une sous-vue dont le cadre est ((20,20), (100,100) et vous avez changé les limites de superView en ((20,20),(200,200)) , alors le cadre de subView sera toujours ((20,20), (100,100)) mais décalé de (20,20) parce que son système de coordonnées superview a été décalé de (20,20).

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

9
répondu m.eldehairy 2016-05-06 22:13:14
la source

encadre son relatif à son SuperView alors que les limites relatives à son NSView.

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

FRAME

BOUNDS

2
répondu RAGHUNATH 2016-10-30 04:02:13
la source

les réponses ci-dessus ont très bien expliqué la différence entre les limites et les cadres.

limites : une taille de vue et L'emplacement selon son propre système de coordonnées.

Frame: une taille de vue et L'emplacement par rapport à sa SuperView.

alors il y a confusion que dans le cas de limites le X,Y sera toujours "0". ce qui n'est pas vrai . Cela peut être compris dans UIScrollView et UICollectionView aussi.

Lorsque les limites " x, y ne sont pas 0.

Supposons que nous avons une vue D'UIScrollView. Nous avons mis en place la pagination. L'UIScrollView a 3 pages et la largeur de son Conteneursize est trois fois la largeur de L'écran(supposons que la largeur de L'écran est de 320). La hauteur est constante(200).

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

ajouter trois UIImageViews comme subViews et garder un oeil attentif sur le x valeur de la trame

        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 bornes seront (x: 0,y: 0, Largeur: 320, hauteur : 200)

  2. Page 1 : Faites défiler et passez à la Page 1.

    Maintenant, les limites seront (x:320,y:0, largeur : 320, hauteur : 200) Rappelez-vous que nous avons dit en ce qui concerne son propre système de coordination. Si maintenant ,la" partie Visible "de notre ScrollView a son" x " à 320. Regardez le cadre d'imageView1.

  3. Page 2 : Défiler et passer à la Page 2 bornes: (x:640,y : 0, Largeur : 320, hauteur: 200) Encore une fois jeter un coup d'oeil à l'image de imageView2

idem pour UICollectionView. La façon la plus facile de regarder collectionView est de le faire défiler et d'imprimer/enregistrer ses limites et vous obtiendrez l'idée.

0
répondu Muhammad Nayab 2018-09-12 09:16:48
la source

Autres questions sur