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
зрения. Например, если вы измените 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
в пределах своей 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));