UIView
und seine Unterklassen haben alle die Eigenschaften frame
und bounds
. Was ist der Unterschied?
UIView
und seine Unterklassen haben alle die Eigenschaften frame
und bounds
. Was ist der Unterschied?
Antworten:
Die Grenzen einer UIView sind das Rechteck , ausgedrückt als Position (x, y) und Größe (Breite, Höhe) relativ zu ihrem eigenen Koordinatensystem (0,0).
Der Rahmen einer UIView ist das Rechteck , ausgedrückt als Position (x, y) und Größe (Breite, Höhe) relativ zu der Übersicht, in der es enthalten ist.
Stellen Sie sich also eine Ansicht mit einer Größe von 100 x 100 (Breite x Höhe) vor, die bei 25,25 (x, y) ihrer Übersicht positioniert ist. Der folgende Code druckt die Grenzen 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 können also sehen, dass in beiden Fällen die Breite und Höhe der Ansicht gleich sind, unabhängig davon, ob wir die Grenzen oder den Rahmen betrachten. Was anders ist, ist die x, y-Positionierung der Ansicht. Im Fall der Grenzen liegen die x- und y-Koordinaten bei 0,0, da diese Koordinaten relativ zur Ansicht selbst sind. Die x- und y-Koordinaten des Rahmens beziehen sich jedoch auf die Position der Ansicht innerhalb der übergeordneten Ansicht (die wir zuvor bei 25,25 angegeben haben).
Es gibt auch eine großartige Präsentation , die UIViews abdeckt. Siehe Folien 1-20, die nicht nur den Unterschied zwischen Frames und Bounds erklären, sondern auch visuelle Beispiele zeigen.
frame = Position und Größe einer Ansicht unter Verwendung des Koordinatensystems der übergeordneten Ansicht
Grenzen = Position und Größe einer Ansicht unter Verwendung eines eigenen Koordinatensystems
Um mich an den Rahmen zu erinnern , denke ich an einen Bilderrahmen an einer Wand . Der Bilderrahmen ist wie der Rand einer Ansicht. Ich kann das Bild überall an die Wand hängen, wo ich will. Auf die gleiche Weise kann ich eine Ansicht an einer beliebigen Stelle in eine übergeordnete Ansicht einfügen (auch als Übersicht bezeichnet). Die übergeordnete Ansicht ist wie die Wand. Der Ursprung des Koordinatensystems in iOS ist oben links. Wir können unsere Ansicht an den Ursprung der Übersicht setzen, indem wir die xy-Koordinaten des Ansichtsrahmens auf (0, 0) setzen, was so ist, als würden wir unser Bild in der oberen linken Ecke der Wand aufhängen. Um es nach rechts zu bewegen, erhöhen Sie x, um es nach unten zu bewegen, erhöhen Sie y.
Um mich an Grenzen zu erinnern , denke ich an einen Basketballplatz, auf dem der Basketball manchmal aus dem Ruder läuft . Sie dribbeln den Ball über den gesamten Basketballplatz, aber es ist Ihnen egal, wo sich der Platz selbst befindet. Es könnte in einem Fitnessstudio oder draußen in einer High School oder vor Ihrem Haus sein. Es spielt keine Rolle. Du willst nur Basketball spielen. Auf die gleiche Weise kümmert sich das Koordinatensystem für die Grenzen einer Ansicht nur um die Ansicht selbst. Es weiß nichts darüber, wo sich die Ansicht in der übergeordneten Ansicht befindet. Der Ursprung der Grenzen (standardmäßig Punkt (0, 0)) ist die obere linke Ecke der Ansicht. Alle Unteransichten, die diese Ansicht hat, werden in Bezug auf diesen Punkt angelegt. Es ist, als würde man den Basketball in die vordere linke Ecke des Platzes bringen.
Jetzt kommt die Verwirrung, wenn Sie versuchen, Rahmen und Grenzen zu vergleichen. Es ist jedoch nicht so schlimm, wie es zunächst scheint. Lassen Sie uns einige Bilder verwenden, um uns das Verständnis zu erleichtern.
Im ersten Bild links haben wir eine Ansicht, die sich oben links in der übergeordneten Ansicht befindet. Das gelbe Rechteck repräsentiert den Rahmen der Ansicht. Rechts sehen wir die Ansicht wieder, aber diesmal wird die übergeordnete Ansicht nicht angezeigt. Das liegt daran, dass die Grenzen nichts über die übergeordnete Ansicht wissen. 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.
Frame
origin = (0, 0)
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Der Rahmen und die Grenzen waren auf diesem Bild also genau gleich. Schauen wir uns ein Beispiel an, in 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
Sie können also sehen, dass durch Ändern der xy-Koordinaten des Rahmens dieser in der übergeordneten Ansicht verschoben wird. Der Inhalt der Ansicht selbst sieht jedoch immer noch genauso aus. Die Grenzen haben keine Ahnung, dass etwas anders ist.
Bisher waren Breite und Höhe des Rahmens und der Begrenzungen genau gleich. Das ist jedoch nicht immer wahr. Schauen Sie, was passiert, wenn wir die Ansicht um 20 Grad im Uhrzeigersinn drehen. (Die Drehung erfolgt mithilfe von Transformationen. Weitere Informationen finden Sie in der Dokumentation sowie in diesen Ansichts- und Ebenenbeispielen .)
Frame
origin = (20, 52) // These are just rough estimates.
width = 118
height = 187
Bounds
origin = (0, 0)
width = 80
height = 130
Sie können sehen, dass die Grenzen immer noch gleich sind. Sie wissen immer noch nicht, dass etwas passiert ist! Die Frame-Werte haben sich jedoch alle geändert.
Jetzt ist es ein bisschen einfacher, den Unterschied zwischen Frame und Grenzen zu erkennen, nicht wahr? Der Artikel, den Sie wahrscheinlich nicht verstehen, definiert einen Ansichtsrahmen als
... der kleinste Begrenzungsrahmen dieser Ansicht in Bezug auf das übergeordnete Koordinatensystem, einschließlich aller auf diese Ansicht angewendeten 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 Grenzen im obigen Bild gezeichnet habe, existiert also eigentlich nie. Das heißt, wenn Sie drehen, skalieren oder eine andere Transformation durchführen, sollten Sie die Rahmenwerte nicht mehr verwenden. Sie können die Grenzwerte jedoch weiterhin verwenden. Die Apple-Dokumente warnen:
Wichtig: Wenn die
transform
Eigenschaft einer Ansicht die Identitätstransformation nicht enthält, ist der Rahmen dieser Ansicht undefiniert, ebenso wie die Ergebnisse ihres automatischen Größenänderungsverhaltens.
Eher unglücklich über die automatische Größenanpassung ... Es gibt jedoch etwas, das Sie tun können.
In den Apple-Dokumenten heißt es:
Wenn Sie die
transform
Eigenschaft Ihrer Ansicht ändern, werden alle Transformationen relativ zum Mittelpunkt der Ansicht ausgeführt.
Wenn Sie also nach einer Transformation eine Ansicht im übergeordneten Element verschieben müssen, können Sie dies tun, indem Sie die view.center
Koordinaten ändern . Wie frame
, center
verwendet das Koordinatensystem der übergeordneten Ansicht.
Ok, lassen Sie uns unsere Rotation loswerden und uns auf die Grenzen konzentrieren. Bisher blieb der Grenzursprung immer bei (0, 0). Das muss es aber nicht. Was ist, wenn unsere Ansicht eine große Unteransicht hat, die zu groß ist, um auf einmal angezeigt zu werden? Wir machen es 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
Nur die obere linke Ecke des Bildes kann in die Grenzen der Ansicht passen. Schauen Sie nun, was passiert, wenn wir die Ursprungskoordinaten der Grenzen ändern.
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (280, 70)
width = 80
height = 130
Der Rahmen wurde in der Übersicht nicht verschoben, aber der Inhalt innerhalb des Rahmens hat sich geändert, da der Ursprung des Begrenzungsrechtecks an einem anderen Teil der Ansicht beginnt. Dies ist die ganze Idee hinter a UIScrollView
und seinen Unterklassen (zum Beispiel a UITableView
). Siehe Verständnis UIScrollView für weitere Erklärung.
Da frame
die Position einer Ansicht in der übergeordneten Ansicht verknüpft ist, verwenden Sie sie, wenn Sie Änderungen nach außen vornehmen , z. B. die Breite ändern oder den Abstand zwischen der Ansicht und dem oberen Rand der übergeordneten Ansicht ermitteln.
Verwenden bounds
Sie diese Option, wenn Sie nach innen gerichtete Änderungen vornehmen , z. B. Dinge zeichnen oder Unteransichten in der Ansicht anordnen. Verwenden Sie auch die Grenzen, um die Größe der Ansicht zu ermitteln, wenn Sie eine Transfomation durchgeführt haben.
Apple-Dokumente
Verwandte Fragen zu StackOverflow
Andere Ressourcen
Zusätzlich zum Lesen der obigen Artikel hilft es mir sehr, eine Test-App zu erstellen. Vielleicht möchten Sie versuchen, etwas Ähnliches zu tun. (Ich habe die Idee von diesem Videokurs bekommen, aber leider ist er nicht kostenlos.)
Hier ist der Code als Referenz:
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))"
}
}
bounds
Vergleich frame
zu einer Ansicht zu verbessern.
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 lautet:
Fall Gerät Ausrichtung ist Porträt
{{0, 0}, {768, 1024}}
{{0, 0}, {768, 1024}}
Die Ausrichtung des Gehäusegeräts ist Querformat
{{0, 0}, {768, 1024}}
{{0, 0}, {1024, 768}}
Offensichtlich können Sie den Unterschied zwischen Frame und Grenzen erkennen
Der Rahmen ist der Ursprung (obere linke Ecke) und die Größe der Ansicht im Koordinatensystem der Superansicht. Dies bedeutet, dass Sie die Ansicht in der Superansicht übersetzen, indem Sie den Rahmenursprung und die Grenzen ändern sind dagegen die Größe und der Ursprung in eigenes Koordinatensystem, daher ist der Grenzursprung standardmäßig (0,0).
Meistens sind der Rahmen und die Grenzen kongruent, aber wenn Sie beispielsweise eine Ansicht des Rahmens ((140,65), (200,250)) und der Grenzen ((0,0), (200,250)) haben und die Ansicht gekippt wurde so dass es in der unteren rechten Ecke steht, sind die Grenzen immer noch ((0,0), (200,250)), der Rahmen jedoch nicht.
Der Rahmen ist das kleinste Rechteck, das die Ansicht einschließt / umgibt, sodass der Rahmen (wie auf dem Foto) ((140,65), (320,320)) ist.
Ein weiterer Unterschied besteht beispielsweise darin, dass Sie eine SuperView haben, deren Grenzen ((0,0), (200,200)) sind, und diese SuperView eine Unteransicht hat, deren Rahmen ((20,20), (100,100) ist, und Sie die SuperView-Grenzen geändert haben bis ((20,20), (200,200)) ist der SubView-Frame immer noch ((20,20), (100,100)), aber um (20,20) versetzt, da sein Koordinatensystem für die Übersicht um (20,20) versetzt wurde. 20).
Ich hoffe das hilft jemandem.
subView
Rahmen ist relativ zu ihm superView
. Wenn Sie die superView
Grenzen auf etwas ändern, subView
stimmt der Ursprung nicht mit dem überein superView
.
Lassen Sie mich meine 5 Cent hinzufügen.
Der Rahmen wird von der übergeordneten Ansicht der Ansicht verwendet, um ihn in der übergeordneten Ansicht zu platzieren.
Bounds wird von der Ansicht selbst verwendet, um ihren eigenen Inhalt zu platzieren (wie es eine Bildlaufansicht beim Scrollen tut). Siehe auch clipsToBounds . Grenzen können auch zum Vergrößern / Verkleinern des Inhalts der Ansicht verwendet werden.
Analogie:
Rahmen ~ TV-Bildschirm
Grenzen ~ Kamera (zoomen, bewegen, drehen)
Die obigen Antworten haben den Unterschied zwischen Grenzen und Rahmen sehr gut erklärt.
Grenzen: Eine Ansicht Größe und Position gemäß ihrem eigenen Koordinatensystem.
Frame: Eine Ansichtsgröße und Position relativ zu seiner SuperView.
Dann gibt es Verwirrung, dass im Fall von Grenzen das X, Y immer "0" ist. Das ist nicht wahr . Dies kann auch in UIScrollView und UICollectionView verstanden werden.
Wenn die Grenzen x, y nicht 0 sind.
Nehmen wir an, wir haben eine UIScrollView. Wir haben die Paginierung implementiert. Die UIScrollView hat 3 Seiten und die Breite von ContentSize beträgt das Dreifache der Bildschirmbreite (vorausgesetzt, die Bildschirmbreite beträgt 320). Die Höhe ist konstant (angenommen 200).
scrollView.contentSize = CGSize(x:320*3, y : 200)
Fügen Sie drei UIImageViews als SubViews hinzu und sehen Sie sich den x- Wert des Frames genau an
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)
Seite 0: Wenn sich die ScrollView auf 0 befindet, sind die Grenzen (x: 0, y: 0, Breite: 320, Höhe: 200).
Seite 1: Scrollen Sie und gehen Sie zu Seite 1.
Jetzt sind die Grenzen (x: 320, y: 0, Breite: 320, Höhe: 200).
Denken Sie daran, dass wir dies in Bezug auf das eigene Koordinatensystem gesagt haben. Der "sichtbare Teil" unserer ScrollView hat jetzt sein "x" bei 320. Sehen Sie sich den Rahmen von imageView1 an.
Gleiches gilt für UICollectionView. Der einfachste Weg, sich collectionView anzusehen, besteht darin, es zu scrollen und seine Grenzen zu drucken / zu protokollieren. Sie werden auf die Idee kommen.
Alle obigen Antworten sind richtig und dies ist meine Meinung dazu:
Um zwischen Frame und Grenzen zu unterscheiden, sollte der CONCEPTS-Entwickler Folgendes lesen:
- relativ zur Übersicht (eine übergeordnete Ansicht) ist sie in = FRAME enthalten
- Bestimmt relativ zu seinem eigenen Koordinatensystem die Position der Unteransicht = BOUNDS
"Grenzen" ist verwirrend, weil es den Eindruck erweckt, dass die Koordinaten die Position der Ansicht sind, für die sie festgelegt wurde. Diese stehen jedoch in Relationen und werden entsprechend den Rahmenkonstanten angepasst.
Rahmen gegen gebunden
frame = Position und Größe einer Ansicht unter Verwendung des Koordinatensystems der übergeordneten Ansicht
Grenzen = Position und Größe einer Ansicht unter Verwendung eines eigenen Koordinatensystems
Eine Ansicht verfolgt ihre Größe und Position mithilfe von zwei Rechtecken: einem Rahmenrechteck und einem Begrenzungsrechteck. Das Rahmenrechteck definiert die Position und Größe der Ansicht in der Übersicht mithilfe des Koordinatensystems der Ansicht. Das Begrenzungsrechteck definiert das innere Koordinatensystem, das beim Zeichnen des Inhalts der Ansicht verwendet wird, einschließlich des Ursprungs und der Skalierung. Abbildung 2-1 zeigt die Beziehung zwischen dem Rahmenrechteck links und dem Begrenzungsrechteck rechts. “
Kurz gesagt, der Rahmen ist die Idee einer Ansicht durch die Ansicht, und die Grenzen sind die eigene Idee der Ansicht. Das Vorhandensein mehrerer Koordinatensysteme, eines für jede Ansicht, ist Teil der Ansichtshierarchie.