How to set button click effect in Android?
AndroidAndroid Problem Overview
In Android, when I set a background image to a button, I can not see any effect on it when it's clicked.
I need to set some effect on the button, so the user can recognise that the button is clicked.
The button should be dark for a few seconds when it is clicked. How to do this?
Android Solutions
Solution 1 - Android
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.
Solution 2 - Android
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;
}
});
}
Solution 3 - Android
Create your AlphaAnimation
Object that decides how much will be the fading effect of the button, then let it start in the onClickListener
of your buttons
For example :
private AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.8F);
// some code
public void onClick(View v) {
v.startAnimation(buttonClick);
}
of course this is just a way, not the most preferred one, it's just easier
Solution 4 - Android
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"
Solution 5 - Android
To make your item consistent with the system look and feel try referencing the system attribute android:attr/selectableItemBackground
in your desired view's background or foreground tag:
<ImageView
...
android:background="?android:attr/selectableItemBackground"
android:foreground="?android:attr/selectableItemBackground"
...
/>
Use both attributes to get desired effect before/after API level 23 respectively.
Solution 6 - Android
Or using only one background image you can achive the click effect by using setOnTouchListener
Two ways
((Button)findViewById(R.id.testBth)).setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
Button view = (Button) v;
view.getBackground().setColorFilter(0x77000000, PorterDuff.Mode.SRC_ATOP);
v.invalidate();
break;
}
case MotionEvent.ACTION_UP:
// Your action here on button click
case MotionEvent.ACTION_CANCEL: {
Button view = (Button) v;
view.getBackground().clearColorFilter();
view.invalidate();
break;
}
}
return true;
}
});
And if you don't want to use setOnTouchLister
, the another way of achieving this is
myButton.getBackground().setColorFilter(.setColorFilter(0xF00, Mode.MULTIPLY);
StateListDrawable listDrawable = new StateListDrawable();
listDrawable.addState(new int[] {android.R.attr.state_pressed}, drawablePressed);
listDrawable.addState(new int[] {android.R.attr.defaultValue}, myButton);
myButton.setBackgroundDrawable(listDrawable);
Solution 7 - Android
For all the views
android:background="?android:attr/selectableItemBackground"
But for cardview which has elevation use
android:foreground="?android:attr/selectableItemBackground"
For Circular click effect as in toolbar
android:background="?android:attr/actionBarItemBackground"
Also you need to set
android:clickable="true"
android:focusable="true"
Solution 8 - Android
This is the best solution I came up with taking hints from @Vinayak's answer. All the other solutions have different drawbacks.
First of all create a function like this.
void addClickEffect(View view)
{
Drawable drawableNormal = view.getBackground();
Drawable drawablePressed = view.getBackground().getConstantState().newDrawable();
drawablePressed.mutate();
drawablePressed.setColorFilter(Color.argb(50, 0, 0, 0), PorterDuff.Mode.SRC_ATOP);
StateListDrawable listDrawable = new StateListDrawable();
listDrawable.addState(new int[] {android.R.attr.state_pressed}, drawablePressed);
listDrawable.addState(new int[] {}, drawableNormal);
view.setBackground(listDrawable);
}
Explanation:
getConstantState().newDrawable() is used to clone the existing Drawable otherwise the same drawable will be used. Read more from here: https://stackoverflow.com/questions/7979440/android-cloning-a-drawable-in-order-to-make-a-statelistdrawable-with-filters
mutate() is used to make the Drawable clone not share its state with other instances of Drawable. Read more about it here: https://developer.android.com/reference/android/graphics/drawable/Drawable.html#mutate()
Usage:
You can pass any type of View (Button, ImageButton, View etc) as the parameter to the function and they will get the click effect applied to them.
addClickEffect(myButton);
addClickEffect(myImageButton);
Solution 9 - Android
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.
Solution 10 - Android
Step: set a button in XML with onClick Action:
<Button
android:id="@+id/btnEditUserInfo"
style="?android:borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/txt_height"
android:layout_gravity="center"
android:background="@drawable/round_btn"
android:contentDescription="@string/image_view"
android:onClick="edit_user_info"
android:text="Edit"
android:textColor="#000"
android:textSize="@dimen/login_textSize" />
Step: on button clicked show animation point
//pgrm mark ---- ---- ----- ---- ---- ----- ---- ---- ----- ---- ---- -----
public void edit_user_info(View view) {
// show click effect on button pressed
final AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.8F);
view.startAnimation(buttonClick);
Intent intent = new Intent(getApplicationContext(), EditUserInfo.class);
startActivity(intent);
}// end edit_user_info
Solution 11 - Android
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>
Solution 12 - Android
Create bounce.xml file fo animation
LOCATION:
> res->anim->bounce.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="100"
android:fromXScale="0.9"
android:fromYScale="0.9"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0" />
</set>
Add this line in onClick to initialize
final Animation myAnim = AnimationUtils.loadAnimation(this,R.anim.bounce);
button.startAnimation(myAnim);
You get the shrink effect in a button click.
Solution 13 - Android
I had the same issue, where I needed to have a transparent background but still get animation. Setting this solved it for me:
android:background="?android:selectableItemBackground"
Also this if you want to have circular effect:
android:background="?android:selectableItemBackgroundBorderless"
Solution 14 - Android
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.
Solution 15 - Android
If you're using xml background instead of IMG, just remove this :
<item>
<bitmap android:src="@drawable/YOURIMAGE"/>
</item>
from the 1st answer that @Ljdawson gave us.
Solution 16 - Android
Simple and easy way to set View click effect.
> Method
public AlphaAnimation clickAnimation() {
return new AlphaAnimation(1F, 0.4F); // Change "0.4F" as per your recruitment.
}
> Set in View
yourView.startAnimation(clickAnimation());