In Android, when I set background image to Button, I can not see any effect on button.
I need some effect on button so user can recognize that button is clicked.
This can be achieved by creating a drawable xml file containing a list of states for the button. So for example if you create a new xml file called "button.xml" with the following code:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:state_pressed="false" android:drawable="@drawable/YOURIMAGE" />
<item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/gradient" />
<item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/gradient" />
<item android:drawable="@drawable/YOURIMAGE" />
</selector>
To keep the background image with a darkened appearance on press, create a second xml file and call it gradient.xml with the following code:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<bitmap android:src="@drawable/YOURIMAGE"/>
</item>
<item>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient android:angle="90" android:startColor="#880f0f10" android:centerColor="#880d0d0f" android:endColor="#885d5d5e"/>
</shape>
</item>
</layer-list>
In the xml of your button set the background to be the button xml e.g.
android:background="@drawable/button"
Hope this helps!
Edit: Changed the above code to show an image (YOURIMAGE) in the button as opposed to a block colour.
Use RippleDrawable for Material Design state pressed/clicked effect.
In order to achieve this, create ripple item as an .xml under /drawable folder and use it in android:background for any views.
Effect for icon pressed/clicked, use circular ripple effect, for example:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@android:color/darker_gray"
/>
Effect for view clicked with rectangle boundary, we can add ripple over the existing drawable like bellow:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#000000">
<item android:drawable="@drawable/your_background_drawable"/>
</ripple>
You can simply use foreground for your View
to achieve clickable effect:
android:foreground="?android:attr/selectableItemBackground"
For use with dark theme add also theme to your layout
(to clickable effect be clear):
android:theme="@android:style/ThemeOverlay.Material.Dark"
just wanna add another easy way to do this: If your ImageButton remains its background and you don't set it to null, it will work like a normal button and will show the click animation while clicking exactly like other buttons.The way to hide the background while it is still there:
<ImageButton
android:id="@+id/imageButton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="1dp"
android:paddingLeft="1dp"
android:paddingRight="1dp"
android:paddingTop="1dp"
android:src="@drawable/squareicon" />
The paddings won't let the background be visible and make the button act like other buttons.
It is simpler when you have a lot of image buttons, and you don't want to write xml-s for every button.
Kotlin Version:
fun buttonEffect(button: View) {
button.setOnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
v.background.setColorFilter(-0x1f0b8adf, PorterDuff.Mode.SRC_ATOP)
v.invalidate()
}
MotionEvent.ACTION_UP -> {
v.background.clearColorFilter()
v.invalidate()
}
}
false
}
}
Java Version:
public static void buttonEffect(View button){
button.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
v.invalidate();
break;
}
case MotionEvent.ACTION_UP: {
v.getBackground().clearColorFilter();
v.invalidate();
break;
}
}
return false;
}
});
}
Making a minor addition to Andràs answer:
You can use postDelayed
to make the color filter last for a small period of time to make it more noticeable:
@Override
public boolean onTouch(final View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
v.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
v.invalidate();
break;
}
case MotionEvent.ACTION_UP: {
v.postDelayed(new Runnable() {
@Override
public void run() {
v.getBackground().clearColorFilter();
v.invalidate();
}
}, 100L);
break;
}
}
return false;
}
You can change the value of the delay 100L to suit your needs.