Работать со структурами CGPoint
, CGSize
и CGRect
несложно, если вы привыкли к языку, который поддерживает синтаксис точки. Однако программное позиционирование видов или написание кода чертежа является многословным и может стать трудным для чтения.
В этом руководстве я хотел бы прояснить несколько неправильных представлений о фреймах и границах и познакомить вас с CGGeometry , набором структур, констант и функций, которые значительно упрощают работу с CGPoint
, CGSize
и CGRect
.
1. Типы данных
Если вы новичок в разработке для iOS или OS X, вам может быть интересно, что такое структуры CGPoint
, CGSize
и CGRect
. Справочник CGGeometry определяет ряд геометрических примитивов или структур, и нас интересуют CGPoint
, CGSize
и CGRect
.
Как многие из вас, вероятно, знают, CGPoint
— это структура C, которая определяет точку в системе координат. Источник этой системы координат находится вверху слева на iOS и внизу слева на OS X. Другими словами, ориентация ее вертикальной оси отличается на iOS и OS X.
CGSize
— это еще одна простая структура C, которая определяет ширину и значение высоты, а CGRect
имеет поле origin
, CGPoint
и поле size
, CGSize
. Вместе поля origin
и size
определяют положение и размер прямоугольника.
Ссылка CGGeometry также определяет другие типы, такие как CGFloat
и CGVector
. CGFloat
— это не что иное, как typedef
для float
или double
, в зависимости от архитектуры, на которой работает приложение, 32-битной или 64-битной.
2. Рамки и границы
Первое, что я хочу уточнить — это разница между frame
и его bounds
, потому что это то, что сбивает с толку многих начинающих разработчиков iOS. Разница не сложная, хотя.
В iOS и OS X приложение имеет несколько систем координат. Например, в iOS окно приложения располагается в системе координат экрана, а каждое подпредставление окна — в системе координат окна. Другими словами, подпредставления представления всегда расположены в системе координат представления.
Рамка
Как поясняется в документации, frame
вида — это структура, CGRect
, которая определяет размер вида и его положение в CGRect
вида, системе координат суперпредставления. Посмотрите на следующую диаграмму для пояснения.
Bounds
Свойство bounds
вида определяет размер вида и его положение в собственной системе координат вида. Это означает, что в большинстве случаев начало границ вида устанавливается на {0,0}
как показано на следующей диаграмме. Границы вида важны для рисования вида.
Когда свойство frame
вида изменяется, center
и / или bounds
вида также изменяются.
3. CGGeometry Ссылка
Удобные добытчики
Как я упоминал ранее, CGGeometry Reference представляет собой набор структур, констант и функций, которые облегчают работу с координатами и прямоугольниками. Возможно, вы столкнулись с фрагментами кода, подобными этому:
1
|
CGPoint point = CGPointMake(self.view.frame.origin.x + self.view.frame.size.width, self.view.frame.origin.y + self.view.frame.size.height);
|
Этот фрагмент не только труден для чтения, но и довольно многословен. Мы можем переписать этот фрагмент кода, используя две удобные функции, определенные в CGGeometry Reference.
1
2
|
CGRect frame = self.view.frame;
CGPoint point = CGPointMake(CGRectGetMaxX(frame), CGRectGetMaxY(frame));
|
Чтобы упростить приведенный выше фрагмент кода, мы сохраняем frame
в переменной с именем frame
и используем CGRectGetMaxX
и CGRectGetMaxY
. Названия функций не требуют пояснений.
Ссылка CGGeometry определяет функции для возврата наименьшего и наибольшего значений для x- и y-координат прямоугольника, а также x- и y-координат, которые лежат в центре прямоугольника. Две другие удобные функции получения — CGRectGetWidth
и CGRectGetHeight
.
Создание структур
Когда речь заходит о создании структур CGPoint
, CGSize
и CGRect
, большинство из нас использует CGPointMake
и его двоюродных братьев. Эти функции также определены в CGGeometry Reference. Хотя их реализация удивительно проста, они невероятно полезны и заставляют вас писать меньше кода. Например, вот как на самом деле реализован CGRectMake
:
1
2
3
4
5
6
7
|
CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
{
CGRect rect;
rect.origin.x = x;
rect.size.width = width;
return rect;
}
|
Модификация прямоугольников
Функции, которые мы рассмотрели до сих пор, довольно хорошо известны разработчикам iOS и помогают нам писать меньше кода, который будет более читабельным. Однако CGGeometry Reference также определяет ряд других функций, которые менее известны. Например, CGGeometry Reference определяет полдюжины функций для изменения структур CGRect
. Давайте посмотрим на некоторые из этих функций.
CGRectUnion
CGRectUnion
принимает две структуры CGRect
и возвращает наименьший возможный прямоугольник, который содержит оба прямоугольника. Это может показаться тривиальным, и я уверен, что вы можете легко выполнить ту же задачу с помощью нескольких строк кода, но CGGeometry — это всего лишь несколько десятков функций, которые делают ваш код чище и более читабельным.
Если вы добавите следующий фрагмент кода в метод viewDidLoad
контроллера представления, вы должны получить следующий результат в iOS Simulator. Серый прямоугольник является результатом использования CGRectUnion
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
// CGRectUnion
CGRect frame1 = CGRectMake(80.0, 100.0, 150.0, 240.0);
CGRect frame2 = CGRectMake(140.0, 240.0, 120.0, 120.0);
CGRect frame3 = CGRectUnion(frame1, frame2);
UIView *view1 = [[UIView alloc] initWithFrame:frame1];
[view1 setBackgroundColor:[UIColor redColor]];
UIView *view2 = [[UIView alloc] initWithFrame:frame2];
[view2 setBackgroundColor:[UIColor orangeColor]];
UIView *view3 = [[UIView alloc] initWithFrame:frame3];
[view3 setBackgroundColor:[UIColor grayColor]];
[self.view addSubview:view3];
[self.view addSubview:view2];
[self.view addSubview:view1];
|
CGRectDivide
Еще одна полезная функция — CGRectDivide
, которая позволяет разделить данный прямоугольник на два прямоугольника. Взгляните на следующий фрагмент кода и скриншот, чтобы увидеть, как он используется.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
// CGRectDivide
CGRect frame = CGRectMake(10.0, 50.0, 300.0, 300.0);
CGRect part1;
CGRect part2;
CGRectDivide(frame, &part1, &part2, 100.0, CGRectMaxYEdge);
UIView *view1 = [[UIView alloc] initWithFrame:frame];
[view1 setBackgroundColor:[UIColor grayColor]];
UIView *view2 = [[UIView alloc] initWithFrame:part1];
[view2 setBackgroundColor:[UIColor orangeColor]];
UIView *view3 = [[UIView alloc] initWithFrame:part2];
[view3 setBackgroundColor:[UIColor redColor]];
[self.view addSubview:view1];
[self.view addSubview:view2];
[self.view addSubview:view3];
|
Если бы вы рассчитывали красный и оранжевый прямоугольник без использования CGRectDivide
, вы бы CGRectDivide
несколько десятков строк кода. Попробуйте, если не верите мне.
Сравнение и ограничение
Сравнение геометрической структуры и проверка на членство очень легко с помощью следующих шести функций:
-
CGPointEqualToPoint
-
CGSizeEqualToSize
-
CGRectEqualToRect
-
CGRectIntersectsRect
-
CGRectContainsPoint
-
CGRectContainsRect
Ссылка CGGeometry имеет несколько других драгоценных камней, таких как CGPointCreateDictionaryRepresentation
для преобразования структуры CGPoint в CFDictionaryRef
и CGRectIsEmpty
чтобы проверить, CGRectIsEmpty
ли ширина и высота прямоугольника 0.0
. Прочитайте документацию CGGeometry Reference, чтобы узнать больше.
4. Бонус: логирование
Регистрация структур в консоли XCode громоздка без нескольких вспомогательных функций. К счастью, инфраструктура UIKit определяет несколько функций, которые делают это очень просто. Я использую их все время. Взгляните на следующий фрагмент кода, чтобы увидеть, как они работают. Это не ракетостроение.
1
2
3
4
|
CGPoint point = CGPointMake(10.0, 25.0);
CGSize size = CGSizeMake(103.0, 223.0);
CGRect frame = CGRectMake(point.x, point.y, size.width, size.height);
NSLog(@»\n%@\n%@\n%@», NSStringFromCGPoint(point), NSStringFromCGSize(size), NSStringFromCGRect(frame));
|
Существуют также вспомогательные функции для регистрации аффинных преобразований ( NSStringFromCGAffineTransform
), структур вставок ребер ( NSStringFromUIEdgeInsets
) и структур смещения ( NSStringFromUIOffset
).
Вывод
IOS SDK содержит множество драгоценных камней, о которых многие разработчики не знают. Я надеюсь, что убедил вас в полезности CGGeometry Reference . Как только вы начнете использовать его набор функций, вы удивитесь, как раньше обходились без него.