使用ColorFilter进行Ninepatch Drawable

时间:2013-03-12 10:49:48

标签: android nine-patch android-drawable porter-duff statelistdrawable

我正在创建一些日历视图,我想要做的是创建一个可点击的LineairLayout的背景。

因此,我创建了一个包含两个图像的StateListDrawable:

  1. 背景图片
  2. 按下项目时的图像
  3. 到目前为止,它适用于这段代码:

        NinePatchDrawable background = (NinePatchDrawable) context.getResources().getDrawable(R.drawable.calendar_item);
        Drawable backgroundFocus = context.getResources().getDrawable(R.drawable.calendar_focus);
    
        int stateFocused = android.R.attr.state_focused;
        int statePressed = android.R.attr.state_pressed;
    
        StateListDrawable sld = new StateListDrawable();
        sld.addState(new int[]{ stateFocused,  statePressed}, backgroundFocus);
        sld.addState(new int[]{-stateFocused,  statePressed}, backgroundFocus);
        sld.addState(new int[]{-stateFocused}, background);
        return sld;
    

    但我想做点额外的事情。我希望用户能够传递他想用来显示背景的颜色。因此,背景var必须是可变的,但它必须基于9-patch drawable。

    所以我想我可以做这样的事情:

    background.setColorFilter(Color.RED, PorterDuff.Mode.DST_IN);
    

    其中Color.RED必须替换为用户选择的颜色。

    但这似乎不起作用。九个补丁是完美创建的,但没有应用颜色滤镜。

    我也尝试了其他的PoterDuff.Mode:

    • SRC
    • SRC_ATOP
    • DST_IN
    • ...

    如果你有任何线索我做错了什么或我能做些什么来解决我的问题请告诉我! : - )

    氪,

    德克

1 个答案:

答案 0 :(得分:2)

我认为你不能为StateListDrawable中的每个Drawable分配ColorFilters。原因:当StateListDrawable更改状态时,将删除/替换ColorFilter。要查看此操作,请更改语句的顺序,以便:

background.setColorFilter(Color.RED, PorterDuff.Mode.DST_IN);

在创建StateListDrawable之后出现。您将看到ColorFilter IS已应用。但是,只要状态发生变化(单击,然后释放),ColorFilter就不再存在了。

StateListDrawables允许您设置ColorFilter:StateListDrawable#setColorFilter(ColorFilter)。这是使用提供的(或null)ColorFilter的方式:

<强> StateListDrawable#onStateChange(INT [])

@Override
protected boolean onStateChange(int[] stateSet) {
    ....
    if (selectDrawable(idx)) {    // DrawableContainer#selectDrawable(int)
        return true;
    }
    ....
}

<强> DrawableContainer#selectDrawable(int)的

public boolean selectDrawable(int idx) {
    ....
    if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) {
        Drawable d = mDrawableContainerState.mDrawables[idx];
        mCurrDrawable = d;
        mCurIndex = idx;

        if (d != null) {
            ....

            // So, at this stage, any ColorFilter you might have supplied
            // to `d` will be replaced by the ColorFilter you
            // supplied to the StateListDrawable, or `null`
            // if you didn't supply any.                 
            d.setColorFilter(mColorFilter);

            ....
        }
    } else {
        ....
    }
}

解决方法

如果可能的话,使用ImageView(尺寸的match_parent)进行可视通信。将您创建的StateListDrawable设置为ImageView的背景。为叠加层创建另一个StateListDrawable:

StateListDrawable sldOverlay = new StateListDrawable();

// Match Colors with states (and ultimately, Drawables)
sldOverlay.addState(new int[] { statePressed }, 
                         new ColorDrawable(Color.TRANSPARENT));

sldOverlay.addState(new int[] { -statePressed }, 
                         new ColorDrawable(Color.parseColor("#50000000")));

// Drawable that you already have
iv1.setBackground(sld);

// Drawable that you just created
iv1.setImageDrawable(sldOverlay);

另一种可能性:使用FrameLayout代替LinearLayout。 LinearLayouts没有前景属性。

// StateListDrawable
frameLayout.setBackground(sld);

// For tint
frameLayout.setForeground(sldOverlay);

确实涉及透支,使其成为次优解决方案/解决方法。也许你可以看一下扩展StateListDrawable和DrawableContainer。由于您没有将ColorFilter用于StateListDrawable,因此您可以从覆盖的d.setColorFilter(mColorFilter);中删除DrawableContainer#selectDrawable(int)