UIView рамка, межі та центр


320

Я хотів би знати, як правильно використовувати ці властивості.

Як я розумію, frame можна використовувати з контейнера представлення, яке я створюю. Він встановлює положення перегляду відносно подання контейнера. Він також встановлює розмір цього виду.

Також center може використовуватися з контейнера представлення, яке я створюю. Ця властивість змінює положення перегляду відносно контейнера.

Нарешті, boundsвідносно самого виду. Це змінює зону, що малюється, для перегляду.

Чи можете ви надати більше інформації про зв’язок між frameі bounds? Що можна сказати про clipsToBoundsі masksToBoundsвластивості?


1
Ця дискусія вже вирішена тут. тому будь ласка дивіться його тут або міг бачити розробник документації , наданої тут developer.apple.com/library/ios/#documentation/uikit/reference / ... stackoverflow.com/questions/1210047 / ... slideshare.net/onoaonoa/cs193p-lecture-5 -перегляд-анімація
Чудовий

Відповіді:


577

Оскільки питання, яке я задавав, було бачено багато разів, я надам детальну відповідь на нього. Ви можете змінити його, якщо хочете додати більш правильний вміст.

Спочатку резюме на питання: рамка, межі та центр та їхні стосунки.

Кадр Вид frame( CGRect) - це положення його прямокутника в системі superviewкоординат. За замовчуванням він починається вгорі зліва.

Межі Огляд bounds( CGRect) виражає прямокутник перегляду у власній системі координат.

Центрcenter є CGPointвираженим в термінах superviewсистеми «s координат і визначає положення точної центральної точки зору.

Узяті з позиції UIView + , це відносини (вони не працюють у коді, оскільки вони є неформальними рівняннями) серед попередніх властивостей:

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

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

  • frame.size = bounds.size

ПРИМІТКА. Ці відносини не застосовуються при повороті поглядів. Для отримання додаткової інформації я запропоную вам поглянути на наступне зображення, зроблене з кухонного ящика на базі курсу 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)але так як view2«S frame originпочинається з (20.0, 20.0), вони будуть збігатися.

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

Позиція originпредставляє позицію view's в її межах, 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, це призведе до того, що субпрезентація буде відсічена до меж приймача. Якщо встановлено НІ, підзагляди, рамки яких виходять за межі видимих ​​меж приймача, не відсікаються. Значення за замовчуванням - НІ.

Іншими словами, якщо перегляд frameє, (0, 0, 100, 100)а його підвід - (90, 90, 30, 30)це лише ви, ви побачите лише частину цього перегляду. Останній не перевищує межі батьківського подання.

masksToBoundsеквівалентно clipsToBounds. Замість а UIView, ця властивість застосовується до а CALayer. Під капотом clipsToBoundsдзвонить masksToBounds. Для подальших посилань дивіться, як співвідношення кліпів UIViewToBounds та масок CALayerToBounds? .


@Rhubarb Ви абсолютно праві. Я зазначу це у своїй відповіді. Дякую.
Лоренцо Б

Я не знаю, чи отримаю я відповідь, але чому підвид переходить у негативному напрямку, коли змінено походження кордонів. Я просто не можу опустити голову. Дякую!!
nimgrg

@nimgrg Здається, погляд переходить у негативному напрямку, але це не так. Внутрішні координати огляду змінюються.
Лоренцо Б

пробачте мої геометричні здібності, якщо внутрішні координати наглядового огляду змінені на походження (30,0, 20,0), чи точка (0,0) лежить всередині синього квадрата чи поза ним. Я просто намагаюся відстежити зміни та зрозуміти це. Дякуємо, що знайшли час для відповіді.
nimgrg

@flexaddicted: Вітаю, слайд, який ви додали, говорить: "Переглянути середину B у власному просторі координат: bounds.size.width / 2 + origin.x" - чому це так? Оскільки заголовок говорить у власному просторі координат, я б сказав, що це: bounds.size.width / 2 + bounds.origin.x ?? Чи не так ??

134

На це питання вже є хороша відповідь, але я хочу доповнити його ще кількома картинками. Моя повна відповідь тут.

Щоб мені запам'ятати кадр , я думаю про рамку для картин на стіні . Подібно до того, як зображення можна переміщувати будь-де на стіні, система координат кадру огляду є надзором. (стіна = нагляд, кадр = вид)

Щоб допомогти мені запам'ятати межі , я думаю про межі баскетбольного майданчика . Баскетбол знаходиться десь в корі, подібно до того, як система координат меж зору знаходиться в межах самого погляду. (суд = вид, баскетбол / гравці = вміст всередині подання)

Як і кадр, view.center також знаходиться в координатах огляду.

Рамка проти меж - Приклад 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

введіть тут опис зображення

Ще раз, дивіться тут мою відповідь з більш детальною інформацією.


2
Спасибі Сурагч. Це дійсно дуже чітка картина рамки та пов'язаної різниці. Я дуже ціную ваші зусилля.
Мохд Хайдер

Усі речі, які я хочу побачити в одній короткій і стислій відповіді. Дякую!
Метт Чуанг

Дивовижно! Для прикладу 3: Я не розумію. ви лише трохи перемістили походження кадру, як це змінить обертання зображення?
Мед

@ asma22, в прикладі 3 я просто намагався показати, що при обертанні зображення кадр змінюється, але межі не виникають. Дивіться мою більш повну відповідь .
Сурагч

89

Я знайшов це зображення найбільш корисним для розуміння кадру, меж тощо.

введіть тут опис зображення

Також врахуйте, що frame.size != bounds.sizeпри повороті зображення.


14
Малюнок вартістю тисяч слів.
Нарендра Камма

3
Найкраще можливе пояснення
Ратіканта Патра

@Erben Mo: Привіт, доданий вами слайд говорить: "Переглянути середину B у власному просторі координат: bounds.size.width / 2 + origin.x" - чому це так? Оскільки заголовок говорить у власному просторі координат, я б сказав, що це: bounds.size.width / 2 + bounds.origin.x ?? Чи не так ??

1
Яке джерело цього образу? Посилання?
Девід

1
@David Це з курсу CS193p Стенфорда на iTunesU, знайденого тут: www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2013-fall
preynolds

3

Я думаю, якщо ви думаєте це з точки зору CALayer, все більш зрозуміло.

Кадр насправді зовсім не є окремою властивістю подання чи шару, це віртуальна властивість, обчислена з меж, положення ( UIViewу центрі) та перетворення.

Таким чином, в основному, як ці властивості (і anchorPoint) насправді вирішують макети шару / перегляду, і будь-яке з цих трьох властивостей не змінить жодне інше властивість, як-от зміна трансформації не змінює межі.


2

На цю посаду є дуже хороші відповіді з детальним поясненням. Я просто хотів би зазначити, що існує ще одне пояснення із візуальним поданням значення рамки, меж, центру, перетворення, межі походження у відеозаписі WWDC 2011 Розуміння візуалізації UIKit починаючи з @ 4: 22 до 20:10


0

Прочитавши вищевказані відповіді, тут додаю мої інтерпретації.

Припустимо, веб-переглядач в Інтернеті - це веб-браузер , frameякий визначає, де і наскільки великий показ веб-сторінки. Прокрутка браузера - це bounds.originте, що вирішує, яка частина веб-сторінки буде показана. bounds.originважко зрозуміти. Найкращий спосіб дізнатися - це створити програму Single View, намагаючись змінити ці параметри і побачити, як змінюються підгляди.

- (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));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.