Android: scroll a ListView with volume keys
Scrolling a list view in an Android app using the volume buttons on the side of the phone is actually quite easy. Not knowing this, yesterday I spent some time looking for a nice easy tutorial to do this, and found nothing. Having it coded and released in version 1.0 of Quoter, I thought it’d be a good thing to write one myself.
Basically, what you need to do is to override the dispatchKeyEvent() method in your Activity, and intercept key presses for the volume keys, leaving the other keys untouched. This is how I did it, fairly straightforward:
@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);
}
Note that we only execute our code on the ACTION_DOWN event – the ACTION_UP event is only caught in order to mute the keypress sound. Then event.getKeyCode() is checked, and if the key pressed is volume up or volume down, my scrolling functions are called and the function returns. In any other case (another event or different keys) the execution is passed on to the standard key press handler.
Next are the scrolling functions to scroll the ListView. The problem with these is, you can scroll to any x/y coordinates using the scrollTo method. But what I needed is to scroll to the next visible item, since Quoter is a reading app and one wants to scroll to the next qoute in the list and read it. So this is what I did:
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();
}
First we get the list position of the first element visible on screen. If it’s already the last position in scroll direction, we do nothing. If it isn’t, we set the selection in the list to the next item; this automatically scrolls the list (same thing happens if you use the D-pad keys to navigate a list). The only problem now is, the list item becomes selected and highlighted, which we don’t want since we’re reading text from it. By clearing the focus from the list, we remove the selection. All done.
In English, please
Bitte, in Deutsch
По-русски, пожалуйста
Замечательно! Это то, что нужно, спасибо. Однако есть трабл…. при нажатии кнопки громкости воспроизводится системный противно-пищащий звук. Курю гугл в ожидании…
Спасибо за Ваш пример, но у меня есть замечание. Надо также обработать ACTION_UP и вернуть true, чтобы не было звука клавиши во время прокрутки. С Вашим кодом звук как раз появлялся. Проверялось на Incredible S.
Спасибо за подсказку, сейчас допишу пост.