如何在Android上使ImageView具有类似按钮的点击效果?

91

我在我的安卓应用中有一个类似按钮的imageView,在其中添加了onClick事件。但是,可能会发现当点击时,并没有给imageView添加可点击效果。如何实现这一点?

28个回答

80

你可以使用类似以下的方法,使用单张图片来完成此操作:

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

我可能会把这个变成ImageView的子类(或者ImageButton,因为它也是ImageView的子类),以便更容易地重用,但这应该允许你对一个ImageView应用“选中”效果。


2
我还添加了一个ACTION_CANCEL的情况,它运行得很好,谢谢! - Alan
1
这可能是另一个问题,但我如何在ACTION_UP之后取消操作?具体来说... 用户点击图像。 用户将手指从图像上拖出以取消操作。 但是使用此代码无法取消操作。 - sudocoder
我还会添加 MotionEvent.ACTION_OUTSIDE ;) - bonnyz
3
如果不返回false,视图的实际onClick()事件将不会被触发。 - Nimrod Dayan
谢谢,这帮助我解决了按钮onclick,offclick的需求。 - wesley franks
显示剩余4条评论

55

你可以为点击和未点击状态设计不同的图像,并将它们设置在 onTouchListener 中,如下所示。

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;
            }
        });
更好的选择是定义一个选择器如下所示。
<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>

在事件中选择图片:

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

1
你能解释一下 res.getDrawable 和 res 的作用吗? - VenushkaT
v.setSelected方法只有在触发MotionEvent.ACTION_MOVE事件后才会立即变为false。一旦手指释放,就会触发MotionEvent.ACTION_UP事件。如果使用选择器方法,请使用单独的逻辑来设置setSelected或setPressed。如果(arg1.getAction() == MotionEvent.ACTION_DOWN){v.setPressed(true);} else if(arg1.getAction() == MotionEvent.ACTION_UP){v.setPressed(false);} - Adam Denoon
最好使用 MotionEvent.ACTION_DOWN || MotionEvent.ACTION_MOVE,这样我们按住屏幕时图像就会一直显示。 - Alaa M.
你不需要使用 setOnTouchListener(...)。你可以在XML中创建 <selector ...>,然后设置ImageView的可点击性,如 <ImageView ... android:clickable="true" android:focusable="true" android:src="@drawable/my_selector" /> - Pierre

45
编辑:虽然下面的原始答案可行且易于设置,但是如果您想/需要更高效的实现,请参考谷歌Android开发者倡导者Nick Butcher发布的这篇文章。另外还要注意,在Android M中,默认情况下,android:foreground属性将包括所有视图,包括ImageView。请参阅此帖子
使用ImageView作为选择器的问题在于,你只能将其设置为视图的背景 - 只要你的图像是不透明的,你就看不到选择器效果的背后。
诀窍是将你的ImageView包装在一个FrameLayout中,并使用属性android:foreground来定义其内容的覆盖层。如果我们将android:foreground设置为一个选择器(例如API级别11+的?android:attr/selectableItemBackground),并将OnClickListener附加到FrameLayout而不是ImageView上,那么图像将与我们的选择器可绘制物重叠 - 我们所需的单击效果!
看这里:
<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>

(请注意,这应放在您的父布局中。)
final View imageButton = findViewById(R.id.imageButton);
imageButton.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View view) {
        // do whatever we wish!
    }
});

2
太好了!这是一个非常好的解决方案。在通讯录应用中也使用了相同的解决方案来执行短信或电话操作。 - Jerry
无法在API < 11中工作。?android:attr/selectableItemBackground需要API级别11(当前最低级别为8) - MSaudi
selectableItemBackground属性仅在API级别11中添加,因此,如果您想在较旧的API级别中使用此解决方案,则必须使用另一个选择器。例如,对于支持API级别7的我的一个应用程序,我使用使用Android Holo Colors Generator工具生成的@drawable/list_selector_holo_light资源。 - justasm
您可以使用可选择项背景(selectableItemBackground)仅使用1个<ImageButton>来实现相同的行为! - Yohan Dahmani

30

在XML文件中使用 style="?android:borderlessButtonStyle",这将显示Android默认的点击效果。

<ImageView
    android:id="@+id/imageView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_launcher" 
    style="?android:borderlessButtonStyle"
/>

1
这实际上是最好的答案,要简单得多。 - FrankMonza
1
这会设置填充,即使您将填充设置为0,如果您提供的图像占据整个imageView,您也看不到任何点击效果。 - android developer
2
@androiddeveloper 使用 android:adjustViewBounds="true" 取消填充。 - Hafez Divandari
1
建议使用 style="?android:attr/borderlessButtonStyle":https://developer.android.com/guide/topics/ui/controls/button#Borderless - Hafez Divandari
在 ActionBar 或 ToolBar 上使用 style="?android:actionButtonStyle" 以实现可点击的 ImageView。 - palindrom

21

3
个人无法使其看起来像ImageView。没有边框,将图像拉伸到ImageButton的大小等。如果您能解决这个边框和拉伸问题,并更新您的帖子。我的一些声望将作为赏金给予您=) - totten

15

这是我的简单解决方法:

ImageView iv = (ImageView) findViewById(R.id.imageView);

iv.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View arg0) {
        // TODO Auto-generated method stub
        //Agrega porcentajes de cada fraccion de grafica pastel

        Animation animFadein = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.fade_in);

        iv.startAnimation(animFadein);
    });

在文件res/anim/fade_in.xml中:

<?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:fillAfter="true" >

<alpha
    android:duration="100"
    android:fromAlpha="0.0"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:toAlpha="1.0" />
 </set>

太棒了,谢谢!我看过这个帖子,尝试了所有简洁的方法,但都没有成功。最后我找到了这里,并且对我很有用。一个观察 - 如果你有两个或更多的按钮想要应用动画效果...对于我的代码,我发现我需要为我想要应用效果的每个按钮创建一个唯一的Animation对象实例。重复使用相同的实例会使所有按钮在点击其中一个时闪烁。 - Gene Bo

11

如果您希望在轻敲时出现涟漪效果,则可以使用以下代码:

<ImageView
    ...
    android:background="?attr/selectableItemBackgroundBorderless"
    android:clickable="true"
    ...
</ImageView>

同样地,您可以为TextView实现点击效果。

<TextView
    ...
    android:background="?attr/selectableItemBackgroundBorderless"
    android:clickable="true"
    ...
</TextView>

9

将可选背景设置为ImageView并添加一些填充。然后附加OnClickListener。

<ImageView
    android:id="@+id/your_image_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/your_image"
    android:padding="10dp"
    android:background="?android:attr/selectableItemBackground"/>

有没有一种方法可以在不设置填充的情况下使用它,并使整个ImageView都具有效果,而不仅仅是空白区域? - android developer
这将显示立方中的涟漪,我们需要中心涟漪。 - Kishan Solanki

8

定义选择器Drawable的选择

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

我需要使用android:state_pressed而不是android:state_selected。
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed ="true"   
        android:drawable="@drawable/img_down" />
    <item android:state_pressed ="false"   
        android:drawable="@drawable/img_up" />
</selector>

5
这对我有用:

这对我有用:

img.setOnTouchListener(new OnTouchListener(){

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction())
                {
                    case MotionEvent.ACTION_DOWN:
                    {
                        ((ImageView)v).setImageAlpha(200);
                        break;
                    }
                    case MotionEvent.ACTION_MOVE:
                    {
                        // if inside bounds
                        if(event.getX() > 0 && event.getX() < v.getWidth() && event.getY() > 0 && event.getY() < v.getHeight())
                        {
                            ((ImageView)v).setImageAlpha(200);
                        }
                        else
                        {
                            ((ImageView)v).setImageAlpha(255);
                        }

                        break;
                    }
                    case MotionEvent.ACTION_UP:
                    {
                        ((ImageView)v).setImageAlpha(255);
                    }
                }
                return true;
            }

        });

@编辑:正如Gunhan所说,使用setImageAlpha方法会存在向后兼容性问题。我使用了这个方法:

public static void setImageAlpha(ImageView img, int alpha)
    {
        if(Build.VERSION.SDK_INT > 15)
        {
            img.setImageAlpha(alpha);
        }
        else
        {
            img.setAlpha(alpha);
        }
    }

1
setImageAlpha需要API级别16。因此,对于向后兼容的应用程序,无法使用它。 - Gunhan
1
@Gunhan 实际上,你可以使用“nineOldAndroids”库,它允许在旧的API上使用alpha。只需使用:ViewHelper.setAlpha(view,alpha); - android developer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接