[android] How to set button click effect in Android?

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.

Button should be dark while a few second when it clicked, so what should I do for this?

Thanks.

This question is related to android

The answer is


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


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.

https://stackoverflow.com/a/11513474/4683601


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>


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;
        }
    });
}

Create bounce.xml file for animation

<?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.


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.


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.


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;
        }
});

enter image description here

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);

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

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"

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: 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);

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"