Android: прокрутка ListView клавишами громкости

24.02.2011
Olexandr Savchuk

Прокрутка списка кнопками громкости в приложениях на Андроиде нa самом деле не является чем-то сложным. Не зная этого, вчера я потратил какое-то время в поисках хорошего руководства на эту тему. Написав код и опубликовав Quoter в версии 1.0, я решил сам написать небольшую заметку об этом.

Итак, что нам нужно сделать, это переписать метод dispatchKeyEvent() в нашей Activity, и таким образом перехватить нажатия кнопок громкости.

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
	if (event.getAction() == KeyEvent.ACTION_DOWN) {
		switch (event.getKeyCode()) {
		case KeyEvent.KEYCODE_VOLUME_UP:
			scrollToPrevious();
			return true;
		case KeyEvent.KEYCODE_VOLUME_DOWN:
			scrollToNext();
			return true;
		}
	}
	if (event.getAction() == KeyEvent.ACTION_UP
		&& (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP
			|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN)) {
		return true;
	}
	return super.dispatchKeyEvent(event);
}

Наш код выполняется только на событии нажатия клавиш (ACTION_DOWN). Событие ACTION_UP перехватывается для того, чтобы предотвратить системный звук нажатия клавиши. Также проверяется event.getKeyCode(), и если нажата одна из нужных клавиш, вызываются соответствующие функции. В других случаях (другие события или клавиши) событие передается стандартному обработчику.

Теперь остались только собственно функции прокрутки ListView. Проблема с ними вот в чем. Можно прокрутить список в любую точку с помощью метода scrollTo(), но нам нужно перейти не к координатам, а к конкретному элементу списка – Quoter есть приложение для чтения, и читатель хочет перейти к следующей цитате. Вот что мы для этого можем сделать:

private void scrollToNext() {
	int currentPosition = getListView().getFirstVisiblePosition();
	if (currentPosition == getListView().getCount() - 1)
		return;
	getListView().setSelection(currentPosition + 1);
	getListView().clearFocus();
}

private void scrollToPrevious() {
	int currentPosition = getListView().getFirstVisiblePosition();
	if (currentPosition == 0)
		return;
	getListView().setSelection(currentPosition - 1);
	getListView().clearFocus();
}

Вначале определяем позицию в списке первого видимого на экране элемента. Если это уже последний элемент в нужном направлении, ничего не делаем. В другом случае выставляем выбранный элемент списка на следующую позицию, при этом список прокручивается куда надо автоматически (как при навигации стрелками на клавиатуре). Единственная оставшаяся проблема: при выделении элемента списка он подсвечивается, что мешает читать. Снимаем выделение, убрав фокус со списка. Готово.

Комментарии (3) Комментировать →
  1. 25.05.2011 25.05.2011
    lecovich permalink

    Замечательно! Это то, что нужно, спасибо. Однако есть трабл…. при нажатии кнопки громкости воспроизводится системный противно-пищащий звук. Курю гугл в ожидании…

  2. 28.05.2011 28.05.2011
    Андрей permalink

    Спасибо за Ваш пример, но у меня есть замечание. Надо также обработать ACTION_UP и вернуть true, чтобы не было звука клавиши во время прокрутки. С Вашим кодом звук как раз появлялся. Проверялось на Incredible S.

  3. 29.05.2011 29.05.2011

    Спасибо за подсказку, сейчас допишу пост.

Leave a Reply