I like the color filter suggestion in previous answers from @conjugatedirection and @Tomasz; However, I found that the code provided so far wasn't as easily applied as I expected.
First, it wasn't mentioned where to apply and clear the color filter. It's possible that there are other good places to do this, but what came to mind for me was an OnTouchListener.
From my reading of the original question, the ideal solution would be one that does not involve any images. The accepted answer using custom_button.xml from @emmby is probably a better fit than color filters if that's your goal. In my case, I'm starting with a png image from a UI designer of what the button is supposed to look like. If I set the button background to this image, the default highlight feedback is lost completely. This code replaces that behavior with a programmatic darkening effect.
button.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 0x6D6D6D sets how much to darken - tweak as desired
setColorFilter(v, 0x6D6D6D);
break;
// remove the filter when moving off the button
// the same way a selector implementation would
case MotionEvent.ACTION_MOVE:
Rect r = new Rect();
v.getLocalVisibleRect(r);
if (!r.contains((int) event.getX(), (int) event.getY())) {
setColorFilter(v, null);
}
break;
case MotionEvent.ACTION_OUTSIDE:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
setColorFilter(v, null);
break;
}
return false;
}
private void setColorFilter(View v, Integer filter) {
if (filter == null) v.getBackground().clearColorFilter();
else {
// To lighten instead of darken, try this:
// LightingColorFilter lighten = new LightingColorFilter(0xFFFFFF, filter);
LightingColorFilter darken = new LightingColorFilter(filter, 0x000000);
v.getBackground().setColorFilter(darken);
}
// required on Android 2.3.7 for filter change to take effect (but not on 4.0.4)
v.getBackground().invalidateSelf();
}
});
I extracted this as a separate class for application to multiple buttons - shown as anonymous inner class just to get the idea.