Android ImageView更改色调以模拟按钮点击

40

我有一个ImageView,在其中设置了从URL获取的位图。在ImageView上,我设置了一个onClickListener来打开一个对话框。

当点击ImageView时,我想要改变它的色调(使其更暗),以提供一种类似于按钮点击的感觉。

你有什么建议?

5个回答

102

happydude的回答是处理这个问题最优雅的方式,但不幸的是(正如评论中指出的),ImageView的源代码只接受整数(纯色)。Issue 18220已经存在了几年,解决了这个问题,我在那里发布了一个解决方法,在此做个总结:

扩展ImageView并包装drawableStateChanged(),使用代码根据新状态设置tint:

TintableImageView.java

package com.example.widgets;

import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.support.v7.widget.AppCompatImageView;

import com.example.R;

public class TintableImageView extends AppCompatImageView {

    private ColorStateList tint;

    public TintableImageView(Context context) {
        super(context);
    }

    public TintableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

    public TintableImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs, defStyle);
    }

    private void init(Context context, AttributeSet attrs, int defStyle) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TintableImageView, defStyle, 0);
        tint = a.getColorStateList(R.styleable.TintableImageView_tintColorStateList);
        a.recycle();
    }

    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        if (tint != null && tint.isStateful())
            updateTintColor();
    }    

    private void updateTintColor() {
        int color = tint.getColorForState(getDrawableState(), 0);
        setColorFilter(color);
    }

}

定义自定义属性:

attrs.xml

<?xml version="1.0" encoding="UTF-8"?>
<resources>

    <declare-styleable name="TintableImageView">
        <attr name="tintColorStateList" format="reference|color" />
    </declare-styleable>

</resources>

请使用小部件和自定义属性的本地命名空间,而不是Android的命名空间:

example_layout.xml

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <com.example.widgets.TintableImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/example"
        android:clickable="true"
        app:tintColorStateList="@color/color_selector"/>

</LinearLayout>

您可以像happydude建议的那样使用颜色选择器:

color_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:color="@color/pressed_color"/>
    <item android:color="#00000000"/>
</selector>

2
我正在尝试您的解决方案,但是当TintableImageView内部的构造函数调用其超类时,仍然会出现“java.lang.NumberFormatException:Invalid int:“@2130837701””的错误。 我需要传递new int [] {R.styleable.TintableImageView_tint},因为obtainStyledAttributes要求一个数组,并且在colors.xml中声明<drawable name =“tab_icon_selector”> @ drawable / tab_icon_selector </ drawable>以便能够从android:tint引用它。 - Lucas Jota
3
因此,我的答案在attrs.xml中定义了一个自定义的色彩属性。您必须在布局中使用定制的 "app:tint" 而不是 "android:tint"。本质上,您正在创建一个新的属性,它包装了原生属性并逐个颜色地提供它。 - Stephen Kidson
请在SO上回答我的问题,这样我就可以接受它了。https://dev59.com/C2Ik5IYBdhLWcg3wMLmI - Lucas Jota
我已经在那里提供了一个答案。对于其他人来说,你可以将你的selector.xml放在/res/color中,使用@color引用它。 - Stephen Kidson
1
我复制了你的代码并检查了一切,但它就是不起作用。 - DYS
显示剩余9条评论

8
一种方法是使用ColorFilter和包含按钮按下时的色调颜色的ColorStateList的组合。在res/color目录中,ColorStateList的xml如下所示:

button_pressed.xml

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

    <item android:state_pressed="true" android:color="@color/pressed_color"/>
    <item android:color="#00000000"/>

</selector>

其中@color/pressed_color是您的色调颜色(应该是部分透明的)。然后在您的ImageView子类中,您可以通过重写drawableStateChanged()方法来应用该颜色。

@Override
protected void drawableStateChanged() {
    super.drawableStateChanged();

    ColorStateList list = getResources().getColorStateList(R.color.button_pressed);
    int color = list.getColorForState(getDrawableState(), Color.TRANSPARENT);
    setColorFilter(color);
    invalidate();
}

任何时候按钮的状态发生变化,都会调用此代码,并自动设置合适的色调。

我尝试了你的建议。它似乎没有做任何事情。使用调试器,我注意到在onPress时drawableStateChanged()方法未被触发,但似乎仅在onClick时才会触发。 - Abhishek
嗯,我在上面的代码中没有看到任何错误。 根据定义,当按下状态更改时,应调用该方法。 我一直在自己的代码中使用这个结构,它可以正常工作。 作为一个测试,在您的ImageView XML中添加android:tint="@color/pressed_color"。 这应该会给您的图像添加一个永久的色调,因为它调用与上面代码相同的colorfilter设置方法。 这样,您至少可以排除您选择的颜色有问题的可能性。 - happydude
抱歉,我有点傻。您可以直接将颜色状态列表添加到您的ImageView XML文件中。请参见上面的编辑。 - happydude
1
好的。当我设置android:tint="@drawable/button_pressed"时,编译期间出现了以下错误:06-19 20:22:54.222: E/AndroidRuntime(2338): Caused by: java.lang.NumberFormatException: 无法将'res/drawable/button_pressed.xml'解析为整数 06-19 20:22:54.222: E/AndroidRuntime(2338): at java.lang.Integer.parse(Integer.java:383) 06-19 20:22:54.222: E/AndroidRuntime(2338): at java.lang.Integer.parseInt(Integer.java:372) 06-19 20:22:54.222: E/AndroidRuntime(2338): at com.android.internal.util.XmlUtils.convertValueToInt(XmlUtils.java:12s) - Abhishek
首先,请忽略“编辑”(edit)操作。我查看了源代码,确实tint只接受纯色。很抱歉让你走错了方向。第二,在我创建的自定义ImageView中尝试了上面原始帖子中的代码,它对我有效。我通过使用setImageResource(int)来设置图像进行了测试,虽然我不明白为什么其他图像设置方法不能工作。最后,请确保在XML定义中添加android:clickable="true"。如果没有这一行,它将无法正常工作。 - happydude

0

我得测试一下,但你应该能够将一个具有此行为的xml设置为ImageView drawable,然后将你的位图设置为ImageView背景。


0
对我来说,一个简单的解决方案是使用setAlpha(180)onClick事件中使图像变暗,给用户一个反馈,表明它已被点击或触摸。
final ImageView myImage = (ImageView) findViewById(R.id.ivDocument);
myImage.setImage...(... your image ...); // load your ImageView
myImage.setClickable(true);
myImage.setFocusable(true);
myImage.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        myImage.setAlpha(180);
        doWhateverYouWantHere(v);
    }
});

关于你的XML布局,没什么特别的。

-1

这段代码片段对我有效:

porterDuffColorFilter = newPorterDuffColorFilter(getResources().getColor(R.color.cardview_dark_background),PorterDuff.Mode.MULTIPLY);

imgView.getDrawable().setColorFilter(porterDuffColorFilter);
imgView.setBackgroundColor(Color.TRANSPARENT);

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