首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >切换颜色滤镜的StateListDrawable

切换颜色滤镜的StateListDrawable
EN

Stack Overflow用户
提问于 2011-05-16 22:04:42
回答 5查看 9.7K关注 0票数 10

我想创建在TabHost中使用的自定义按钮。我一直在尝试使用相同的图像资源(png),但根据不同的状态更改colorfilter。因此,我将此代码用作自定义按钮的布局:

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="fill_parent">
    <ImageView android:id="@+id/tab_icon"
        android:layout_centerInParent="true" android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView android:id="@+id/tab_text" android:layout_below="@id/tab_icon"
        android:layout_centerHorizontal="true" android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

在我的活动中,我添加了如下选项卡:

代码语言:javascript
复制
tabHost.addTab(tabHost.newTabSpec(TAB_NAME_NEWS).setIndicator(buildTab(R.drawable.tab_icon_news, R.string.news))
          .setContent(newsIntent));

这是'buildTab‘方法:

代码语言:javascript
复制
private final static int[] SELECTED = new int[] { android.R.attr.state_selected };
private final static int[] IDLE = new int[] { -android.R.attr.state_selected };

private View buildTab(int icon, int label) {
    LayoutInflater inflater = LayoutInflater.from(this);
    View view = inflater.inflate(R.layout.tab_button, null);
    StateListDrawable drawable = new StateListDrawable();

    Drawable selected = getResources().getDrawable(icon);
    selected.mutate();
    selected.setBounds(0, 0, selected.getIntrinsicWidth(), selected.getIntrinsicHeight());
    selected.setColorFilter(new LightingColorFilter(0xFFFFFFFF, 0x0000FF00));
    drawable.addState(SELECTED, selected);

    Drawable idle = getResources().getDrawable(icon);
    idle.mutate();
    idle.setColorFilter(new LightingColorFilter(0xFFFFFFFF, 0x000000FF));
    drawable.addState(IDLE, idle);

    ((ImageView) view.findViewById(R.id.tab_icon)).setImageDrawable(drawable);
    ((TextView) view.findViewById(R.id.tab_text)).setText(getString(label));
    return view;
}

在选中状态下,图像应为完全绿色(0x0000FF00),在未选中状态下,图像应为蓝色(0x000000FF)。

问题是滤色器似乎被完全忽略了。我在任何情况下都看不到颜色的变化。

我还试图通过在<ImageView/>上设置android:tint属性来获得相同的结果,但是显然您不能在那里使用对<selector>的引用,因为它抛出了一个NumberFormatException

我看不出我做错了什么,所以任何帮助都将不胜感激。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-05-20 20:21:08

好吧,我从来没有让上面的代码工作过,所以这是我最终要做的。

首先,我继承了LayerDrawable:

代码语言:javascript
复制
public class StateDrawable extends LayerDrawable {

    public StateDrawable(Drawable[] layers) {
        super(layers);
    }

    @Override
    protected boolean onStateChange(int[] states) {
        for (int state : states) {
            if (state == android.R.attr.state_selected) {
                super.setColorFilter(Color.argb(255, 255, 195, 0), PorterDuff.Mode.SRC_ATOP);
            } else {
                super.setColorFilter(Color.GRAY, PorterDuff.Mode.SRC_ATOP);
            }
        }
        return super.onStateChange(states);
    }

    @Override
    public boolean isStateful() {
        return true;
    }

}

我将buildTab()方法更改为以下内容:

代码语言:javascript
复制
private View buildTab(int icon, int label) {
    LayoutInflater inflater = LayoutInflater.from(this);
    View view = inflater.inflate(R.layout.tab_button, null);
    ((ImageView) view.findViewById(R.id.tab_icon)).setImageDrawable(new StateDrawable(new Drawable[] { getResources()
          .getDrawable(icon) }));
    ((TextView) view.findViewById(R.id.tab_text)).setText(getString(label));
    return view;
}

我仍然像这样添加选项卡:

代码语言:javascript
复制
Intent fooIntent = new Intent().setClass(this, FooActivity.class);
tabHost.addTab(tabHost.newTabSpec(TAB_NAME_INFO).setIndicator(buildTab(R.drawable.tab_icon_info, R.string.info)).setContent(infoIntent));

这对我来说很有效,兼容Android1.6。

票数 15
EN

Stack Overflow用户

发布于 2012-05-13 20:26:05

也不能通过将颜色滤镜直接应用于可绘制来解决这个问题。对我来说起作用的是将图像作为位图,用相同的度量创建一个空的第二个,为第二个定义画布,将该颜色滤镜应用于一个paint对象,并在第二个对象上绘制第一个位图。最后,从新的位图创建一个BitmapDrawable,就完成了。以下是代码

代码语言:javascript
复制
    ImageButton imageButton = (ImageButton)findViewById(R.id.aga);

    Bitmap one = BitmapFactory.decodeResource(getResources(), R.drawable.pen_circle);
    Bitmap oneCopy = Bitmap.createBitmap(one.getWidth(), one.getHeight(), Config.ARGB_8888);

    Canvas c = new Canvas(oneCopy);
    Paint p = new Paint();
    p.setColorFilter(new LightingColorFilter(Color.CYAN, 1));
    c.drawBitmap(one, 0, 0, p);

    StateListDrawable states = new StateListDrawable();
    states.addState(new int[] {android.R.attr.state_pressed}, new BitmapDrawable(oneCopy));
    states.addState(new int[] { }, imageButton.getDrawable());
    imageButton.setImageDrawable(states);
票数 10
EN

Stack Overflow用户

发布于 2013-10-01 16:40:21

这是我的类,被黑来支持ColorFilter:

用法:

代码语言:javascript
复制
final Drawable icon = getResources().getDrawable(iconResId);
final Drawable filteredIcon = // this is important
        icon.getConstantState().newDrawable();
final FilterableStateListDrawable selectorDrawable =
        new FilterableStateListDrawable();
selectorDrawable.addState(ICON_STATE_SELECTED, filteredIcon,
        new PorterDuffColorFilter(mIconOverlayColor, PorterDuff.Mode.SRC_ATOP));
selectorDrawable.addState(ICON_STATE_DEFAULT, icon);

正如您所看到的,ColorFilter并没有直接应用于可绘制对象,而是在向选择器可绘制对象添加状态时与之关联的。

这里重要的是

  • 你需要从常量状态创建一个新的可绘制对象,否则你将修改常量状态,从而修改活动中该可绘制对象的任何实例。
  • 你需要使用我的自定义addState方法,它与框架方法addState具有相同的名称,但我添加了一个额外的参数(ColorFilter)。框架超类中不存在此方法!

代码(很脏,但对我来说很好用):

代码语言:javascript
复制
/**
 * This is an extension to {@link android.graphics.drawable.StateListDrawable} that workaround a bug not allowing
 * to set a {@link android.graphics.ColorFilter} to the drawable in one of the states., it add a method
 * {@link #addState(int[], android.graphics.drawable.Drawable, android.graphics.ColorFilter)} for that purpose.
 */
public class FilterableStateListDrawable extends StateListDrawable {

    private int currIdx = -1;
    private int childrenCount = 0;
    private SparseArray<ColorFilter> filterMap;

    public FilterableStateListDrawable() {
        super();
        filterMap = new SparseArray<ColorFilter>();
    }

    @Override
    public void addState(int[] stateSet, Drawable drawable) {
        super.addState(stateSet, drawable);
        childrenCount++;
    }

    /**
     * Same as {@link #addState(int[], android.graphics.drawable.Drawable)}, but allow to set a colorFilter associated to this Drawable.
     *
     * @param stateSet    - An array of resource Ids to associate with the image.
     *                    Switch to this image by calling setState().
     * @param drawable    -The image to show.
     * @param colorFilter - The {@link android.graphics.ColorFilter} to apply to this state
     */
    public void addState(int[] stateSet, Drawable drawable, ColorFilter colorFilter) {
        // this is a new custom method, does not exist in parent class
        int currChild = childrenCount;
        addState(stateSet, drawable);
        filterMap.put(currChild, colorFilter);
    }

    @Override
    public boolean selectDrawable(int idx) {
        if (currIdx != idx) {
            setColorFilter(getColorFilterForIdx(idx));
        }
        boolean result = super.selectDrawable(idx);
        // check if the drawable has been actually changed to the one I expect
        if (getCurrent() != null) {
            currIdx = result ? idx : currIdx;
            if (!result) {
                // it has not been changed, meaning, back to previous filter
                setColorFilter(getColorFilterForIdx(currIdx));
            }
        } else if (getCurrent() == null) {
            currIdx = -1;
            setColorFilter(null);
        }
        return result;
    }

    private ColorFilter getColorFilterForIdx(int idx) {
        return filterMap != null ? filterMap.get(idx) : null;
    }
}

我打开了一个关于这个的bug:https://code.google.com/p/android/issues/detail?id=60183

更新:这个错误已经在框架中修复了,因为我想是棒棒糖。我认为修复提交是这样的:https://android.googlesource.com/platform/frameworks/base/+/729427d%5E!/

或者在Github上:https://github.com/android/platform_frameworks_base/commit/729427d451bc4d4d268335b8dc1ff6404bc1c91e

我的解决方法应该在棒棒糖之后仍然有效,只是不使用谷歌的修复程序。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6018602

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档