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
?
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 .
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.
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 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?.
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
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
Przykład 3
Frame
origin = (20, 52) // These are just rough estimates.
width = 118
height = 187
Bounds
origin = (0, 0)
width = 80
height = 130
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
Przykład 5
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (280, 70)
width = 80
height = 130
Ponownie, zobacz tutaj dla mojej odpowiedzi więcej szczegółów.
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.
Należy również pamiętać, że frame.size != bounds.size
podczas obracania obrazu.
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.
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.
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
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));
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