Я хотел бы знать, как правильно использовать эти свойства.
Как я понимаю, frame
может использоваться из контейнера создаваемого представления.
Он устанавливает положение представления относительно вида контейнера. Он также устанавливает размер этого вида.
Также center
может использоваться из контейнера создаваемого представления. Это свойство изменяет положение представления относительно его контейнера.
Наконец, bounds
относится к самому представлению. Он изменяет область вывода для представления.
Можете ли вы рассказать подробнее о связи между frame
и bounds
? Как насчет свойств clipsToBounds
и masksToBounds
?
Поскольку вопрос, который я задал, был замечен много раз, я предоставлю подробный ответ. Не стесняйтесь изменять его, если вы хотите добавить более правильный контент.
Сначала перескажите вопрос: кадр, границы и центр и их отношения.
Рамка Вид 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
позволяет вам переместить и/или изменить размер представления в пределах 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
представления (см. Предыдущие уравнения).
Рассмотрение примера1 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 frame is: %@", NSStringFromCGRect([view1 frame]));
NSLog(@"view1 bounds is: %@", NSStringFromCGRect([view1 bounds]));
NSLog(@"view1 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)
Установка этого значения в значение YES приводит к тому, что subviews будут обрезаны до границ приемника. Если установлено значение NO, subviews, чьи рамки выходят за пределы видимые границы приемника не обрезаны. Значение по умолчанию НЕТ.
Другими словами, если представление frame
равно (0, 0, 100, 100)
, а его подвью (90, 90, 30, 30)
, вы увидите только часть этого поднабора. Последнее не будет превышать границы родительского вида.
masksToBounds
эквивалентен clipsToBounds
. Вместо UIView
это свойство применяется к CALayer
. Под капотом clipsToBounds
вызывается masksToBounds
. Для дальнейших ссылок взгляните на Какова связь между клипами UIViewToBounds и масками CALayerToBounds?.
У этого вопроса уже есть хороший ответ, но я хочу дополнить его еще несколькими картинками. Мой полный ответ здесь.
Чтобы помочь мне запомнить фрейм, я думаю о рамке на стене. Подобно тому, как изображение можно перемещать в любом месте стены, система координат рамы просмотра - это супервизор. (wall = superview, frame = view)
Чтобы помочь мне запомнить границы, я думаю о пределах баскетбольной площадки. Баскетбол находится где-то внутри суда, точно так же, как система координат точек зрения находится внутри самого представления. (court = view, basketball/players = content внутри представления)
Подобно кадру, view.center также находится в координатах надстройки.
Желтый прямоугольник представляет собой рамку представления. Зеленый прямоугольник представляет границы представления. Красная точка на обоих изображениях представляет собой начало кадра или границ в их системах координат.
Frame
origin = (0, 0)
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Frame
origin = (40, 60) // That is, x=40 and y=60
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Frame
origin = (20, 52) // These are just rough estimates.
width = 118
height = 187
Bounds
origin = (0, 0)
width = 80
height = 130
Это то же самое, что и в примере 2, за исключением того, что на этот раз отображается весь контент представления, как бы он выглядел, если бы он не был привязан к границам представления.
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (0, 0)
width = 80
height = 130
Frame
origin = (40, 60)
width = 80
height = 130
Bounds
origin = (280, 70)
width = 80
height = 130
Снова, см. здесь для получения более подробной информации.
Я нашел этот образ наиболее полезным для понимания фрейма, границ и т.д.
Также обратите внимание, что frame.size != bounds.size
, когда изображение повернуто.
Я думаю, если вы думаете, что это с точки зрения CALayer
, все становится понятным.
Кадр на самом деле не является отдельным свойством представления или слоя вообще, это виртуальное свойство, вычисленное из границ, положения (UIView
center) и преобразуется.
Итак, в основном, как это делают свойства layer/view, эти три свойства (и anchorPoint), и любое из этих трех свойств не изменит никакого другого свойства, как изменение преобразования не изменяет границ.
Есть очень хорошие ответы с подробным объяснением этого сообщения. Я просто хотел бы напомнить, что есть еще одно объяснение с визуальным представлением для значения Frame, Bounds, Center, Transform, Bounds Origin в WWDC 2011 video Понимание рендеринга UIKit, начиная с @4: 22 до 20:10
Прочитав приведенные выше ответы, добавьте мои интерпретации.
Предположим, что просмотр в Интернете, веб-браузер - это ваш frame
, который решает, где и как большой показать веб-страницу. Скроллер браузера - это ваш bounds.origin
, который определяет, какая часть веб-страницы будет показана. bounds.origin
трудно понять. Лучший способ узнать - создать приложение Single View, попробовать изменить эти параметры и посмотреть, как изменяются субвью.
- (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));