How can I give an imageview click effect like a button on Android?

Solution 1:

You can do this with a single image using something like this:

     //get the image view
    ImageView imageView = (ImageView)findViewById(R.id.ImageView);

    //set the ontouch listener
    imageView.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {

            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    ImageView view = (ImageView) v;
                    //overlay is black with transparency of 0x77 (119)
                    view.getDrawable().setColorFilter(0x77000000,PorterDuff.Mode.SRC_ATOP);
                    view.invalidate();
                    break;
                }
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL: {
                    ImageView view = (ImageView) v;
                    //clear the overlay
                    view.getDrawable().clearColorFilter();
                    view.invalidate();
                    break;
                }
            }

            return false;
        }
    });

I will probably be making this into a subclass of ImageView (or ImageButton as it is also a subclass of ImageView) for easier re-usability, but this should allow you to apply a "selected" look to an imageview.

Solution 2:

You can design different images for clicked/not clicked states and set them in the onTouchListener as follows

final ImageView v = (ImageView) findViewById(R.id.button0);
        v.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View arg0, MotionEvent arg1) {
                switch (arg1.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    v.setImageBitmap(res.getDrawable(R.drawable.img_down));
                    break;
                }
                case MotionEvent.ACTION_CANCEL:{
                    v.setImageBitmap(res.getDrawable(R.drawable.img_up));
                    break;
                }
                }
                return true;
            }
        });

The better choice is that you define a selector as follows

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true"   
        android:drawable="@drawable/img_down" />
    <item android:state_selected="false"   
        android:drawable="@drawable/img_up" />
</selector>

and select the image in the event:

v.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View arg0, MotionEvent arg1) {
                v.setSelected(arg1.getAction()==MotionEvent.ACTION_DOWN);
                return true;
            }
        });

Solution 3:

It's possible to do with just one image file using the ColorFilter method. However, ColorFilter expects to work with ImageViews and not Buttons, so you have to transform your buttons into ImageViews. This isn't a problem if you're using images as your buttons anyway, but it's more annoying if you had text... Anyway, assuming you find a way around the problem with text, here's the code to use:

ImageView button = (ImageView) findViewById(R.id.button);
button.setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);

That applies a red overlay to the button (the color code is the hex code for fully opaque red - first two digits are transparency, then it's RR GG BB.).

Solution 4:

EDIT: Although the original answer below works and is easy to set up, refer to this post by an Android Developer Advocate at Google if you want / need a more efficient implementation. Also note that the android:foreground attribute is coming to all Views, including ImageView, by default in Android M.


The problem with using a selector for an ImageView is that you can only set it as the view's background - as long as your image is opaque, you will not see the selector's effect behind it.

The trick is to wrap your ImageView in a FrameLayout with the attribute android:foreground which allows us to define an overlay for its content. If we set android:foregroundto a selector (e.g.?android:attr/selectableItemBackground for API level 11+) and attach the OnClickListener to the FrameLayout instead of the ImageView, the image will be overlaid with our selector's drawable - the click effect we desire!

Behold:

<FrameLayout
    android:id="@+id/imageButton"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:foreground="?android:attr/selectableItemBackground" >

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/yourImageFile" />

</FrameLayout>

(Note this should be placed within your parent layout.)

final View imageButton = findViewById(R.id.imageButton);
imageButton.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View view) {
        // do whatever we wish!
    }
});