Одной из самых "вкусных” функциональностей, которые предоставляет iPhone/iPod Touch, безусловно является акселерометр. Его реализация в устройствах от Apple не первая в мире — попытки внедрения модуля определения положения аппарата были и раньше, например, в телефонах от Sony Ericsson и Nokia, но действительно удачное применение удалось найти именно Apple, сделав акселерометр одной из главных отличительных черт своих телефонов и плееров.
В этот раз начну свою статью необычно — с видео, в котором продемонстрирую в действии приложение, созданием которого мы займемся в этом посте.
Как и большинство классов, с которыми нам довелось познакомиться, API акселерометра прост до безобразия. Для его использования в своих программах нужно быть знакомым всего с двумя классами и одним делегатом. Но прежде чем приступить к знакомству с ними, создайте новый проект на основе шаблона "Window based application” в XCode. Я назвал его "accelerometer”.
Хочу заранее предупредить, что без сертификата разработчика попробовать в действии это приложение вам не удастся, как и любые примеры с сайта developer.apple.com, работающие с информацией о положении аппарата в пространстве, так как в симуляторе нет возможности эмулировать вращение устройства. Но информации в статье достаточно, чтобы составить представление о функционировании акселерометра, знания о работе с которым пригодятся вам в будущем и позволят писать приложения, использующие его функциональность, уже сейчас.
Первым делом нам потребуется создать в нашей программе Table View и заполнить его буквами алфавита. Для этих целей воспользуемся готовым объектом UITableViewController, который немного упростит нам дальнейшую работу с таблицей. Для тех, кто еще не был знаком с UITableView, отправляю к статье Вездесущий UITableView, а остальные откройте MainWindow.xib и добавьте на форму объект UITableViewController.
dataSource и delegate для нашей таблицы автоматически установлены на объект UITableViewController. Чтобы описать методы, ответственные за наполнение таблицы данными, измените класс UITableViewController на tableViewController, сгенерируйте файлы класса и включите их в состав проекта.
Чтобы наша таблица отображалась в окне приложение, добавьте outlet переменную viewController класса tableViewController в класс accelerometerAppDelegate, и свяжите ее с объектом tableViewController на форме через Interface Builder. А в методе applicationDidFinishLaunching: добавьте следующую строчку:
[window addSubview:viewController.view];
Специально не описываю подробности всего процесса, так как уже неоднократно освещал эти вопросы в предыдущих статьях. В случае появления трудностей взгляните в исходный код проекта, приложенного в конце статьи.
В accelerometerAppDelegate.h объявите переменную list класса NSMutableArray, в которую мы поместим сгенерированный нами алфавит. В этом нам поможет метод stringWithFormat класса NSString, в котором мы будем формировать символы по кодам из нижней части ACSII таблицы. Код поместим во все тот же applicationDidFinishLaunching:.
list = [[NSMutableArray alloc] init];
for (int i = 65; i < 65+26; i++) {
[list addObject:[NSString stringWithFormat:@"%c", i]];
}
Не забудьте освободить переменную list в dealloc.
Нам осталось сформировать код, ответственный за заполнение таблицы данными. Подробно останавливаться на нем не буду, лишь приведу исходный текст tableViewController.m.
Теперь, когда подготовительная фаза завершена, мы можем приступить к знакомству с акселерометром. Но прежде немного теории.
Акселерометр — устройство, измеряющее проекцию силы тяжести. С его помощью можно также установить величину ускорения аппарата под действием внешних сил. Для получения информации о величине и направлении ускорения используются значения проекций на оси координат.
* изображение взято с сайта http://www.forestgumpsays.com/?p=42
В состоянии покоя, когда устройство не двигается, величина замеряемого ускорения равна силе тяжести и принята за единицу. Соотношения величин проекций этой силы на оси координат дают нам углы поворота устройства в пространстве. Если iPhone находится в движении, то величину ускорения, с которым разгоняется аппарат, можно посредством дополнительных преобразований вычислить на основе значений проекций.
Заметьте, это именно ускорение, а не скорость движения устройства. То есть, если ваш iPhone начнет падать на землю, то проекции величины ускорения примут значение 0 по всем осям — ваш iPhone будет в невесомости :) А если вы поднимаетесь с должным ускорением на лифте вверх, то значение силы тяжести на время ускорения увеличится.
Чтобы было понятнее, пользуясь значением по оси Z можно определить в каком положении находится аппарат: лицом вверх (-1, при нулевых значениях по другим осям), в вертикальном положении (0) или лицом вниз (+1).
Ось Y дает нам следующую информацию: iPhone находится в вертикальном положении (-1), лежит в горизонтальной плоскости (0) или находится в вертикальном положении, только вверх ногами (+1).
И, наконец, ось X дает информацию о повороте аппарата влево (-1) или вправо (+1).
Для случая произвольной ориентации iPhone данные о величине ускорения распределяются по осям согласно проекции вектора ускорения.
Всю эту информацию аккумулирует объект класса UIAcceleration, возвращающий данные по всем осям, а также временной маркер, позволяющий определить относительное время замера указанных величин. Напрямую подступиться к данным этого класса нельзя, эту информацию можно получить только через делегат UIAccelerometerDelegate, предоставляющего для реализации один единственный метод accelerometer:didAccelerate:, в который возвращается объект класса UIAcceleration. Назначение делегата и инициализация вызовов метода accelerometer:didAccelerate: происходит при помощи класса UIAccelerometer. Пришло время написать код, реализующий описанный алгоритм.
В метод applicationDidFinishLaunching: добавьте следующие строки.
Первая назначает интервал в секундах, с которым будут посылаться данные от акселерометра в класс-делегат, назначенный в следующей строке. В заголовочном файле класса accelerometerAppDelegate укажите протокол UIAccelerometerDelegate.
Но что же мы должны в нем написать, чтобы реализовать прокрутку списка? Возьмем за точку отсчета положение нашего устройства в пространстве, при котором угол между задней стенкой и землей составляет 45 градусов. В этом случае проекции силы тяжести на ось Y будет составлять -0.7. Если мы отклоняем аппарат чуть ближе к вертикальному положению, то примем, что при достижении угла в 30 градусов от вертикали мы должны перелистнуть список к концу. И наоборот, при достижении угла в 30 и менее градусов от горизонтального положения, мы должны перелистнуть список к началу.
В первом случае абсолютная величина проекции силы тяжести на ось Y, направленная вдоль аппарата, станет равна 0.86. Те, кто не понял откуда взялось это значение, вспоминаем геометрию и вычисление проекции на ось координат вектора единичной длины. Во втором случае это же значение равно 0.5. Для реализации прокрутки мы воспользуемся методом scrollToRowAtIndexPath:atScrollPosition:animated: класса UITableView.