2011-11-02 28 views
75

我試圖製作一個通用框架函數,使任何Drawable在被按下/聚焦/選中/ /等時變亮。Android:克隆drawable以使StateListDrawable具有過濾器

我的函數需要一個Drawable並返回一個StateListDrawable,其中默認狀態是Drawable本身,並且android.R.attr.state_pressed的狀態與drawable相同,只是使用setColorFilter應用了一個過濾器。

我的問題是,我無法克隆drawable,並使用應用的過濾器製作一個單獨的實例。這是我想要實現的:

StateListDrawable makeHighlightable(Drawable drawable) 
{ 
    StateListDrawable res = new StateListDrawable(); 

    Drawable clone = drawable.clone(); // how do I do this?? 

    clone.setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY); 
    res.addState(new int[] {android.R.attr.state_pressed}, clone); 
    res.addState(new int[] { }, drawable); 
    return res; 
} 

如果我不克隆,那麼過濾器顯然適用於兩種狀態。我試過與mutate()玩,但它沒有幫助..

任何想法?

更新:

接受的答案確實是克隆一個繪製。它並沒有幫助我,但是因爲我的一般功能在另一個問題上失敗了。看起來,當你將一個drawable添加到一個StateList時,它將失去所有的過濾器。

+0

嗨,你有沒有找到一個解決方案drawables丟失過濾器?我遇到了同樣的問題:(我最終通過克隆位圖並逐個像素地應用濾鏡來從源圖像中生成其他圖像。是的,這是效率低下的,但我只處理了一堆小圖像 – port443

+0

I無法用StateListDrawable解決它,但如果你不使用StateListDrawable並仍然失去你的過濾器,請確保你的位圖是可變的。有很好的相關問題:http://stackoverflow.com/questions/5499637/drawable-setcolorfilter -not-working-on-android-2-1,我也發現LightingColorFilter在PorterDuff失敗的地方工作..喜歡這個機器人:) – talkol

+0

在這個鏈接很好的答案http://stackoverflow.com/questions/ 10889415 /添加一個顏色過濾器到可繪製的變化 - 所有按鈕使用相同的可繪製 – Alan

回答

138

嘗試以下操作:

Drawable clone = drawable.getConstantState().newDrawable(); 
+1

謝謝!這種方法似乎成功地克隆了一個drawable。我試圖編寫的函數雖然不起作用..看起來,當一個drawable被插入到一個StateList時,它失去了它的過濾器:( – talkol

+3

+1幫助我修復MapView中一個非常奇怪的錯誤,其中重用了Drawable AlertDialog中的ItemizedOverlay使得ItemizedOverlay在觸發時移動 讓Drawable的新實例解決問題 – kskjon

+8

如果我們嘗試使用setAlpha方法,那麼要正確地工作,在這種情況下,兩個可繪製的位圖變化 然後我得到第一個可繪製爲:getResources()。getDrawable(),第二個爲:getResources()。getDrawable()。mutate()。 –

1

我回答一個相關的問題here

基本上好像StateListDrawables確實失去了他們的過濾器。我從最初想要使用的位圖的修改副本創建了一個新的BitmapDrawale。

86

如果您將篩選器/ etc應用於使用getConstantState().newDrawable()創建的可繪製對象,則該可繪製對象的所有實例也將被更改,因爲可繪製對象使用constantState作爲緩存!

所以,如果你用彩色濾鏡和newDrawable爲一個圓圈着色,你將改變所有圓圈的顏色。

如果你想讓這個可繪製的可更新而不影響其他實例,那麼你必須改變現有的常量狀態。

// To make a drawable use a separate constant state 
drawable.mutate() 

對於一個好的解釋,參見:

http://www.curious-creature.org/2009/05/02/drawable-mutations/

http://developer.android.com/reference/android/graphics/drawable/Drawable.html#mutate()

+0

實際上,mutate()確實返回完全相同的實例,但其內部狀態已更改,因此應用顏色過濾器不會影響其他實例。你能回顧並修復你的答案嗎? – clemp6r

+1

@ clemp6r如果您不使用突變所有顏色變化的實例 - 您需要調用突變以僅更改克隆的顏色 –

+1

檢查[API ref](http://developer.android.com /reference/android/graphics/drawable/Drawable.html#mutate())(「Make this drawable mutable。 - Returns this drawable」)and the [source code](http://grepcode.com/file/repo1.maven .org/maven2/org.robolectric/android-all/4.2.2_r1.2-robolectric-0/android/graphics/drawable/BitmapDrawable.java#426)(「return this」)。調用mutate()是必需的,但返回的實例是相同的。這不會創建一個克隆,它只會改變drawable實例的內部狀態,以允許修改它而不會影響同一drawable的其他實例。 – clemp6r

10

這是我的解決方案,在此基礎上代碼:https://stackoverflow.com/a/6071813/2075875。這個想法是,當用戶觸摸它時,ImageView會獲取顏色過濾器,並且當用戶停止觸摸時,將會移除顏色過濾器。內存中只有1個drawable/bitmap,因此不需要浪費它。它的工作原理應該如此。

class PressedEffectStateListDrawable extends StateListDrawable { 

    private int selectionColor; 

    public PressedEffectStateListDrawable(Drawable drawable, int selectionColor) { 
     super(); 
     this.selectionColor = selectionColor; 
     addState(new int[] { android.R.attr.state_pressed }, drawable); 
     addState(new int[] {}, drawable); 
    } 

    @Override 
    protected boolean onStateChange(int[] states) { 
     boolean isStatePressedInArray = false; 
     for (int state : states) { 
      if (state == android.R.attr.state_pressed) { 
       isStatePressedInArray = true; 
      } 
     } 
     if (isStatePressedInArray) { 
      super.setColorFilter(selectionColor, PorterDuff.Mode.MULTIPLY); 
     } else { 
      super.clearColorFilter(); 
     } 
     return super.onStateChange(states); 
    } 

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

用法:

Drawable drawable = new FastBitmapDrawable(bm); 
imageView.setImageDrawable(new PressedEffectStateListDrawable(drawable, 0xFF33b5e5)); 
+0

它也適用於我,謝謝! – Mikhail

+0

也適用於我!這是一個有趣的解決方案,謝謝!)Android吸盤,這樣糟糕的不正常工作的API :( –

+0

我認爲這是迄今爲止解決(StateListDrawable + BitmapDrawable)中的錯誤的最佳解決方案! –

6

這是我的作品。

Drawable clone = drawable.getConstantState().newDrawable().mutate();