UIView
a wszystkie jego podklasy mają właściwości frame
i bounds
. Co za różnica?
UIView
a wszystkie jego podklasy mają właściwości frame
i bounds
. Co za różnica?
Odpowiedzi:
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.
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
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ć.
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
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
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
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
transform
wł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ć.
Podczas modyfikowania
transform
wł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.center
współrzędne. Podobnie frame
, center
uż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 UIImageView
z 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
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
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 UIScrollView
i jego podklasami (na przykład a UITableView
). Zobacz Objaśnienie UIScrollView, aby uzyskać więcej wyjaśnień.
Ponieważ frame
odnosi 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, bounds
gdy 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.
Dokumenty Apple
Powiązane pytania StackOverflow
Inne zasoby
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).
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))"
}
}
bounds
vs frame
widok.
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
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.
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.
subView
ramka jest względem niego superView
. zmiana superView
granic na cokolwiek nie spowoduje, że subView
pochodzenie się z nim zbiegnie superView
.
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)
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)
Strona 0: Gdy ScrollView jest na stronie 0 Granice będą (x: 0, y: 0, szerokość: 320, wysokość: 200)
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.
To samo dotyczy przypadku UICollectionView. Najprostszym sposobem na obejrzenie kolekcjiView jest przewinięcie jej i wydrukowanie / zalogowanie jej granic, a wpadniesz na pomysł.
Wszystkie powyższe odpowiedzi są prawidłowe i oto moje zdanie na ten temat:
Aby odróżnić ramkę od granic programista CONCEPTS powinien przeczytać:
- względem superview (jeden widok nadrzędny) jest zawarty w = FRAME
- 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.
Ramka a oprawka
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.