UIView frame, bounds and center

Chciałbym wiedzieć, jak wykorzystać te właściwości we właściwy sposób.

Jak rozumiem, frame może być używany z kontenera widoku, który tworzę. Ustawia pozycję widoku względem widoku kontenera. Ustawia również rozmiar tego widoku.

Również center mogą być używane z kontenera widoku, który tworzę. Ta właściwość zmienia położenie widoku względem kontenera.

Wreszcie, bounds jest względem samego widoku. Zmienia rysowalny obszar dla widoku.

Czy możesz podać więcej informacji o związku między frame i bounds? Co z właściwościami clipsToBounds i masksToBounds?

Author: Greg, 2011-03-19

7 answers

Ponieważ pytanie, które zadałem, było wielokrotnie widziane, podam na nie szczegółową odpowiedź. Możesz go zmodyfikować, jeśli chcesz dodać więcej poprawnych treści.

Najpierw podsumowanie na pytanie: rama, granice i centrum i ich relacje.

Frame a view ' S frame (CGRect) jest położeniem jego prostokąta w układzie współrzędnych superview. Domyślnie zaczyna się w lewym górnym rogu.

Bounds a view ' s bounds (CGRect) wyraża pogląd prostokąt we własnym układzie współrzędnych.

Środek A center jest CGPoint wyrażony w układzie współrzędnych superview i określa położenie dokładnego punktu środkowego punktu widzenia.

Wzięte z UIView + position są to relacje (nie działają w kodzie, ponieważ są równaniami nieformalnymi) między poprzednimi właściwości:

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

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

  • frame.size = bounds.size

Uwaga: te relacje nie mają zastosowania, jeśli widoki są obrócone. Aby uzyskać więcej informacji, proponuję spojrzeć na poniższe zdjęcie wykonane z Szuflada kuchenna na podstawie Stanford CS193p oczywiście. Podziękowania dla @ rabarbar .

Rama, granice i środek

Korzystanie z frame pozwala na zmień położenie i / lub zmień rozmiar widoku w jego superview. Zwykle może być używany z superview, na przykład podczas tworzenia określonego widoku podrzędnego. Na przykład:

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

Kiedy potrzebujesz współrzędnych do rysowania wewnątrz view, Zwykle odnosisz się do bounds. Typowym przykładem może być rysowanie w obrębie view subview jako wstawka pierwszego. Rysowanie subview wymaga znajomości bounds superview. Na przykład:

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

Różne zachowania zdarzają się, gdy zmieniasz bounds z widok. Na przykład, jeśli zmienisz bounds size, zmiany frame (i vice versa). Zmiana zachodzi wokół center widoku. Użyj poniższego kodu i zobacz, co się stanie:

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

Ponadto, jeśli zmienisz bounds origin zmieniasz origin jego wewnętrznego układu współrzędnych. Domyślnie origin znajduje się w (0.0, 0.0) (lewy górny róg). Na przykład, jeśli zmienisz origin na view1, możesz zobaczyć (skomentuj poprzedni kod, jeśli chcesz), że teraz lewy górny róg view2 dotyka view1 jeden. Motywacja jest dość prosta. Mówisz do view1, że jej lewy górny róg jest teraz na pozycji (20.0, 20.0), ale od view2 ' s frame origin zaczyna się od (20.0, 20.0), będą się pokrywać.

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

origin reprezentuje pozycję view w jej superview, ale opisuje pozycję bounds środka.

Wreszcie, bounds i origin nie są pojęciami pokrewnymi. Oba pozwalają na wyprowadzenie frame widoku (patrz poprzednie równania).

Etui View1 badanie

Oto, co dzieje się podczas korzystania z poniższego fragmentu.

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

Obraz relatywny.

Tutaj wpisz opis obrazka

Zamiast tego, co się stanie, jeśli zmienię [self view] granice, jak poniżej.

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

Obraz relatywny.

Tutaj wpisz opis obrazka

Tutaj mówisz [self view], że jej lewy górny róg znajduje się teraz na pozycji (30.0, 20.0), ale ponieważ początek ramki view1 zaczyna się od (30.0, 20.0), będą się pokrywać.

Dodatkowe referencje (aby zaktualizować inne referencje, jeśli chcesz)

O clipsToBounds (źródło Apple doc)

Ustawienie tej wartości na yes powoduje przycinanie podglądów do granic odbiornika. Jeśli ustawiono na nie, podwidywacze, których ramki wykraczają poza widoczne granice odbiornika nie są przycięte. Wartością domyślną jest Nie.

Innymi słowy, jeśli Widok frame to (0, 0, 100, 100), a jego subview to (90, 90, 30, 30), zobaczysz tylko część tego subview. Ten ostatni nie przekroczy granic widoku nadrzędnego.

masksToBounds jest równoważne clipsToBounds. Zamiast UIView, właściwość ta jest stosowana do CALayer. Pod maską, clipsToBounds rozmowy masksToBounds. W celu uzyskania dalszych odniesień zajrzyj do jak wygląda relacja między Clipstoboundami UIView i maskstoboundami Calayera?.

 558
Author: Lorenzo Boaro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:05

To pytanie ma już dobrą odpowiedź, ale chcę je uzupełnić o kilka zdjęć. Moja pełna odpowiedź jest tutaj.

Aby pomóc mi zapamiętać ramkę , myślę o ramkę na zdjęcie na ścianie. Podobnie jak obraz może być przesuwany w dowolnym miejscu na ścianie, układem współrzędnych ramki widoku jest superwizor. (wall= superview, frame=view)

Aby pomóc mi zapamiętać granice , myślę o granicach boiska do koszykówki . Na Koszykówka jest gdzieś w korcie, podobnie jak układ współrzędnych granic widoku jest w samym widoku. (court=view, basketball/players=content inside the view)

Jak ramka, widok.centrum znajduje się również we współrzędnych superwizji.

Frame vs Bounds-przykład 1

Żółty prostokąt reprezentuje ramkę widoku. Zielony prostokąt reprezentuje granice widoku. Czerwona kropka na obu obrazach reprezentuje pochodzenie ramki lub granic w ich układach współrzędnych.

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

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

Tutaj wpisz opis obrazka


Przykład 2

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

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

Tutaj wpisz opis obrazka


Przykład 3

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

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

Tutaj wpisz opis obrazka


Przykład 4

Jest to to samo co w przykładzie 2, z tą różnicą, że tym razem cała zawartość widoku jest pokazana tak, jak wyglądałaby, gdyby nie została przycięta do granic widoku.

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

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

Tutaj wpisz opis obrazka


Przykład 5

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

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

Tutaj wpisz opis obrazka

Ponownie, zobacz tutaj dla mojej odpowiedzi więcej szczegółów.

 124
Author: Suragch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:25

Uznałem Ten obraz za najbardziej pomocny w zrozumieniu ramki, granic itp.

Tutaj wpisz opis obrazka

Należy również pamiętać, że frame.size != bounds.size podczas obracania obrazu.

 87
Author: Erben Mo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-23 07:27:34
  • właściwość frame zawiera frame rectangle, który określa rozmiar i położenie widoku w jego układzie współrzędnych superview.
  • właściwość bounds zawiera prostokąt bounds, który określa rozmiar widoku (i jego pochodzenie) we własnym lokalnym układzie współrzędnych.
  • właściwość center zawiera znany środkowy punkt widzenia w układzie współrzędnych superview.
 8
Author: Saheb Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-17 08:59:19

Myślę, że jeśli myślisz o tym z punktu CALayer, wszystko jest bardziej jasne.

Ramka nie jest tak naprawdę odrębną właściwością widoku lub warstwy, jest wirtualną właściwością, obliczaną z granic, położenia (UIView's center) i przekształcenia.

Więc zasadniczo o tym, w jaki sposób układy warstwy/widoku są naprawdę decydowane przez te trzy właściwości(i punkt kontrolny), a żadna z tych trzech właściwości nie zmieni żadnej innej właściwości, tak jak zmiana transformacji nie zmienia granic.

 3
Author: coolbeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-21 05:51:34

Są bardzo dobre odpowiedzi ze szczegółowym wyjaśnieniem tego postu. Chciałbym tylko odnieść się do tego, że istnieje inne wyjaśnienie z wizualną reprezentacją znaczenia Ramki, granic, Centrum, transformacji, pochodzenia granic w wideo WWDC 2011zrozumienie renderowania UIKit starting from @4: 22 till 20: 10

 1
Author: Wael Showair,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-31 19:16:25

Po przeczytaniu powyższych odpowiedzi, tutaj dodaję moje interpretacje.

Załóżmy, że przeglądanie online, przeglądarka internetowa jest twoją frame, która decyduje o tym, gdzie i jak duża będzie wyświetlana strona. Scroller przeglądarki jest twoim bounds.origin, Który decyduje, która część strony zostanie wyświetlona. Trudno to zrozumieć. Najlepszym sposobem na nauczenie się jest tworzenie aplikacji z pojedynczym widokiem, próba modyfikacji tych parametrów i sprawdzenie, jak zmieniają się podglądy.

- (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));
 0
Author: NSTNF,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-25 12:17:04