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 -view-animation
Великолепно,

Ответы:


577

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

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

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

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

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

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

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

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


@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

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


0

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

Предположим, что вы просматриваете онлайн, веб-браузер - это ваш сайт, 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));
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.