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


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

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

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

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

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

7 300

7 ответов:

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

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

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

границы A вид 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 вид. Например, если вы измените 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; 

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

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

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 приводит к тому, что подвиды будут обрезаны до границ из приемника. Если задано значение нет, подвиды, фреймы которых выходят за пределы видимые границы приемника не обрезаются. Значение по умолчанию НЕТ.

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

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

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

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

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

как рама, вид.центр также находится в координатах супервизора.

рамка против границ-Пример 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

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

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

enter image description here

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

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

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

Frame на самом деле не является отдельным свойством вида или слоя вообще, это виртуальное свойство, вычисленное из границ, позиции(UIView ' s center), и преобразование.

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

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

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

предположим, просмотр в интернете,браузер ваш 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));