iOS. Приемы программирования - Вандад Нахавандипур
Шрифт:
Интервал:
Закладка:
— (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear: animated];
[self createGestureRecognizer];
[self createSmallSquareView];
[self createAnimatorAndBehaviors];
}
Отлично. Теперь, взглянув на файл реализации метода createGestureRecognizer, вы увидите, что мы устанавливаем регистратор жестов касаний в методе контроллера вида — этот метод называется handleTap:. В методе handleTap: вычисляем расстояние между центральной точкой маленького квадратного вида и той точкой опорного вида, до которой дотронулся пользователь. В результате имеем магнитуду силы толчка. Кроме того, рассчитаем угол между центром маленького квадратного вида и точкой касания, чтобы определить угол толчка:
— (void) handleTap:(UITapGestureRecognizer *)paramTap{
/* Получаем угол между центральной точкой квадратного вида и точкой касания */
CGPoint tapPoint = [paramTap locationInView: self.view];
CGPoint squareViewCenterPoint = self.squareView.center;
/* Вычисляем угол между центральной точкой квадратного вида и точкой касания, чтобы определить угол толчка
Формула для определения угла между двумя точками:
arc tangent 2((p1.x — p2.x), (p1.y — p2.y)) */
CGFloat deltaX = tapPoint.x — squareViewCenterPoint.x;
CGFloat deltaY = tapPoint.y — squareViewCenterPoint.y;
CGFloat angle = atan2(deltaY, deltaX);
[self.pushBehavior setAngle: angle];
/* Используем расстояние между точкой касания и центром квадратного вида для вычисления магнитуды толчка
Формула определения расстояния:
Квадратный корень из ((p1.x — p2.x)^2 + (p1.y — p2.y)^2) */
CGFloat distanceBetweenPoints =
sqrt(pow(tapPoint.x — squareViewCenterPoint.x, 2.0) +
pow(tapPoint.y — squareViewCenterPoint.y, 2.0));
[self.pushBehavior setMagnitude: distanceBetweenPoints / 200.0f];
}
Не буду чрезмерно углубляться в тригонометрию, но в этом коде используется простая формула, изучаемая в школьном курсе. По этой формуле рассчитывается угол в радианах между двумя точками. Также применяется теорема Пифагора, позволяющая узнать расстояние между двумя точками. Эти формулы вы найдете, взглянув на комментарии, которые я оставил в коде. Если же хотите подробнее разобраться с такими понятиями, как углы и радианы, рекомендую проштудировать учебник по тригонометрии.
Теперь, запустив приложение, вы сначала увидите маленький зеленый квадрат в центре экрана. Дотроньтесь до экрана в любой точке поля, окружающего квадрат (белое пространство), чтобы зеленый квадрат (вид) стал двигаться. В данном примере я беру расстояние между точкой касания и центром квадрата и делю его на 200, чтобы получить реалистичную магнитуду толчка, но вы в данном примере можете увеличить ускорение, выбрав, скажем, значение 100, а не 200. Всегда лучше экспериментировать с разными числовыми значениями, чтобы подобрать оптимальный вариант для вашего приложения.
См. также
Раздел 2.2.
2.4. Прикрепление нескольких динамических элементов друг к другу
Постановка задачи
Требуется прикреплять друг к другу динамические элементы, например виды, так, чтобы движения одного вида автоматически приводили в движение второй. В качестве альтернативы можно прикреплять динамический элемент к точке привязки, чтобы при движении этой точки (в результате действий приложения или пользователя) этот элемент автоматически перемещался вместе с ней.
Решение
Инстанцируйте поведение прикрепления, относящееся к типу UIAttachmentBehavior, с помощью метода экземпляра initWithItem: point: attachedToAnchor: этого класса. Добавьте это поведение к аниматору (см. раздел 2.0), отвечающему за динамику и физику движения.
Обсуждение
На первый взгляд поведение прикрепления может показаться непонятным. Оно сводится к следующему: вы можете задать на экране точку привязки, а затем заставить точку следовать за этой привязкой. Но я хотел бы обсудить эту возможность подробнее.
Допустим, у вас на столе лежит большая фотография. Если вы поставите указательный палец в верхний правый угол фотографии и начнете совершать им вращательные движения, то фотография, возможно, также будет вертеться на столе вместе с вашим пальцем. Такое же реалистичное поведение вы можете создать и в iOS, воспользовавшись поведением прикрепления из UIKit.
В этом примере мы собираемся создать такой эффект, который продемонстрирован на рис. 2.3.
Рис. 2.3. Именно такого эффекта мы хотим добиться в данном разделе с помощью поведения прикрепления
Как видите, на экране находятся три вида. Основной вид расположен в центре, в правом верхнем углу этого вида есть еще один вид, более мелкий. Маленький вид — это и есть тот элемент, который будет следовать за точкой привязки, по принципу, который я описал в примере с фотографией. Наконец, необходимо отметить, что точка привязки в данном примере будет перемещаться по экрану под действием жеста панорамирования и регистратора соответствующих жестов (см. раздел 10.3). Затем в результате таких движений станет двигаться большой вид, расположенный в центре экрана. Итак, начнем с определения необходимых свойств контроллера вида:
#import «ViewController.h»
@interface ViewController ()
@property (nonatomic, strong) UIView *squareView;
@property (nonatomic, strong) UIView *squareViewAnchorView;
@property (nonatomic, strong) UIView *anchorView;
@property (nonatomic, strong) UIDynamicAnimator *animator;
@property (nonatomic, strong) UIAttachmentBehavior *attachmentBehavior;
@end
@implementation ViewController
<# Оставшаяся часть кода контроллера вида находится здесь #>
Далее нам потребуется создать маленький квадратный вид. Но на этот раз мы поместим внутрь него еще один вид. Маленький вид, который будет располагаться в правом верхнем углу родительского вида, мы фактически соединим с точкой привязки поведения прикрепления, как было показано в примере с фотографией:
— (void) createSmallSquareView{
self.squareView =
[[UIView alloc] initWithFrame:
CGRectMake(0.0f, 0.0f, 80.0f, 80.0f)];
self.squareView.backgroundColor = [UIColor greenColor];
self.squareView.center = self.view.center;
self.squareViewAnchorView = [[UIView alloc] initWithFrame:
CGRectMake(60.0f, 0.0f, 20.0f, 20.0f)];
self.squareViewAnchorView.backgroundColor = [UIColor brownColor];
[self.squareView addSubview: self.squareViewAnchorView];
[self.view addSubview: self.squareView];
}
Далее создадим вид с точкой привязки:
— (void) createAnchorView{
self.anchorView = [[UIView alloc] initWithFrame:
CGRectMake(120.0f, 120.0f, 20.0f, 20.0f)];
self.anchorView.backgroundColor = [UIColor redColor];
[self.view addSubview: self.anchorView];
}
После этого потребуется создать регистратор жестов панорамирования и аниматор, как мы уже делали в предыдущих разделах этой главы:
— (void) createGestureRecognizer{
UIPanGestureRecognizer *panGestureRecognizer =
[[UIPanGestureRecognizer alloc] initWithTarget: self
action:@selector(handlePan:)];
[self.view addGestureRecognizer: panGestureRecognizer];
}
— (void) createAnimatorAndBehaviors{
self.animator = [[UIDynamicAnimator alloc]
initWithReferenceView: self.view];
/* Создаем распознавание столкновений */
UICollisionBehavior *collision = [[UICollisionBehavior alloc]
initWithItems:@[self.squareView]];
collision.translatesReferenceBoundsIntoBoundary = YES;
self.attachmentBehavior = [[UIAttachmentBehavior alloc]
initWithItem: self.squareView
point: self.squareViewAnchorView.center
attachedToAnchor: self.anchorView.center];
[self.animator addBehavior: collision];
[self.animator addBehavior: self.attachmentBehavior];
}
— (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear: animated];
[self createGestureRecognizer];
[self createSmallSquareView];
[self createAnchorView];
[self createAnimatorAndBehaviors];
}
Как видите, мы реализуем поведение привязки с помощью его метода экземпляра initWithItem: point: attachedToAnchor:. Этот метод принимает следующие параметры:
• initWithItem — динамический элемент (в нашем примере — вид), который должен быть подключен к точке привязки;
• point — точка внутри динамического элемента, которая должна быть соединена с точкой привязки. В данном поведении центральная точка элемента используется для установки соединения с точкой привязки. Но вы можете изменить этот параметр, присвоив ему другое значение;
• attachedToAnchor — сама точка привязки, измеряемая как значение CGPoint.
Теперь, когда мы соединили верхний правый угол квадратного вида с точкой привязки (представленной как вид точки привязки), необходимо продемонстрировать, что, двигая точку привязки, мы опосредованно будем двигать и квадратный вид. Вернемся к методу createGestureRecognizer, написанному ранее. Там мы задействовали регистратор жестов касания, который будет отслеживать движение пальца пользователя по экрану. Мы решили обрабатывать регистратор жестов в методе handlePan: вида и реализуем этот метод так: