UIView рамка, граници и център

Бих искал да знам как да използвам тези свойства по правилния начин.

Доколкото разбирам, frame може да се използва от контейнера на изгледа, който създавам. Той задава позицията на изгледа спрямо изгледа на контейнера. Той също така задава размера на този изглед.

Също така center може да се използва от контейнера на изгледа, който създавам. Това свойство променя позицията на изгледа спрямо неговия контейнер.

И накрая, bounds е относително към самия изглед. Променя зоната за рисуване за изгледа.

Можете ли да дадете повече информация за връзката между frame и bounds? Какво ще кажете за свойствата clipsToBounds и masksToBounds?


person Lorenzo B    schedule 19.03.2011    source източник
comment
Тази дискусия вече е разрешена тук. така че, моля, погледнете го тук или можете да видите документацията на разработчиците, дадена тук developer.apple.com/library/ios/#documentation/uikit/reference/ stackoverflow.com/questions/1210047/ slideshare.net/onoaonoa/cs193p-lecture-5-view-animation   -  person Splendid    schedule 19.03.2011


Отговори (6)


Тъй като въпросът, който зададох, е виждан много пъти, ще дам подробен отговор на него. Чувствайте се свободни да го промените, ако искате да добавите по-правилно съдържание.

Първо обобщение на въпроса: рамка, граници и център и техните взаимоотношения.

Рамка frame (CGRect) на изглед е позицията на неговия правоъгълник в координатната система на superview. По подразбиране започва горе вляво.

Граници bounds (CGRect) на изглед изразява правоъгълник на изглед в неговата собствена координатна система.

Център center е CGPoint, изразено чрез координатната система на superview и определя позицията на точната централна точка на изгледа.

Взети от UIView + позиция това са връзките (те не t работят в код, тъй като те са неофициални уравнения) сред предишните свойства:

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

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

  • frame.size = bounds.size

ЗАБЕЛЕЖКА: Тези връзки не се прилагат, ако изгледите са завъртани. За допълнителна информация ще ви предложа да разгледате следното изображение, взето от The Kitchen Drawer< /strong> въз основа на курса Stanford CS193p. Кредити отиват при @Rhubarb.

Рамка, граници и център

Използването на frame ви позволява да препозиционирате и/или преоразмерите изглед в рамките на неговия superview. Обикновено може да се използва от superview, например, когато създавате конкретен подизглед. Например:

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

Когато имате нужда от координатите за чертане вътре в view, обикновено се обръщате към bounds. Типичен пример може да бъде да начертаете в рамките на view подизглед като вмъкване на първия. Изчертаването на подизгледа изисква да знаете bounds на суперизгледа. Например:

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

Различни поведения се случват, когато промените bounds на изглед. Например, ако промените bounds size, frame се променя (и обратно). Промяната се случва около center на изгледа. Използвайте кода по-долу и вижте какво се случва:

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

Освен това, ако промените bounds origin, вие променяте origin на неговата вътрешна координатна система. По подразбиране origin е на (0.0, 0.0) (горния ляв ъгъл). Например, ако промените origin за view1, можете да видите (коментирайте предишния код, ако искате), че сега горният ляв ъгъл за view2 докосва този view1. Мотивацията е съвсем проста. Казвате на view1, че горният му ляв ъгъл сега е на позиция (20.0, 20.0), но тъй като frame origin на view2 започва от (20.0, 20.0), те ще съвпаднат.

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

origin представлява позицията на view в рамките на superview, но описва позицията на центъра bounds.

И накрая, bounds и origin не са свързани понятия. И двете позволяват да се изведе frame на изглед (вижте предишните уравнения).

Казус от View1

Ето какво се случва, когато използвате следния фрагмент.

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

Относителният образ.

въведете описание на изображението тук

Това вместо това какво се случва, ако променя [self view] границите като следното.

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

Относителният образ.

въведете описание на изображението тук

Тук казвате на [self view], че неговият горен ляв ъгъл сега е на позиция (30.0, 20.0), но тъй като произходът на рамката на view1 започва от (30.0, 20.0), те ще съвпаднат.

Допълнителни препратки (за актуализиране с други препратки, ако желаете)

Относно clipsToBounds (източник Apple doc)

Задаването на тази стойност на YES кара подизгледите да бъдат изрязани до границите на приемника. Ако е зададено на NO, подизгледите, чиито рамки се простират отвъд видимите граници на приемника, не се изрязват. Стойността по подразбиране е НЕ.

С други думи, ако frame на даден изглед е (0, 0, 100, 100) и неговият подизглед е (90, 90, 30, 30), вие ще видите само част от този подизглед. Последният няма да надхвърли границите на родителския изглед.

masksToBounds е еквивалентно на clipsToBounds. Вместо към UIView, това свойство се прилага към CALayer. Под капака clipsToBounds се обажда на masksToBounds. За допълнителни справки вижте Как е връзката между ClipsToBounds на UIView и masksToBounds на CALayer?.

person Community    schedule 01.07.2012
comment
@Rhubarb Напълно си прав. Ще го посоча в отговора си. Благодаря. - person Lorenzo B; 05.12.2012
comment
Не знам дали ще получа отговор, но защо подизгледът се движи в отрицателна посока, когато произходът на границите се промени. Просто не мога да разбера това нещо. Благодаря!! - person nimgrg; 20.06.2013
comment
@nimgrg Изглежда, че изгледът се движи в отрицателна посока, но не е така. Променени са вътрешните координати на суперизгледа. - person Lorenzo B; 20.06.2013
comment
простете за моите геометрични способности, ако вътрешните координати на суперизгледа се променят на начало (30.0, 20.0), точката (0,0) лежи ли вътре в синия квадрат или извън него. Просто се опитвам да проследя промените и да ги осмисля. Благодаря, че отделихте време за отговор. - person nimgrg; 20.06.2013
comment
@flexaddicted: Здравей, слайдът, който добави, казва: Средата на изглед B в собственото му координатно пространство е: bounds.size.width/2+origin.x -- защо е така? Тъй като заглавието казва в свое собствено координатно пространство, бих казал, че е: bounds.size.width/2+bounds.origin.x?? не е ли?? - person ; 06.08.2013
comment
@user2568508 Да, всъщност е така. ;) - person Lorenzo B; 06.08.2013
comment
@flexaddicted: хм малко се обърках сега, изглежда, че слайдът казва bounds.size.width/2+bounds.origin.x -- по някакви причини изглежда, че не забелязах bounds пред origin.x и следователно моят коментар. Изглежда правилният отговор е: ..+bounds.origin.x - person ; 06.08.2013
comment
На първата снимка как мога да разбера кога CGPoint (напр. 141,66) е вътре в рамката, но не и в зоната на границите? И обратното? - person Xiangdong; 22.01.2015
comment
Разработчиците най-често ограничават изгледите, като използват или 1) разкадровки (добре) 2) ограничения (добре) 3) рамка на суперизглед (не добре) 4) Рядко ги виждам да използват границите на суперизглед. Така че само да заключим, че казвате, че използването на рамката на superview няма смисъл, защото изгледът може да се завърти и вместо това границите на superview са правилният подход. Това има смисъл, но предполагам, че тъй като през повечето време не се занимаваме с ротирани изгледи, не се натъкваме на неочаквани проблеми. нали В: Има ли случай, когато действителното използване на границите на суперизгледа не би било това, което искате? Ако да кога? - person Honey; 07.10.2018

Този въпрос вече има добър отговор, но искам да го допълня с още няколко снимки. Пълният ми отговор е тук.

За да ми помогне да запомня рамка, сещам се за рамка за картина на стена. Точно както една картина може да бъде преместена навсякъде по стената, координатната система на рамката на изгледа е суперизгледът. (стена=изглед, рамка=изглед)

За да ми помогне да запомня границите, се сещам за границите на баскетболно игрище. Баскетболната топка е някъде в игрището, точно както координатната система на границите на изгледа е в самия изглед. (корт=изглед, баскетбол/играчи=съдържание в изгледа)

Подобно на рамката, view.center също е в координатите на superview.

Рамка срещу граници - Пример 1

Жълтият правоъгълник представлява рамката на изгледа. Зеленият правоъгълник представлява границите на изгледа. Червената точка и в двете изображения представлява началото на рамката или границите в техните координатни системи.

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

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

въведете описание на изображението тук


Пример 2

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

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

въведете описание на изображението тук


Пример 3

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

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

въведете описание на изображението тук


Пример 4

Това е същото като пример 2, с изключение на това, че цялото съдържание на изгледа е показано така, както би изглеждало, ако не беше изрязано до границите на изгледа.

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

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

въведете описание на изображението тук


Пример 5

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

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

въведете описание на изображението тук

Отново вижте тук за моя отговор с повече подробности.

person Suragch    schedule 08.03.2015
comment
Благодаря Сурагч. Това е наистина много ясна картина на рамката и обвързаната разлика. Наистина оценявам усилията ви. - person Mohd Haider; 26.03.2015
comment
Всички неща, които искам да видя в един кратък и стегнат отговор. Благодаря! - person Matt Chuang; 27.01.2016
comment
Страхотно! Пример 3: Не разбирам. преместихте само малко началото на рамката си, как това променя въртенето на изображението ви? - person Honey; 16.04.2016
comment
@asma22, В пример 3 просто се опитвах да покажа, че когато завъртите изображение, рамката се променя, но границите не. Вижте по-пълния ми отговор. - person Suragch; 16.04.2016

Намерих това изображение за най-полезно за разбиране на рамка, граници и т.н.

въведете описание на изображението тук

Също така имайте предвид, че frame.size != bounds.size, когато изображението се завърти.

person Erben Mo    schedule 12.10.2012
comment
Картина, която струва хиляди думи. - person Narendra Kamma; 20.11.2012
comment
Най-доброто възможно обяснение - person Ratikanta Patra; 30.05.2013
comment
@Erben Mo: Здравей, слайдът, който добави, казва: Средата на изглед B в собственото му координатно пространство е: bounds.size.width/2+origin.x -- защо е така? Тъй като заглавието казва в свое собствено координатно пространство, бих казал, че е: bounds.size.width/2+bounds.origin.x?? не е ли?? - person ; 06.08.2013
comment
Какъв е източникът на това изображение? Линк? - person David; 15.10.2014
comment
@David Това е от курса CS193p на Станфорд в iTunesU, който можете да намерите тук: www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2013-fall - person preynolds; 21.08.2015

Мисля, че ако мислите от гледна точка на CALayer, всичко е по-ясно.

Рамката изобщо не е отделно свойство на изгледа или слоя, то е виртуално свойство, изчислено от границите, позицията (центъра на UIView) и трансформацията.

Така че основно как оформленията на слоя/изгледа наистина се определят от тези три свойства (и anchorPoint) и нито едно от тези три свойства няма да промени никое друго свойство, както промяната на трансформацията не променя границите.

person coolbeet    schedule 21.10.2014

Има много добри отговори с подробно обяснение към тази публикация. Бих искал само да отбележа, че има друго обяснение с визуално представяне за значението на Frame, Bounds, Center, Transform, Bounds Origin във видеоклипа на WWDC 2011 Разбиране на изобразяването на UIKit от @4:22 до 20:10

person Wael Showair    schedule 31.10.2015

След като прочетох горните отговори, тук добавям моите интерпретации.

Да предположим, че сърфирате онлайн, уеб браузър е вашият frame, който решава къде и колко голяма да покаже уеб страницата. Скролерът на браузъра е вашият bounds.origin, който решава коя част от уеб страницата ще бъде показана. bounds.origin е трудно за разбиране. Най-добрият начин да научите е да създадете приложение за единичен изглед, опитвайки се да промените тези параметри и да видите как се променят подизгледите.

- (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));
person NSTNF    schedule 03.04.2015