Книга: iOS. Приемы программирования
Обсуждение
Обсуждение
Распознаватель жестов UIRotationGestureRecognizer, как понятно из его названия, отлично подходит для распознавания жестов вращения и помогает делать пользовательские интерфейсы значительно более интуитивно понятными. Например, если пользователь работает с устройством в полноэкранном режиме и встречает на экране какое-то изображение, ориентация которого не соответствует ориентации экрана, то вполне логично, что он попытается подправить картинку, повернув ее на дисплее.
Класс UIRotationGestureRecognizer реализует свойство rotation, указывающее степень и направление вращения, заданного жестом пользователя. Эти показатели выражаются в радианах. Вращение определяется в зависимости от исходного положения пальцев (UIGestureRecognizerStateBegan) и их конечного положения (UIGestureRecognizerStateEnded).
Чтобы вращать элементы пользовательского интерфейса, наследующие от класса UIView, можно передать свойство rotation распознавателя жестов вращения функции CGAffineTransformMakeRotation, чтобы она выполнила аффинное преобразование, как показано в следующем примере.
Код, приведенный в подразделе «Решение» данного раздела, передает актуальный объект (в данном случае контроллер вида) к цели распознавателя жестов вращения. Целевой селектор задается как handleRotations: — метод, который мы хотим реализовать. Но прежде, чем приступить к этому, изучим заголовочный файл контроллера вида:
#import «ViewController.h»
@interface ViewController ()
@property (nonatomic, strong)
UIRotationGestureRecognizer *rotationGestureRecognizer;
@property (nonatomic, strong)
UILabel *helloWorldLabel;
/* Из этого объявления свойства можно удалить метки nonatomic
и unsafe_unretained. Имея значение с плавающей точкой, компилятор
автоматически сгенерирует для нас обе эти метки. */
@property (nonatomic, unsafe_unretained)
CGFloat rotationAngleInRadians;
@end
@implementation ViewController
Прежде чем продолжать, рассмотрим, за что отвечает каждое из этих свойств и почему они объявляются:
• helloWorldLabel — это метка, которую мы должны поставить на виде в контроллере вида. Потом напишем код для вращения этой метки. Вращение будет начинаться всякий раз, когда пользователь станет совершать вращательные жесты на виде, обладающем этой меткой (в данном случае речь идет о виде нашего контроллера вида);
• rotationGestureRecognizer — это экземпляр распознавателя жестов вращения, который мы позже выделим и инициализируем;
• rotationAngleInRadians — это значение, которое будет запрашиваться как точный угол поворота метки. Изначально это свойство устанавливается в нуль. Поскольку углы вращения, сообщаемые распознавателем, сбрасываются перед каждым новым пуском распознавателя, можно всякий раз сохранять значение распознавателя жестов вращения, когда он переходит в состояние UIGestureRecognizerStateEnded. В следующий раз при запуске жеста мы суммируем предыдущее значение вращения и новое значение вращения, получив в результате общий угол вращения.
Размер метки и ее центральная точка могут выбираться произвольно. Аналогично непринципиально и положение самой метки, так как мы просто пытаемся вращать метку вокруг ее центра независимо от того, в какой части вида она расположена. Единственный важный аспект здесь заключается в том, что в универсальных приложениях положение метки в контроллере вида следует рассчитывать динамически при работе с разными целями (то есть устройствами), основываясь на размерах ее родительского вида. Если приложение запускается на иных устройствах, кроме iPhone и iPad, метка может оказываться в различных точках экрана.
Применяя свойство метки center и устанавливая эту точку в центре объемлющего вида, мы выравниваем по центру и содержимое самой метки. Преобразование вращения, которое мы применим к данной метке, станет вращать метку вокруг ее центральной точки. А если содержимое метки выровнено по левому или по правому краю и ее истинный контур шире, чем пространство, необходимое для полного отображения содержимого (без отсечения), то вращаться такая метка будет довольно неестественно и не вокруг центра. Если вам любопытно, как это выглядит на практике, попробуйте выровнять содержимое метки по левому или правому краю и посмотрите, что получится.
Как показано в подразделе «Решение» данного раздела, созданный нами распознаватель жестов вращения будет отправлять свои события методу handleRotations:. Вот реализация этого метода:
— (void) handleRotations:(UIRotationGestureRecognizer *)paramSender{
if (self.helloWorldLabel == nil){
return;
}
/* Берем предыдущее значение вращения и суммируем его с актуальным
значением вращения. */
self.helloWorldLabel.transform =
CGAffineTransformMakeRotation(self.rotationAngleInRadians +
paramSender.rotation);
/* Когда значение завершится, сохраняем полученный угол для
дальнейшего использования. */
if (paramSender.state == UIGestureRecognizerStateEnded){
self.rotationAngleInRadians += paramSender.rotation;
}
}
Распознаватель жестов вращения посылает нам информацию об углах вращения очень интересным способом. Этот распознаватель является непрерывным. Это означает, что распознаватель приступает к вычислению углов, как только пользователь начинает жест вращения, и отправляет обновления методу-обработчику с краткими интервалами до тех пор, пока пользователь не закончит жест. В каждом сообщении начальный угол воспринимается как нулевой, и это сообщение содержит информацию о начальной точке вращения (достигнутой после окончания предыдущего акта вращения) и конечной точке. Таким образом, полный эффект от данного жеста можно узнать, только суммировав значения углов, полученные в результате различных событий. Движение по часовой стрелке дает положительное угловое значение, а против часовой стрелки — отрицательное.
Если вы работаете с симулятором iPhone, а не с реальным устройством, то можете имитировать и вращательное движение. Для этого нужно просто удерживать клавишу Option. В симуляторе вы увидите два кружка, которые появятся на одинаковом расстоянии от центра экрана. Они будут соответствовать подушечкам двух пальцев. Если вы захотите переместить «пальцы» из центра в другую точку экрана, то нужно нажать клавишу Shift, удерживая Alt, и перейти в желаемую точку. Когда вы отпустите указатель, новая точка станет центром для двух подушечек пальцев.
Теперь мы просто присвоим этот угол углу вращения метки. Но вы можете представить, что произойдет, когда одно вращение закончится, а другое начнется? Угол второго вращательного жеста заменит первое вращение в значении rotation и будет сообщен обработчику. Поэтому, как только вращательный жест завершится, необходимо сохранить текущее вращательное значение метки. Угловое значение, получаемое в результате каждого вращательного движения, должно суммироваться с предыдущими по очереди. Ранее было показано, как этот результат присваивается общему вращательному преобразованию метки.
Кроме того, прежде мы говорили о применении функции CGAffineTransformMakeRotation для создания аффинного преобразования. Функции iOS SDK, названия которых начинаются на CG, относятся к фреймворку Core Graphics. Чтобы в программах, использующих Core Graphics, успешно протекали процессы компиляции и связывания, необходимо убедиться, что Core Graphics добавлен в список фреймворков. В новых версиях Xcode стандартный проект автоматически связывается с фреймворком Core Graphics, так что об этом можно не беспокоиться.
Теперь, когда вы уверены, что фреймворк Core Graphics добавлен к целевой сборке, можно скомпилировать и запустить приложение.