UIView рамка, границы и центр - PullRequest
314 голосов
/ 19 марта 2011

Я хотел бы знать, как правильно использовать эти свойства.

Как я понимаю, frame можно использовать из контейнера создаваемого мною представления. Он устанавливает позицию просмотра относительно контейнера. Он также устанавливает размер этого представления.

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

Наконец, bounds относительно самого представления. Изменяет область рисования для вида.

Можете ли вы дать больше информации об отношениях между frame и bounds? А как насчет свойств clipsToBounds и masksToBounds?

Ответы [ 6 ]

568 голосов
/ 01 июля 2012

Поскольку вопрос, который я задавал, встречался много раз, я приведу подробный ответ на него. Не стесняйтесь изменять его, если хотите добавить более правильный контент.

Сначала краткий обзор вопроса: рамка, границы, центр и их отношения.

Рамка Вид frame (CGRect) - это положение его прямоугольника в системе координат superview. По умолчанию он начинается слева вверху.

Границы Вид bounds (CGRect) выражает прямоугольник вида в своей собственной системе координат.

Центр A center - это CGPoint, выраженное в системе координат superview, и оно определяет положение точной центральной точки вида.

Взято из UIView + position это отношения (они не работают в коде, поскольку они являются неформальными уравнениями) среди предыдущих свойств:

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

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

  • frame.size = bounds.size

ПРИМЕЧАНИЕ: Эти отношения не применяются, если представления повернуты. Для получения дополнительной информации, я предлагаю вам взглянуть на следующее изображение, взятое с Кухонный ящик на основе Stanford CS193p курс. Кредиты идут на @Rhubarb.

Frame, bounds and center

Использование 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 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 в пределах 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]));

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

enter image description here

Это вместо того, что произойдет, если я изменю [self view] границы следующим образом.

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

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

enter image description here

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

Дополнительные ссылки (для обновления другими ссылками, если хотите)

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

Установка этого значения в YES заставляет подпредставления обрезаться до границ получателя. Если установлено значение NO, подпредставления, кадры которых выходят за рамки видимые границы приемника не ограничены. Значением по умолчанию является NO.

Другими словами, если frame представления - (0, 0, 100, 100), а его подпредставление - (90, 90, 30, 30), вы увидите только часть этого подпредставления. Последнее не будет выходить за пределы родительского представления.

masksToBounds эквивалентно clipsToBounds. Вместо UIView это свойство применяется к CALayer. Под капотом clipsToBounds звонит masksToBounds. Для дальнейших ссылок взгляните на Какова связь между clipsToBounds UIView и masksToBounds CALayer? .

131 голосов
/ 08 марта 2015

На этот вопрос уже есть хороший ответ, но я хочу дополнить его еще несколькими картинками. Мой полный ответ здесь.

Чтобы помочь мне вспомнить рамка , я думаю о рамка для фотографий на стене . Точно так же, как изображение может быть перемещено в любое место на стене, система координат рамки вида является суперпредставлением (стена = супер-вид, рамка = вид)

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

Как и кадр, view.center также находится в координатах суперпредставления.

Рамка против границ - Пример 1

Желтый прямоугольник представляет рамку вида. Зеленый прямоугольник представляет границы представления. Красная точка на обоих изображениях представляет происхождение рамки или границ в их системах координат.

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

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

enter image description here


Пример 2

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

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

enter image description here


Пример 3

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

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

enter image description here


Пример 4

Это то же самое, что и в примере 2, за исключением того, что на этот раз все содержимое представления отображается так, как если бы оно не было обрезано до границ представления.

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

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

enter image description here


Пример 5

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

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

enter image description here

Опять же, см. здесь для моего ответа с более подробной информацией.

88 голосов
/ 12 октября 2012

Я нашел это изображение наиболее полезным для понимания рамки, границ и т. Д.

enter image description here

Также обратите внимание, что frame.size != bounds.size при повороте изображения.

3 голосов
/ 21 октября 2014

Я думаю, если вы думаете, что с точки зрения CALayer, все более ясно.

Фрейм - это не совсем отдельное свойство вида или слоя, это виртуальныйсвойство, вычисляемое по границам, положению (центр UIView) и преобразованию.

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

1 голос
/ 31 октября 2015

На этот пост есть очень хорошие ответы с подробным объяснением. Я просто хотел бы сослаться на то, что есть другое объяснение с визуальным представлением значения Frame, Bounds, Center, Transform, Bounds Origin в видео WWDC 2011 Понимание рендеринга UIKit , начиная с @ 4:22 до 20: 10

0 голосов
/ 03 апреля 2015

После прочтения приведенных выше ответов, здесь добавляются мои интерпретации.

Предположим, что вы просматриваете онлайн, веб-браузер - это ваш frame, который решает, где и насколько велик показ веб-страницы. Scroller браузера - это ваш bounds.origin, который решает, какая часть веб-страницы будет отображаться. bounds.origin трудно понять. Лучший способ научиться - создавать приложение Single View Application, пытаясь изменить эти параметры и посмотреть, как меняются подпредставления.

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