Cocoa: Jaka jest różnica między ramką a granicami?

587

UIViewa wszystkie jego podklasy mają właściwości framei bounds. Co za różnica?

mk12
źródło
1
Zrozumienie ramki macoscope.com/blog/understanding-frame
onmyway133
dla mnie najbardziej zwięzłe wyjaśnienie znajduje się tutaj: videos.raywenderlich.com/courses/99-scroll-view-school/lessons/…
Vlad
1
W filmie o 2:30 nie ma nic zwięzłego. Mogę przeczytać zdanie lub dwa znacznie szybciej niż 2:30.
dsjoerg,
Dla mnie jest o wiele bardziej jasne, jeśli myślę w ten sposób: Frame = Bounds & Position
Serg

Odpowiedzi:

902

Te granice od An UIView jest prostokąt , wyrażone w miejscu (x, y), wielkość (szerokość, wysokość) w stosunku do jego własnych układu współrzędnych (0,0).

Ramki o UIView jest prostokąt , wyrażone w miejscu (x, y), wielkość (szerokość, wysokość) w stosunku do SuperView jest on zawarty wewnątrz.

Wyobraźmy sobie widok o rozmiarze 100 x 100 (szerokość x wysokość) ustawiony na 25,25 (x, y) jego widoku. Poniższy kod drukuje granice i ramkę tego widoku:

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

Wyjście tego kodu to:

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

Widzimy więc, że w obu przypadkach szerokość i wysokość widoku są takie same, niezależnie od tego, czy patrzymy na granice, czy ramkę. Różni się pozycjonowaniem widoku x, y. W przypadku granic współrzędne xiy wynoszą 0,0, ponieważ współrzędne te odnoszą się do samego widoku. Jednak współrzędne ramki x i y są względne względem położenia widoku w widoku macierzystym (który wcześniej powiedzieliśmy, że ma 25,25).

Jest też świetna prezentacja obejmująca UIViews. Zobacz slajdy 1-20, które nie tylko wyjaśniają różnicę między ramkami i granicami, ale także pokazują przykłady wizualne.

shek
źródło
37
Więc x, y dla granic nie zawsze będzie wynosić 0,0, ponieważ jest to położenie obiektu w ... samym sobie. A może mógłbyś podać scenariusz, w którym by nie był?
mk12
5
O ile mi wiadomo, początek granic zawsze będzie wynosił 0,0
shek
77
W rzeczywistości bounds.origin może być czymś innym niż 0,0. Użyj setBoundsOrigin: aby przenieść / przetłumaczyć początek. Aby uzyskać więcej informacji, zobacz „Wyświetl geometrię” w „Wyświetl przewodnik programowania dla kakao”.
Meltemi
127
UIScrollView to przykład, w którym granice można przesunąć, aby pokazać różne regiony zawartości w widoku.
Brad Larson
92
Mała wskazówka - użycie NSStringFromCGRect może zaoszczędzić trochę czasu na zarejestrowanie poprawek.
beryl
645

Krótka odpowiedź

ramka = położenie i rozmiar widoku za pomocą układu współrzędnych widoku nadrzędnego

  • Ważne dla: umieszczenia widoku w obiekcie nadrzędnym

bounds = położenie i rozmiar widoku przy użyciu własnego układu współrzędnych

  • Ważne dla: umieszczania treści widoku lub widoków podrzędnych w sobie

Szczegółowa odpowiedź

Aby pomóc mi zapamiętać ramkę , myślę o ramce na ścianie . Ramka obrazu jest jak ramka widoku. Mogę zawiesić obraz w dowolnym miejscu na ścianie. W ten sam sposób mogę umieścić widok w dowolnym miejscu w widoku nadrzędnym (zwanym także superview). Widok rodzica jest jak ściana. Początek układu współrzędnych w iOS znajduje się w lewym górnym rogu. Możemy umieścić nasz widok na początku podglądu, ustawiając współrzędne xy ramki widoku na (0, 0), co przypomina zawieszenie naszego obrazu w lewym górnym rogu ściany. Aby przesunąć w prawo, zwiększ x, aby przesunąć w dół, zwiększ y.

Aby pomóc mi zapamiętać granice , myślę o boisku do koszykówki, w którym czasami koszykówka jest wyrzucana z boiska . Dryblujesz piłkę po całym boisku do koszykówki, ale tak naprawdę nie obchodzi cię, gdzie jest sam boisko. Może być na siłowni, na zewnątrz w szkole średniej lub przed domem. To nie ma znaczenia Po prostu chcesz grać w koszykówkę. W ten sam sposób układ współrzędnych dla granic widoku dba tylko o sam widok. Nic nie wie o tym, gdzie widok znajduje się w widoku nadrzędnym. Początek granic (domyślnie punkt (0, 0)) to lewy górny róg widoku. Wszelkie poddziały, które ma ten pogląd, są przedstawione w odniesieniu do tego punktu. To tak, jakby wziąć koszykówkę do lewego przedniego rogu boiska.

Teraz zamieszanie pojawia się, gdy próbujesz porównać ramkę i granice. Jednak tak naprawdę nie jest tak źle, jak się wydaje. Wykorzystajmy kilka zdjęć, które pomogą nam zrozumieć.

Frame vs Bounds

Na pierwszym zdjęciu po lewej mamy widok, który znajduje się w lewym górnym rogu jego widoku nadrzędnego. Żółty prostokąt reprezentuje ramkę widoku. Po prawej stronie ponownie widzimy widok, ale tym razem widok rodzica nie jest wyświetlany. Jest tak, ponieważ granice nie wiedzą o widoku nadrzędnym. Zielony prostokąt reprezentuje granice widoku. Czerwona plamka na obu obrazach reprezentuje początek ramki lub granic.

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

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

wprowadź opis zdjęcia tutaj

Ramka i obwiednie były dokładnie takie same na tym zdjęciu. Spójrzmy na przykład, w którym są różne.

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

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

wprowadź opis zdjęcia tutaj

Możesz więc zobaczyć, że zmiana współrzędnych xy ramki przesuwa ją w widoku nadrzędnym. Ale treść samego widoku nadal wygląda dokładnie tak samo. Granice nie mają pojęcia, że ​​coś jest inne.

Do tej pory szerokość i wysokość ramki i obrzeży były dokładnie takie same. Jednak nie zawsze tak jest. Zobacz, co się stanie, jeśli obrócimy widok o 20 stopni w prawo. (Obracanie odbywa się za pomocą transformacji. Aby uzyskać więcej informacji, zobacz dokumentację oraz te przykłady widoku i warstw ).

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

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

wprowadź opis zdjęcia tutaj

Widać, że granice są nadal takie same. Nadal nie wiedzą, że coś się stało! Jednak wszystkie wartości ramek się zmieniły.

Teraz łatwiej jest dostrzec różnicę między ramką a granicami, prawda? Artykuł Prawdopodobnie nie rozumiesz ramek i ramek definiuje ramkę widoku jako

... najmniejsza ramka graniczna tego widoku w odniesieniu do jego macierzystego układu współrzędnych, w tym wszelkie transformacje zastosowane do tego widoku.

Należy zauważyć, że jeśli przekształcisz widok, wówczas ramka stanie się niezdefiniowana. Tak więc w rzeczywistości żółta ramka, którą narysowałem wokół obróconych zielonych granic na powyższym obrazku, nigdy nie istnieje. Oznacza to, że jeśli obracasz, skalujesz lub wykonujesz jakąś inną transformację, nie powinieneś więcej używać wartości ramek. Nadal jednak możesz używać wartości granic. Dokumenty Apple ostrzegają:

Ważne: jeśli transformwłaściwość widoku nie zawiera transformacji tożsamości, ramka tego widoku jest niezdefiniowana, podobnie jak wyniki jego zachowań automatycznych.

Raczej niefortunne z powodu autoresize… Jest jednak coś, co możesz zrobić.

Dokumenty Apple zawierają:

Podczas modyfikowania transformwłaściwości widoku wszystkie przekształcenia są wykonywane względem punktu środkowego widoku.

Jeśli więc po zakończeniu transformacji musisz przesunąć widok w obiekcie nadrzędnym, możesz to zrobić, zmieniając view.centerwspółrzędne. Podobnie frame, centerużywa układu współrzędnych w widoku rodzica.

Ok, pozbądźmy się naszej rotacji i skupmy się na granicach. Do tej pory początek granic zawsze pozostawał na (0, 0). Jednak nie musi. Co się stanie, jeśli nasz widok ma duży widok podrzędny, który jest zbyt duży, aby wyświetlić go jednocześnie? Zrobimy to UIImageViewz dużym obrazem. Oto nasze drugie zdjęcie z góry, ale tym razem możemy zobaczyć, jak wyglądałaby cała treść widoku z naszego widoku.

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

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

wprowadź opis zdjęcia tutaj

Tylko lewy górny róg obrazu mieści się w granicach widoku. Teraz spójrz, co się stanie, jeśli zmienimy współrzędne początkowe granic.

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

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

wprowadź opis zdjęcia tutaj

Ramka nie przesunęła się w widoku podglądu, ale zawartość wewnątrz ramki uległa zmianie, ponieważ początek prostokąta obwiedni zaczyna się w innej części widoku. To jest cała idea stojąca za a UIScrollViewi jego podklasami (na przykład a UITableView). Zobacz Objaśnienie UIScrollView, aby uzyskać więcej wyjaśnień.

Kiedy używać ramki, a kiedy używać granic

Ponieważ frameodnosi się do położenia widoku w jego widoku nadrzędnym, używasz go podczas wprowadzania zewnętrznych zmian , takich jak zmiana jego szerokości lub znalezienie odległości między widokiem a górą jego widoku nadrzędnego.

Użyj tego, boundsgdy wprowadzasz wewnętrzne zmiany , takie jak rysowanie rzeczy lub rozmieszczanie widoków podrzędnych w widoku. Użyj również granic, aby uzyskać rozmiar widoku, jeśli dokonałeś na nim transfomacji.

Artykuły do ​​dalszych badań:

Dokumenty Apple

Powiązane pytania StackOverflow

Inne zasoby

Ćwicz się

Oprócz czytania powyższych artykułów bardzo pomaga mi stworzenie aplikacji testowej. Możesz spróbować zrobić coś podobnego. (Pomysł zrodził się z tego kursu wideo, ale niestety nie jest bezpłatny).

wprowadź opis zdjęcia tutaj

Oto kod dla odniesienia:

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

    }

}
Suragch
źródło
Wygląda na to, że szerokość i wysokość granicy są zbędne, a właściwość „origin” byłaby wystarczająca (tak jak w przypadku Flasha).
Ian Warburton
użyj granic do „jak rysowanie rzeczy lub aranżowanie widoków podrzędnych w widoku”. masz na myśli, jeśli mam viewController, który ma dwa przyciski, powinienem umieścić przyciski, używając „granic” widoku viewController ?! Zawsze korzystałem z ramki widoku ...
Honey
@ Kochanie, jestem trochę zardzewiały na moich umiejętnościach iOS, ponieważ pracuję na Androidzie przez ostatni rok. Wierzę, że widok główny kontrolera widoku wypełnia ekran, więc jego ramka i granice powinny być takie same.
Suragch
5
Utworzono repozytorium github.com/maniramezan/FrameVsBounds.git w oparciu o przykładową aplikację podaną tutaj, aby pomóc lepiej zrozumieć boundsvs framewidok.
manman
Dzięki! Dobre wytłumaczenie. Obraz jest cenniejszy niż 1000 słów
Pedro Trujillo,
43

spróbuj uruchomić poniższy kod

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

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

wyjście tego kodu to:

jeśli urządzenie ma orientację pionową

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

jeśli urządzenie ma orientację poziomą

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

oczywiście widać różnicę między ramką a granicami

Tristan
źródło
2
to już nie jest prawda (iOS 8)
Julian Król
13

Rama jest prostokątem, który definiuje UIView w odniesieniu do jego SuperView .

Granica rect to zakres wartości, które definiują układ współrzędnych tego NSView.

tzn. wszystko w tym prostokącie będzie faktycznie wyświetlane w UIView.

jorik
źródło
10

ramka jest początkiem (lewy górny róg) i rozmiarem widoku w układzie współrzędnych super widoku, oznacza to, że tłumaczysz widok w jego super widoku, zmieniając początek ramki, z drugiej strony granice to rozmiar i początek jego własny układ współrzędnych, więc domyślnie początek granic to (0,0).

przez większość czasu ramka i granice są przystające, ale jeśli masz na przykład widok ramki ((140,65), (200,250)) i granic ((0,0), (200,250)), a widok został przechylony tak, aby stał w prawym dolnym rogu, wówczas granice nadal będą wynosić ((0,0), (200,250)), ale ramka nie jest.

wprowadź opis zdjęcia tutaj

ramka będzie najmniejszym prostokątem otaczającym / otaczającym widok, więc ramka (jak na zdjęciu) będzie ((140,65), (320,320)).

inną różnicą jest na przykład, jeśli masz superView, którego granice to ((0,0), (200,200)), a ten superView ma subView, którego ramka to ((20,20), (100,100)) i zmieniłeś granice superView na ((20,20), (200,200)), wówczas ramka widoku podrzędnego będzie nadal ((20,20), (100,100)), ale zostanie przesunięta o (20,20), ponieważ jej układ współrzędnych nadzoru został zrównoważony przez (20, 20).

mam nadzieję, że to komuś pomoże.

m.eldehairy
źródło
w odniesieniu do ostatniego akapitu: subView ramka jest względem niego superView. zmiana superViewgranic na cokolwiek nie spowoduje, że subViewpochodzenie się z nim zbiegnie superView.
staticVoidMan
5

Wykadruj jego krewnego względem jego SuperView, podczas gdy Bound względem jego NSView.

Przykład: X = 40, Y = 60. Zawiera również 3 widoki. Ten schemat pokazuje wyraźny pomysł.

RAMA

MIEDZA

RAGHUNATH
źródło
4

Pozwól mi dodać 5 centów.

Ramka jest używana przez widok nadrzędny widoku do umieszczenia go w widoku nadrzędnym.

Bounds jest używany przez samego widoku, aby umieścić własną treść (jak myślą przewijania robi podczas przewijania). Zobacz także clipsToBounds . Granice można również wykorzystać do powiększania / zmniejszania zawartości widoku.

Analogia:
Ramka ~ Ekran telewizora
Związane ~ Kamera (powiększanie, przesuwanie, obracanie)

Serg
źródło
2

Powyższe odpowiedzi bardzo dobrze wyjaśniły różnicę między granicami i ramkami.

Granice: Rozmiar i położenie widoku według własnego układu współrzędnych.

Ramka: Rozmiar widoku i lokalizacja względem jego SuperView.

Potem jest zamieszanie, że w przypadku Bounds X, Y zawsze będzie wynosić „0”. To nie jest prawda . Można to zrozumieć również w UIScrollView i UICollectionView.

Gdy granice x, y nie są równe 0.
Załóżmy, że mamy UIScrollView. Wdrożyliśmy paginację. UIScrollView ma 3 strony, a jego szerokość ContentSize jest trzy razy większa od szerokości ekranu (zakładając, że ScreenWidth wynosi 320). Wysokość jest stała (załóż 200).

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

Dodaj trzy UIImageViews jako subViews i uważnie przyjrzyj się wartości x ramki

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. Strona 0: Gdy ScrollView jest na stronie 0 Granice będą (x: 0, y: 0, szerokość: 320, wysokość: 200)

  2. Strona 1: Przewiń i przejdź do strony 1.
    Teraz granice będą (x: 320, y: 0, szerokość: 320, wysokość: 200) Pamiętaj, że mówiliśmy w odniesieniu do własnego układu współrzędnych. Zatem teraz „Widoczna część” naszego ScrollView ma „x” na 320. Spójrz na ramkę imageView1.

  3. Strona 2: Przewiń i przejdź do strony 2 Granice: (x: 640, y: 0, szerokość: 320, wysokość: 200) Ponownie spójrz na ramkę obrazuViewView2

To samo dotyczy przypadku UICollectionView. Najprostszym sposobem na obejrzenie kolekcjiView jest przewinięcie jej i wydrukowanie / zalogowanie jej granic, a wpadniesz na pomysł.

Muhammad Nayab
źródło
2

Wszystkie powyższe odpowiedzi są prawidłowe i oto moje zdanie na ten temat:

Aby odróżnić ramkę od granic programista CONCEPTS powinien przeczytać:

  1. względem superview (jeden widok nadrzędny) jest zawarty w = FRAME
  2. w stosunku do własnego układu współrzędnych określa jego lokalizację widoku podrzędnego = BOUNDS

„granice” są mylące, ponieważ sprawiają wrażenie, że współrzędne są pozycją widoku, dla którego są ustawione. Są to jednak relacje i dostosowane zgodnie ze stałymi ramek.

ekran iPhone'a

przystań
źródło
1

Jeszcze jedna ilustracja pokazująca różnicę między ramką a granicami. W tym przykładzie:

  • View B jest podrozdziałem View A
  • View B został przeniesiony do x:60, y: 20
  • View B został obrócony 45 degrees

wprowadź opis zdjęcia tutaj

yoAlex5
źródło
0

Ramka a oprawka

  • Jeśli utworzysz widok w X: 0, Y: 0, szerokość: 400, wysokość: 400, jego ramka i obwiednie są takie same.
  • Jeśli przeniesiesz ten widok do X: 400, jego ramka odzwierciedli tę zmianę, ale jego granice nie. Pamiętaj, że granice odnoszą się do własnej przestrzeni widoku, a wewnętrznie do widoku nic się nie zmieniło.
  • Jeśli przekształcisz widok, np. Obrócisz go lub przeskalujesz w górę, ramka zmieni się, aby to odzwierciedlić, ale granice nadal się nie zmienią - jeśli chodzi o widok wewnętrzny, nie zmienił się.
  • Jeśli zmienisz granice, zmieni to zawartość wewnątrz ramki, ponieważ początek prostokąta granic zaczyna się w innej części widoku.
Anit Kumar
źródło
-1

ramka = położenie i rozmiar widoku za pomocą układu współrzędnych widoku nadrzędnego

bounds = położenie i rozmiar widoku przy użyciu własnego układu współrzędnych

Widok śledzi swój rozmiar i położenie za pomocą dwóch prostokątów: prostokąta ramki i prostokąta obwiedni. Prostokąt ramki określa położenie i rozmiar widoku w superwizji za pomocą układu współrzędnych superwizji. Prostokąt obwiedni określa wewnętrzny układ współrzędnych używany podczas rysowania zawartości widoku, w tym jego początku i skalowania. Rysunek 2-1 pokazuje zależność między prostokątem ramy po lewej stronie i prostokątem granic po prawej stronie. ”

Krótko mówiąc, ramka jest pomysłem widoku w widoku superwizyjnym, a granice - pomysłem widoku. Posiadanie wielu układów współrzędnych, po jednym dla każdego widoku, jest częścią hierarchii widoków.

Xab Ion
źródło
Gdzie jest rysunek 2-1?
Alexander Mayatsky