web-dev-qa-db-ja.com

Android:フィルターを使用してStateListDrawableを作成するためのドロアブルのクローン作成

pressed/focused/selected/etcのときにDrawableが強調表示される一般的なフレームワーク関数を作成しようとしています。

私の関数はDrawableを取り、StateListDrawableを返します。デフォルトの状態はDrawableそのものであり、_Android.R.attr.state_pressed_の状態は、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()で遊んでみましたが、助けにはなりません。

何か案は?

更新:

受け入れられた答えは確かにドロアブルを複製します。私の一般的な機能が別の問題で失敗するので、それは私を助けませんでした。 StateListにドロアブルを追加すると、すべてのフィルターが失われるようです。

86
talkol

以下を試してください:

Drawable clone = drawable.getConstantState().newDrawable();
153
Flavio

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

98
Peter Ajtai

これは私のために働くものです。

Drawable clone = drawable.getConstantState().newDrawable().mutate();
14
Yanru Bi

これはこれに基づく私の解決策です SOの質問

アイデアは、ImageViewはユーザーがタッチするとカラーフィルターを取得し、ユーザーがタッチを停止するとカラーフィルターが削除されるというものです。メモリ内には1つのドロウアブル/ビットマップのみがあるため、無駄にする必要はありません。正常に機能します。

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));
10
Malachiasz

関連する質問に答えました こちら

基本的に、StateListDrawablesは実際にフィルターを失っているようです。最初に使用したいビットマップの変更されたコピーから新しいBitmapDrawaleを作成しました。

1
Kuno