Уже довольно давно работаю фрилансером и иногда беру пару-тройку простеньких проектов за $100-200 для разгрузки мозга. В этот раз клиент попросил использовать внешние кнопки регулировки громкости в iPhone. Проблема состояла в том, что встроенного API для внешних кнопок в iOS не существует: до недавних пор использование хардверных элементов устройства, отличное от системного поведения, было запрещено. Поэтому различные приложения типа «Camera+» и «Camera Pro» никак не могли донести подобный функционал до пользователя. Однако, по счастливой случайности, в iOS 5 разработчики Apple сами начали использовать подобный подход к интерфейсу: сделать фотографию в системном приложении камеры теперь можно, нажав на клавишу увеличения громкости.
Как реализовать подобное поведение внешних клавиш в своем приложении, смотрите под катом. Исходники прилагаются в конце статьи.
Немного погуглив о задаче, можно наткнуться на открытое решение RBVolumeButtons, которое открывает аудио сессию и начинает слушать изменение громкости. В моем случае, этот класс неприятно влиял на работу камеры: активировав новую аудио сессию, мы прерывали аудиосессию камеры. Я решил собрать свой велосипед, подойдя к процессу со слегка иной стороны; написать отдельный класс NKVolumeButtons, скрывающий в себе весь необходимый функционал.
После короткого разбора полетов я решил использовать класс MPMusicPlayer из встроенного фреймворка MediaPlayer. В этом класе есть два сиглтона музыкального плеера: один для приложения и второй системный, общий для всего телефона. Мы будем слушать изменения громкости музыкального плеера для нашего приложения. Для этого добавим в метод инициализации объекта NKVolumeButtons немного кода:
[[MPMusicPlayerController applicationMusicPlayer] addObserver:self forKeyPath:@"volume" options:NSKeyValueObservingOptionNew context:nil];
Все по канонам KVO: вместо собственного велосипеда мы используем старую добрую категорию, унаследованную от NSObject. Соответственно, нам нужен и обработчик события — когда параметр, который мы слушаем, изменится, нам нужно как-то принять эту информацию. Смело добавляем метод в NKVolumeButtons!
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { // Здесь мы можем проверить, тот ли keyPath мы получаем; но зачем? Ведь единственный параметр, который мы слушаем - это volume [self checkVolumeButtons]; } - (void)checkVolumeButtons { // 1 float currentVolume = [[MPMusicPlayerController applicationMusicPlayer] volume]; // 2 if (currentVolume > 0.5) { [self volumeUp]; } else if (currentVolume < 0.5) { [self volumeDown]; } // 3 [[MPMusicPlayerController applicationMusicPlayer] setVolume:0.5]; }
Разберем код по-порядку:
- Получаем текущую громкость приложения
- Проверяем, увеличилась ли громкость, или уменьшилась
- Возвращаем громкость к исходному значению
Что за исходное значение? Объясняю: если пользователь зашел в наше приложение, а громкость на нуле? Тогда нажатия клавиши уменьшения громкости не будут иметь смысла — ничего работать не будет. Поэтому с самого начала нам нужно установить громкость на определенном уровне, от которого и будем плясать. Параметр volume может принимать значения от 0 до 1, так что мы выберем середину — 0.5. Добавим следующий код в инициализацию объекта NKVolumeButtons:
[[MPMusicPlayerController applicationMusicPlayer] setVolume:0.5];
А теперь приступим к реализации методов volumeUp и volumeDown. Для удобства добавим два параметра классу NKVolumeButtons, доступных извне — upBlock и downBlock. Приведем файл NKVolumeButtons.h к следующему виду:
typedef void (^ButtonBlock)(); #import <Foundation/Foundation.h> @interface NKVolumeButtons : NSObject @property (nonatomic, copy) ButtonBlock upBlock; @property (nonatomic, copy) ButtonBlock downBlock; @end
Здесь мы просто в удобном ключе добавили возможность устанавливать извне блоки кода, которые будут вызываться при нажатии клавиш регулировки громкости. Не стоит забывать и о синтезации наших параметров. Добавьте следующее в имплементацию NKVolumeButtons:
@synthesize upBlock = _upBlock; @synthesize downBlock = _downBlock;
И, конечно же, вызов наших блоков в нужное время:
- (void)volumeUp { // Всегда нужно проверять, получилось ли задать нужные параметры if(self.upBlock) { self.upBlock(); } } - (void)volumeDown { // Всегда нужно проверять, получилось ли задать нужные параметры if(self.upBlock) { self.upBlock(); } }
А вот и еще одна проблемка! Каждый раз, когда мы изменяем громкость, на экране появляется индикатор громкости. Что же, воспользуемся готовым решением, которое уже было в RBVolumeButtons. На то он и opensource, чтобы помогать друг другу, не так ли? Добавьте следующий код в NKVolumeButtons.m:
// Прячем индикатор громкости CGRect frame = CGRectMake(0, -100, 10, 0); UIView *volumeView = [[MPVolumeView alloc] initWithFrame:frame]; [volumeView sizeToFit]; [[[[UIApplication sharedApplication] windows] objectAtIndex:0] addSubview:volumeView];
Вот и все! Нам остается только добавить этот класс в проект, инициализировать объект NKVolumeButtons и задать нужные блоки кода. Вот таким простым костылем решается проблема недостатка API внешних клавиш.
Спасибо за то, что дочитали до конца! Исходники доступны на гитхабе.
ссылка на оригинал статьи http://habrahabr.ru/post/182774/
Добавить комментарий