634 Stimmen

Cocoa: Was ist der Unterschied zwischen dem Rahmen und den Begrenzungen?

UIView und seine Unterklassen haben alle die Eigenschaften frame y bounds . Was ist der Unterschied?

1 Stimmen

0 Stimmen

Für mich ist die prägnanteste Erklärung hier zu finden: videos.raywenderlich.com/courses/99-scroll-view-school/lessons/

1 Stimmen

Ein 2:30-Video hat nichts Prägnantes an sich. Ich kann einen oder zwei Sätze viel schneller lesen als 2:30.

952voto

shek Punkte 12621

El Grenzen eines UIView ist die Rechteck ausgedrückt als Ort (x,y) und Größe (Breite,Höhe) relativ zu seinem eigenen Koordinatensystem (0,0).

El Rahmen eines UIView ist die Rechteck ausgedrückt als Position (x,y) und Größe (Breite,Höhe) in Bezug auf die Übersichtsdarstellung, in der es enthalten ist.

Stellen Sie sich also eine Ansicht vor, die eine Größe von 100x100 (Breite x Höhe) hat und bei 25,25 (x,y) der übergeordneten Ansicht positioniert ist. Der folgende Code gibt die Begrenzungen und den Rahmen dieser Ansicht aus:

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

Und die Ausgabe dieses Codes ist:

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

Wir sehen also, dass die Breite und die Höhe der Ansicht in beiden Fällen gleich sind, unabhängig davon, ob wir die Begrenzungen oder den Rahmen betrachten. Der Unterschied liegt in der x,y-Positionierung der Ansicht. Im Falle der Bounds liegen die x- und y-Koordinaten bei 0,0, da sich diese Koordinaten auf die Ansicht selbst beziehen. Die x- und y-Koordinaten des Rahmens beziehen sich jedoch auf die Position der Ansicht innerhalb der übergeordneten Ansicht (die, wie bereits erwähnt, bei 25,25 liegt).

Außerdem gibt es eine großartige Präsentation die UIViews abdeckt. Auf den Folien 1-20 wird nicht nur der Unterschied zwischen Frames und Bounds erklärt, sondern es werden auch visuelle Beispiele gezeigt.

41 Stimmen

So wird nicht die x,y für Grenzen immer 0,0 sein, da seine die Position des Objekts in... selbst. Oder könnten Sie ein Szenario geben, wo es nicht sein würde?

5 Stimmen

Soweit ich weiß, wird der Ursprung der Grenzen immer 0,0 sein.

78 Stimmen

Der bounds.origin kann auch etwas anderes als 0,0 sein. Verwenden Sie setBoundsOrigin:, um den Ursprung zu verschieben. Siehe "View Geometry" in der "View Programming Guide for Cocoa" für weitere Informationen.

756voto

Suragch Punkte 420096

Kurze Antwort

Rahmen \= Position und Größe einer Ansicht mit Hilfe der das Koordinatensystem der übergeordneten Ansicht

  • Wichtig für: Platzierung der Ansicht in der übergeordneten

Grenzen \= Position und Größe einer Ansicht mit ein eigenes Koordinatensystem

  • Wichtig für: Platzierung des Inhalts der Ansicht oder von Unteransichten in der Ansicht selbst

Ausführliche Antwort

Um mich zu erinnern Rahmen denke ich an ein Bilderrahmen an einer Wand . Der Bilderrahmen ist wie der Rand einer Ansicht. Ich kann das Bild an die Wand hängen, wo immer ich will. Auf die gleiche Weise kann ich eine Ansicht an einer beliebigen Stelle innerhalb einer übergeordneten Ansicht (auch Superview genannt) platzieren. Die übergeordnete Ansicht ist wie eine Wand. Der Ursprung des Koordinatensystems in iOS ist oben links. Wir können unsere Ansicht am Ursprung der übergeordneten Ansicht platzieren, indem wir die x-y-Koordinaten des Ansichtsrahmens auf (0, 0) setzen, was dem Aufhängen unseres Bildes in der linken oberen Ecke der Wand entspricht. Um es nach rechts zu verschieben, erhöhen Sie x, um es nach unten zu verschieben, erhöhen Sie y.

Um mich zu erinnern Grenzen denke ich an einen Basketballplatz wo manchmal der Basketball wird aus dem Spielfeld geworfen . Du dribbelst den Ball über den ganzen Basketballplatz, aber es ist dir eigentlich egal, wo der Platz ist. Es könnte in einer Turnhalle sein, oder draußen an einer High School, oder vor deinem Haus. Es spielt keine Rolle. Du willst einfach nur Basketball spielen. Auf die gleiche Weise interessiert sich das Koordinatensystem für die Grenzen einer Ansicht nur für die Ansicht selbst. Es weiß nichts darüber, wo sich die Ansicht in der übergeordneten Ansicht befindet. Der Ursprung der Begrenzungen (standardmäßig der Punkt (0, 0)) ist die linke obere Ecke der Ansicht. Alle Unteransichten, die diese Ansicht hat, werden in Bezug auf diesen Punkt angeordnet. Es ist so, als würde man den Basketball in die vordere linke Ecke des Spielfelds werfen.

Die Verwirrung entsteht nun, wenn man versucht, Rahmen und Grenzen zu vergleichen. Es ist aber nicht so schlimm, wie es zunächst scheint. Nehmen wir einige Bilder zur Hilfe, um es zu verstehen.

Rahmen vs. Grenzen

Im ersten Bild auf der linken Seite haben wir eine Ansicht, die sich oben links von ihrer übergeordneten Ansicht befindet. Das gelbe Rechteck stellt den Rahmen der Ansicht dar. Auf der rechten Seite sehen wir wieder die Ansicht, aber dieses Mal wird die übergeordnete Ansicht nicht angezeigt. Das liegt daran, dass die Begrenzungen die übergeordnete Ansicht nicht kennen. Das grüne Rechteck stellt die Begrenzungen der Ansicht dar. Die roter Punkt in beiden Bildern stellt die Herkunft des Rahmens oder der Begrenzungen.

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

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

enter image description here

Der Rahmen und die Grenzen waren bei diesem Bild also genau gleich. Schauen wir uns nun ein Beispiel an, bei dem sie unterschiedlich sind.

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

Sie können also sehen, dass die Änderung der x-y-Koordinaten des Rahmens diesen in der übergeordneten Ansicht verschiebt. Aber der Inhalt der Ansicht selbst sieht immer noch genau gleich aus. Die Begrenzungen haben keine Ahnung, dass etwas anders ist.

Bisher waren die Breite und Höhe des Rahmens und der Begrenzungen genau gleich. Das ist aber nicht immer der Fall. Sehen Sie sich an, was passiert, wenn wir die Ansicht um 20 Grad im Uhrzeigersinn drehen. (Die Drehung wird mit Hilfe von Transformationen durchgeführt. Siehe die Dokumentation und diese siehe y Beispiele für Ebenen für weitere Informationen).

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

Sie können sehen, dass die Grenzen immer noch dieselben sind. Sie wissen immer noch nicht, dass etwas passiert ist! Die Rahmenwerte haben sich jedoch alle geändert.

Jetzt ist es etwas einfacher, den Unterschied zwischen Frame und Bounds zu erkennen, nicht wahr? Der Artikel Sie verstehen wahrscheinlich nicht, was Frames und Bounds sind definiert einen Ansichtsrahmen als

...das kleinste Begrenzungsrechteck dieser Ansicht in Bezug auf das übergeordnete Koordinatensystem, einschließlich aller auf diese Ansicht angewandten Transformationen.

Es ist wichtig zu beachten, dass der Rahmen undefiniert wird, wenn Sie eine Ansicht transformieren. Der gelbe Rahmen, den ich um die gedrehten grünen Begrenzungen im obigen Bild gezeichnet habe, existiert also eigentlich gar nicht. Das heißt, wenn Sie eine Ansicht drehen, skalieren oder auf andere Weise transformieren, sollten Sie die Rahmenwerte nicht mehr verwenden. Sie können die Werte für die Begrenzungen aber weiterhin verwenden. Die Apple-Dokumente warnen:

Das ist wichtig: Wenn die Ansicht transform Eigenschaft nicht die Identitätstransformation enthält, ist der Rahmen dieser Ansicht undefiniert und auch die Ergebnisse des Verhaltens zur automatischen Größenanpassung.

Ziemlich unglücklich über die automatische Größenanpassung.... Es gibt jedoch etwas, das Sie tun können.

In den Apple-Dokumenten heißt es:

Bei der Änderung der transform Eigenschaft Ihrer Ansicht, alle werden alle Transformationen relativ zum Mittelpunkt der Ansicht durchgeführt. Ansicht durchgeführt.

Wenn Sie also eine Ansicht in der übergeordneten Ansicht verschieben müssen, nachdem eine Transformation durchgeführt wurde, können Sie dies tun, indem Sie die view.center Koordinaten. Wie frame , center verwendet das Koordinatensystem der übergeordneten Ansicht.

Okay, lassen wir die Rotation beiseite und konzentrieren uns auf die Begrenzungen. Bislang lag der Ursprung der Grenzen immer bei (0, 0). Das muss aber nicht so sein. Was ist, wenn unsere Ansicht eine große Unteransicht hat, die zu groß ist, um sie alle auf einmal anzuzeigen? Wir machen daraus eine UIImageView mit einem großen Bild. Hier ist wieder unser zweites Bild von oben, aber dieses Mal können wir sehen, wie der gesamte Inhalt der Unteransicht unserer Ansicht aussehen würde.

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

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

enter image description here

Nur die linke obere Ecke des Bildes kann innerhalb der Grenzen der Ansicht liegen. Schauen Sie sich an, was passiert, wenn wir die Ursprungskoordinaten der Begrenzungen ändern.

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

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

enter image description here

Der Rahmen hat sich in der Superview nicht verschoben, aber der Inhalt innerhalb des Rahmens hat sich geändert, weil der Ursprung des Begrenzungsrechtecks an einem anderen Teil der Ansicht beginnt. Dies ist die ganze Idee hinter einer UIScrollView und seine Unterklassen (zum Beispiel eine UITableView ). Siehe Verstehen von UIScrollView für weitere Erklärungen.

Wann wird ein Rahmen und wann eine Begrenzung verwendet?

Seit frame sich auf die Position einer Ansicht in ihrer übergeordneten Ansicht bezieht, verwenden Sie sie, wenn Sie äußere Veränderungen wie das Ändern der Breite oder das Ermitteln des Abstands zwischen der Ansicht und dem oberen Rand der übergeordneten Ansicht.

Verwenden Sie die bounds wenn Sie innere Veränderungen wie das Zeichnen von Dingen oder das Anordnen von Unteransichten innerhalb der Ansicht. Verwenden Sie auch die Grenzen, um die Größe der Ansicht zu ermitteln, wenn Sie eine Transfomation vorgenommen haben.

Artikel für die weitere Forschung:

Apple-Dokumente

Verwandte StackOverflow-Fragen

Andere Ressourcen

Üben Sie selbst

Zusätzlich zur Lektüre der oben genannten Artikel hilft es mir sehr, eine Testanwendung zu erstellen. Vielleicht möchten Sie versuchen, etwas Ähnliches zu tun. (Ich habe die Idee von dieser Videokurs aber leider ist es nicht kostenlos.)

enter image description here

Hier ist der Code zu Ihrer Information:

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

    }

}

0 Stimmen

Es sieht so aus, als ob die Breite und Höhe von Bound überflüssig ist und eine "Origin"-Eigenschaft ausreichend gewesen wäre (wie bei Flash).

0 Stimmen

Verwenden Sie Bounds für "wie Zeichnen Dinge oder Anordnen von Unteransichten innerhalb der Ansicht". Sie meinen, wenn ich eine viewController, die zwei Tasten habe ich die Tasten mit der Ansicht 'Bounds' der viewController platzieren sollte?! Ich habe immer den Rahmen des Views verwendet...

0 Stimmen

@Honey, ich bin mit meinen iOS-Kenntnissen etwas eingerostet, da ich seit einem Jahr mit Android arbeite. Ich glaube, die Root-Ansicht eines View Controllers füllt den Bildschirm aus, so dass der Rahmen und die Grenzen gleich sein sollten.

43voto

tristan Punkte 759

Versuchen Sie, den folgenden Code auszuführen

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

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

die Ausgabe dieses Codes ist:

Fall, dass das Gerät im Hochformat ausgerichtet ist

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

falls das Gerät im Querformat ausgerichtet ist

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

Sie können natürlich den Unterschied zwischen Frame und Bounds sehen

2 Stimmen

Das ist nicht mehr wahr (iOS 8)

1 Stimmen

14voto

jorik Punkte 645

El Rahmen ist das Rechteck, das die UIView mit in Bezug auf seine Aufsicht .

El Begrenzungsrechteck ist der Bereich von Werten, die das Das Koordinatensystem von NSView.

d.h. alles, was sich in diesem Rechteck befindet, wird tatsächlich in der UIView angezeigt.

13voto

yoAlex5 Punkte 20661

iOS Frame vs Bounds

Rahmen - (x, y) hängen von parenView ab und berechnen einen vollen Rechteckspot, der von Bounds belegt wird.

  • x:60, y:20, Breite: 45, Höhe: 45 ist ein dynamischer Wert, der auf inneren Grenzen basiert.

Grenzen - (x, y) ist 0,0.

  • x:0, y:0, Breite: 20, Höhe: 40 ist ein statisch

Eine weitere Illustration, um den Unterschied zwischen Rahmen und Grenzen zu verdeutlichen. Bei diesem Beispiel:

  • View B ist eine Unteransicht von View A
  • View B wurde verschoben nach x:60, y: 20
  • View B wurde gedreht 45 degrees

enter image description here

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X