Читать книгу iOS. Приемы программирования - Вандад Нахавандипур - Страница 60

Глава 2. Создание динамических и интерактивных пользовательских интерфейсов
2.3. Анимирование компонентов пользовательского интерфейса с помощью толчков

Оглавление

Постановка задачи

Требуется визуально перебрасывать виды с одного места на экране на другое.

Решение

Инициализируйте объект поведения типа UIPushBehavior с помощью относящегося к нему метода initWithItems: mode: и передайте ему значение UIPushBehaviorModeContinuous. Как только будете готовы толкать элементы под углом, вызовите для толчка метод setAngle:. Этот метод задает угол (в радианах) для данного поведения. Затем потребуется установить магнитуду, то есть силу толчка. Эта величина задается с помощью относящегося к толчку поведения setMagnitude:. Магнитуда рассчитывается следующим образом: магнитуда величиной 1 точка соответствует ускорению 100 точек/с2, прилагаемому к целевым видам.

Обсуждение

Толчки, прилагаемые к экранным элементам, очень полезны – особенно толчки, вызывающие непрерывное движение. Допустим, вы разрабатываете приложение-фотоальбом для iPad. В верхней части экрана создали три слайда, каждый из которых соответствует странице альбома, созданной пользователем. В нижней части экрана располагаются различные картинки, которые пользователь может перетаскивать и раскладывать на страницах. Один из способов, позволяющих реализовать для пользователя такую возможность, – добавление к опорному виду регистратора жестов касания (tap gesture recognizer), создание которого рассмотрено в разделе 10.5. Этот регистратор обеспечивает отслеживание пользовательских жестов касания и позволяет перемещать изображения на целевой слайд. Процесс выглядит как перетаскивание. Другой, пожалуй, более оптимальный способ решения этой задачи – использование толчкового поведения, которое разработчики Apple включили в UIKit.

Толчковое поведение относится к типу UIPushBehavior и обладает магнитудой и углом. Угол измеряется в радианах, а магнитуда в 1 точку приводит к ускорению движения, равному 100 точек/с2. Толчковые поведения создаются точно так же, как и любые другие: сначала их необходимо инициализировать, а потом добавить к аниматору типа UIDynamicAnimator.

В этом примере мы собираемся создать вид и поместить его в центре более крупного вида контроллера. Мы подключим к аниматору поведение столкновений, благодаря чему маленький вид не будет вылетать за пределы большого вида (с контроллером). О том, как работать со столкновениями, мы поговорили в разделе 2.2. Затем добавим регистратор жестов касания (см. раздел 10.5) к контроллеру вида. Этот регистратор будет уведомлять нас о каждом жесте касания, произошедшем на экране.

Когда касание будет зарегистрировано, рассчитаем угол между точкой касания и центром маленького квадратного вида. Так мы получим угол, выраженный в радианах, под которым сможем толкнуть этот квадратный вид. Затем рассчитаем расстояние между точкой касания и центром маленького вида, полученное значение используем в качестве магнитуды толчка. Таким образом, магнитуда будет тем больше, чем дальше от центра квадратного вида находится точка касания.

В данном разделе предполагается, что читатель понимает основы тригонометрии. Но даже если вы с ними не знакомы – ничего страшного, поскольку для работы потребуются лишь те формулы, которые я описываю в примерах кода к этому разделу. На рис. 2.2 показано, как вычисляется угол между двумя точками. Итак, я надеюсь, что объяснение получится достаточно подробным, чтобы вы могли написать собственное решение данной проблемы.


Рис. 2.2. Расчет угла между двумя точками


Итак, начнем с определения всех важных свойств нашего контроллера вида:


#import "ViewController.h"


@interface ViewController ()

@property (nonatomic, strong) UIView *squareView;

@property (nonatomic, strong) UIDynamicAnimator *animator;

@property (nonatomic, strong) UIPushBehavior *pushBehavior;

@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.view addSubview: self.squareView];

}

Затем применим регистратор жестов касания, чтобы обнаруживать прикосновения к виду с контроллером:

– (void) createGestureRecognizer{

UITapGestureRecognizer *tapGestureRecognizer =

[[UITapGestureRecognizer alloc] initWithTarget: self

action:@selector(handleTap:)];

[self.view addGestureRecognizer: tapGestureRecognizer];

}

Эти методы выполняют за нас всю необходимую работу. Позже, когда вид отобразится на экране, мы будем вызывать эти методы и они будут действовать.

И не забудем написать метод, который будет задавать поведение столкновения и толчковое поведение:


– (void) createAnimatorAndBehaviors{

self.animator = [[UIDynamicAnimator alloc]

initWithReferenceView: self.view];


/* Создаем обнаружение столкновений */

UICollisionBehavior *collision = [[UICollisionBehavior alloc]

initWithItems:@[self.squareView]];

collision.translatesReferenceBoundsIntoBoundary = YES;


self.pushBehavior = [[UIPushBehavior alloc]

initWithItems:@[self.squareView]

mode: UIPushBehaviorModeContinuous];


[self.animator addBehavior: collision];

[self.animator addBehavior: self.pushBehavior];

}


Подробнее о поведении столкновений рассказано в разделе 2.2. Как только мы запрограммируем все эти методы, нам понадобится вызывать их, когда вид появится на экране:


– (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.

iOS. Приемы программирования

Подняться наверх