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

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

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

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

В заключение, bounds относительно самого представления. Это изменяет область рисования для вида.

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

7 ответов

Решение

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

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

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

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

Центр А 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 позволяет перемещать и / или изменять размер представления в пределах его 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 зрения. Например, если вы измените boundssize, 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));

Кроме того, если вы измените boundsorigin вы меняете origin его внутренней системы координат. По умолчанию origin я сидела (0.0, 0.0) (верхний левый угол). Например, если вы измените origin за view1 Вы можете видеть (прокомментируйте предыдущий код, если хотите), что теперь верхний левый угол для view2 трогает view1 один. Мотивация довольно проста. Вы говорите view1 что его верхний левый угол теперь находится на позиции (20.0, 20.0) но с тех пор view2 "s frameorigin начинается с (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?,

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

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

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

Как и кадр, 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

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

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

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

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

  • Свойство frame содержит прямоугольник рамки, который определяет размер и местоположение представления в системе координат его суперпредставления.
  • Свойство bounds содержит прямоугольник bounds, который определяет размер представления (и его источник содержимого) в собственной локальной системе координат представления.
  • Свойство center содержит известную центральную точку вида в системе координат суперпредставления.

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

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

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

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

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

Предположим, вы просматриваете онлайн, веб-браузер ваш frame который решает, где и как большой показать веб-страницу. Скроллер браузера - это ваш 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));
Другие вопросы по тегам