UIView-Rahmen, Grenzen und Mitte

320

Ich würde gerne wissen, wie man diese Eigenschaften richtig einsetzt.

Soweit ich weiß, framekann aus dem Container der Ansicht verwendet werden, die ich erstelle. Hiermit wird die Ansichtsposition relativ zur Containeransicht festgelegt. Außerdem wird die Größe dieser Ansicht festgelegt.

Auch centerkann aus dem Behälter der Ansicht verwendet werden , ich bin zu schaffen. Diese Eigenschaft ändert die Position der Ansicht relativ zu ihrem Container.

Schließlich boundsist relativ zur Ansicht selbst. Es ändert den Zeichenbereich für die Ansicht.

Können Sie weitere Informationen über die Beziehung zwischen frameund geben bounds? Was ist mit den clipsToBoundsund masksToBoundsEigenschaften?

Lorenzo B.
quelle

Antworten:

577

Da die von mir gestellte Frage schon oft gesehen wurde, werde ich eine detaillierte Antwort darauf geben. Sie können es jederzeit ändern, wenn Sie korrekteren Inhalt hinzufügen möchten.

Zunächst eine Zusammenfassung der Frage: Rahmen, Grenzen und Zentrum und ihre Beziehungen.

Rahmen Die Ansicht frame( CGRect) einer Ansicht ist die Position ihres Rechtecks ​​im superviewKoordinatensystem des Ansichts . Standardmäßig beginnt es oben links.

Grenzen Eine Ansicht bounds( CGRect) drückt ein Ansichtsrechteck in einem eigenen Koordinatensystem aus.

Mittelpunkt A centerwird CGPointin Form des superviewKoordinatensystems ausgedrückt und bestimmt die Position des exakten Mittelpunkts der Ansicht.

Aus UIView + -Position entnommen sind dies die Beziehungen (sie funktionieren nicht im Code, da es sich um informelle Gleichungen handelt) zwischen den vorherigen Eigenschaften:

  • frame.origin = center - (bounds.size / 2.0)

  • center = frame.origin + (bounds.size / 2.0)

  • frame.size = bounds.size

HINWEIS: Diese Beziehungen gelten nicht, wenn Ansichten gedreht werden. Für weitere Informationen schlage ich vor, dass Sie sich das folgende Bild aus The Kitchen Drawer ansehen, das auf dem Stanford CS193p- Kurs basiert . Credits gehen an @Rhubarb .

Rahmen, Grenzen und Mitte

Mit der frameOption können Sie eine Ansicht innerhalb der Ansicht neu positionieren und / oder deren Größe ändern superview. Kann normalerweise von a verwendet werden superview, wenn Sie beispielsweise eine bestimmte Unteransicht erstellen. Zum Beispiel:

// 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];

Wenn Sie die Koordinaten zum Zeichnen in einem benötigen, viewbeziehen Sie sich normalerweise auf bounds. Ein typisches Beispiel könnte sein, in vieweiner Unteransicht als Einschub der ersten zu zeichnen . Das Zeichnen der Unteransicht erfordert die Kenntnis boundsder Übersicht. Zum Beispiel:

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];

Unterschiedliche Verhaltensweisen treten auf, wenn Sie die boundsAnsicht ändern . Wenn Sie beispielsweise das ändern bounds size, ändern sich die frameÄnderungen (und umgekehrt). Die Änderung erfolgt um centerdie Ansicht herum . Verwenden Sie den folgenden Code und sehen Sie, was passiert:

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

Wenn Sie sich ändern, ändern bounds originSie außerdem das origininterne Koordinatensystem. Standardmäßig originist das bei (0.0, 0.0)(obere linke Ecke). Wenn Sie beispielsweise das originfür ändern view1, können Sie sehen (kommentieren Sie den vorherigen Code, wenn Sie möchten), dass jetzt die obere linke Ecke für view2den view1einen berührt . Die Motivation ist ganz einfach. Sie sagen, view1dass sich die obere linke Ecke jetzt an der Position befindet, (20.0, 20.0)aber da view2die von frame originbeginnt (20.0, 20.0), werden sie zusammenfallen.

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

Das originrepräsentiert die viewPosition des 's innerhalb seiner superview, beschreibt aber die Position des boundsZentrums.

Schließlich boundsund originsind keine verwandten Konzepte. Beide erlauben es, das frameeiner Ansicht abzuleiten (siehe vorherige Gleichungen).

Die Fallstudie von View1

Folgendes passiert, wenn das folgende Snippet verwendet wird.

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]));

Das relative Bild.

Geben Sie hier die Bildbeschreibung ein

Dies passiert stattdessen, wenn ich die [self view]Grenzen wie folgt ändere .

// previous code here...
CGRect rect = [[self view] bounds];
rect.origin.x += 30.0f;
rect.origin.y += 20.0f;
[[self view] setBounds:rect];

Das relative Bild.

Geben Sie hier die Bildbeschreibung ein

Hier sagst du, [self view]dass sich seine obere linke Ecke jetzt an der Position (30.0, 20.0) befindet, aber da view1der Frame-Ursprung von (30.0, 20.0) beginnt, fallen sie zusammen.

Zusätzliche Referenzen (zum Aktualisieren mit anderen Referenzen, wenn Sie möchten)

Über clipsToBounds(Quelle Apple Doc)

Wenn Sie diesen Wert auf YES setzen, werden Unteransichten an die Grenzen des Empfängers gekürzt. Bei der Einstellung NO werden Unteransichten, deren Frames über die sichtbaren Grenzen des Empfängers hinausragen, nicht abgeschnitten. Der Standardwert ist NO.

Mit anderen Worten, wenn eine Ansicht frameist (0, 0, 100, 100)und ihre Unteransicht ist (90, 90, 30, 30), sehen Sie nur einen Teil dieser Unteransicht. Letzteres überschreitet nicht die Grenzen der übergeordneten Ansicht.

masksToBoundsist äquivalent zu clipsToBounds. Anstelle von a UIViewwird diese Eigenschaft auf a angewendet CALayer. Unter der Haube clipsToBoundsruft masksToBounds. Weitere Referenzen finden Sie unter Wie ist die Beziehung zwischen den ClipsToBounds von UIView und den MaskenToBounds von CALayer? .

Lorenzo Boaro
quelle
@Rhubarb Du hast vollkommen recht. Ich werde in meiner Antwort darauf hinweisen. Vielen Dank.
Lorenzo B
Ich weiß nicht, ob ich eine Antwort bekomme, aber warum bewegt sich die Unteransicht in die negative Richtung, wenn die Grenzen geändert werden. Ich kann mich einfach nicht darum kümmern. Vielen Dank!!
Nimgrg
@nimgrg Es scheint, dass sich die Ansicht in die negative Richtung bewegt, aber es ist nicht. Interne Koordinaten der Übersicht werden geändert.
Lorenzo B
Verzeihen Sie meine geometrischen Fähigkeiten. Wenn die internen Koordinaten der Übersicht in Ursprung (30.0, 20.0) geändert werden, liegt der Punkt (0,0) innerhalb oder außerhalb des blauen Quadrats. Ich versuche nur, die Änderungen aufzuspüren und einen Sinn daraus zu machen. Vielen Dank, dass Sie sich die Zeit genommen haben, um zu antworten.
Nimgrg
@flexaddicted: Hallo, die Folie, die Sie hinzugefügt haben, sagt: "Die Mitte von Ansicht B in ihrem eigenen Koordinatenraum ist: bounds.size.width / 2 + origin.x" - warum ist das so? Da der Titel in einem eigenen Koordinatenraum steht, würde ich sagen, dass es lautet: bounds.size.width / 2 + bounds.origin.x ?? Ist es nicht?
134

Diese Frage hat bereits eine gute Antwort, aber ich möchte sie mit einigen weiteren Bildern ergänzen. Meine vollständige Antwort ist hier.

Um mich an den Rahmen zu erinnern , denke ich an einen Bilderrahmen an einer Wand . So wie ein Bild an eine beliebige Stelle an der Wand verschoben werden kann, ist das Koordinatensystem des Rahmens einer Ansicht die Übersicht. (Wand = Übersicht, Rahmen = Ansicht)

Um mich an Grenzen zu erinnern , denke ich an die Grenzen eines Basketballplatzes . Der Basketball befindet sich irgendwo auf dem Platz, genau wie das Koordinatensystem der Sichtgrenzen innerhalb der Sicht selbst liegt. (Platz = Ansicht, Basketball / Spieler = Inhalt innerhalb der Ansicht)

Wie der Frame befindet sich auch view.center in den Koordinaten der Übersicht.

Frame vs Bounds - Beispiel 1

Das gelbe Rechteck repräsentiert den Rahmen der Ansicht. Das grüne Rechteck repräsentiert die Grenzen der Ansicht. Der rote Punkt in beiden Bildern repräsentiert den Ursprung des Rahmens oder der Grenzen innerhalb ihrer Koordinatensysteme.

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

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

Geben Sie hier die Bildbeschreibung ein


Beispiel 2

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

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

Geben Sie hier die Bildbeschreibung ein


Beispiel 3

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

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

Geben Sie hier die Bildbeschreibung ein


Beispiel 4

Dies ist dasselbe wie in Beispiel 2, außer dass diesmal der gesamte Inhalt der Ansicht so angezeigt wird, als würde er nicht an die Grenzen der Ansicht gekürzt.

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

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

Geben Sie hier die Bildbeschreibung ein


Beispiel 5

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

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

Geben Sie hier die Bildbeschreibung ein

Auch hier finden Sie meine Antwort mit weiteren Details.

Suragch
quelle
2
Danke Suragch. Es ist wirklich ein sehr klares Bild von Rahmen und gebundenem Unterschied. Ich schätze Ihre Bemühungen sehr.
Mohd Haider
All das Zeug, das ich in einer kurzen und prägnanten Antwort sehen möchte. Vielen Dank!
Matt Chuang
Genial! Zum Beispiel 3: Ich verstehe es nicht. Sie haben den Ursprung Ihres Rahmens nur ein wenig verschoben. Wie ändert sich dadurch die Drehung Ihres Bildes?
Honig
@ asma22, In Beispiel 3 habe ich nur versucht zu zeigen, dass sich beim Drehen eines Bildes der Rahmen ändert, die Grenzen jedoch nicht. Siehe meine ausführlichere Antwort .
Suragch
89

Ich fand dieses Bild am hilfreichsten, um Rahmen, Grenzen usw. zu verstehen.

Geben Sie hier die Bildbeschreibung ein

Bitte beachten Sie auch, dass frame.size != bounds.sizedas Bild gedreht wird.

Erben Mo.
quelle
14
Ein Bild mit tausend Worten.
Narendra Kamma
3
Die bestmögliche Erklärung
Ratikanta Patra
@Erben Mo: Hallo, auf der Folie, die Sie hinzugefügt haben, heißt es: "Die Mitte von Ansicht B in ihrem eigenen Koordinatenraum lautet: bounds.size.width / 2 + origin.x" - warum ist das so? Da der Titel in einem eigenen Koordinatenraum steht, würde ich sagen, dass es lautet: bounds.size.width / 2 + bounds.origin.x ?? Ist es nicht?
1
Woher stammt dieses Bild? Verknüpfung?
David
1
@ David Es ist aus Stanfords CS193p-Kurs auf iTunesU, der hier zu finden ist: www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2013-fall
preynolds
3

Ich denke, wenn Sie es von dem Punkt aus denken CALayer, ist alles klarer.

Frame ist überhaupt keine eigenständige Eigenschaft der Ansicht oder Ebene, sondern eine virtuelle Eigenschaft, die aus den Grenzen, der Position ( UIViewMitte) und der Transformation berechnet wird .

Grundsätzlich wird also festgelegt, wie die Layer- / Ansichtslayouts wirklich von diesen drei Eigenschaften (und anchorPoint) bestimmt werden, und jede dieser drei Eigenschaften ändert keine andere Eigenschaft, wie das Ändern der Transformation die Grenzen nicht ändert.

coolbeet
quelle
2

Es gibt sehr gute Antworten mit detaillierten Erklärungen zu diesem Beitrag. Ich möchte nur darauf hinweisen, dass es eine weitere Erklärung mit visueller Darstellung für die Bedeutung von Frame, Bounds, Center, Transform, Bounds Origin im WWDC 2011-Video gibt. Grundlegendes zum UIKit-Rendering von @ 4: 22 bis 20:10

Wael Showair
quelle
0

Nachdem ich die obigen Antworten gelesen habe, füge ich hier meine Interpretationen hinzu.

Angenommen, Sie surfen online. Der Webbrowserframe entscheidet, wo und wie groß die Webseite angezeigt werden soll . Der Browser des Browsers bounds.originentscheidet, welcher Teil der Webseite angezeigt wird. bounds.originist schwer zu verstehen. Der beste Weg, dies zu lernen, besteht darin, eine Einzelansichtsanwendung zu erstellen, diese Parameter zu ändern und zu sehen, wie sich Unteransichten ändern.

- (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
quelle