Статьи

Основы iOS: рамки, границы и CGGeometry

Работать со структурами CGPoint , CGSize и CGRect несложно, если вы привыкли к языку, который поддерживает синтаксис точки. Однако программное позиционирование видов или написание кода чертежа является многословным и может стать трудным для чтения.

В этом руководстве я хотел бы прояснить несколько неправильных представлений о фреймах и границах и познакомить вас с CGGeometry , набором структур, констант и функций, которые значительно упрощают работу с CGPoint , CGSize и CGRect .

Если вы новичок в разработке для 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-битной.

Первое, что я хочу уточнить — это разница между frame и его bounds , потому что это то, что сбивает с толку многих начинающих разработчиков iOS. Разница не сложная, хотя.

В iOS и OS X приложение имеет несколько систем координат. Например, в iOS окно приложения располагается в системе координат экрана, а каждое подпредставление окна — в системе координат окна. Другими словами, подпредставления представления всегда расположены в системе координат представления.

Как поясняется в документации, frame вида — это структура, CGRect , которая определяет размер вида и его положение в CGRect вида, системе координат суперпредставления. Посмотрите на следующую диаграмму для пояснения.

Свойство bounds вида определяет размер вида и его положение в собственной системе координат вида. Это означает, что в большинстве случаев начало границ вида устанавливается на {0,0} как показано на следующей диаграмме. Границы вида важны для рисования вида.

Когда свойство frame вида изменяется, center и / или bounds вида также изменяются.

Как я упоминал ранее, 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 принимает две структуры 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 , которая позволяет разделить данный прямоугольник на два прямоугольника. Взгляните на следующий фрагмент кода и скриншот, чтобы увидеть, как он используется.

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, чтобы узнать больше.

Регистрация структур в консоли 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 . Как только вы начнете использовать его набор функций, вы удивитесь, как раньше обходились без него.