Android: Cloning a drawable in order to make a StateListDrawable with filters

前端 未结 7 755
梦谈多话
梦谈多话 2020-11-29 18:32

I\'m trying to make a general framework function that makes any Drawable become highlighted when pressed/focused/selected/etc.

My function takes a D

相关标签:
7条回答
  • 2020-11-29 18:52

    Get clone drawable using newDrawable() but make sure it is mutable otherwise your clone effect gone, I used these few lines of code and it is working as expected. getConstantState() may be null as suggested by annotation, so handle this RunTimeException while you cloning drawable.

    Drawable.ConstantState state = d.mutate().getConstantState();
    if (state != null) {
        Drawable drawable = state.newDrawable().mutate();
    }
    
    0 讨论(0)
  • 2020-11-29 18:57

    If you apply a filter / etc to a drawable created with getConstantState().newDrawable() then all instances of that drawable will be changed as well, since drawables use the constantState as a cache!

    So if you color a circle using a color filter and a newDrawable(), you will change the color of all the circles.

    If you want to make this drawable updatable without affecting other instances then, then you must mutate that existing constant state.

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

    For a good explanation see:

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

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

    0 讨论(0)
  • 2020-11-29 18:57

    This is what works for me.

    Drawable clone = drawable.getConstantState().newDrawable().mutate();
    
    0 讨论(0)
  • 2020-11-29 19:03

    Try the following:

    Drawable clone = drawable.getConstantState().newDrawable();
    
    0 讨论(0)
  • 2020-11-29 19:07

    I answered a related question here

    Basically it seems like StateListDrawables indeed lose their filters. I created a new BitmapDrawale from a altered copy of the Bitmap I originally wanted to use.

    0 讨论(0)
  • 2020-11-29 19:15

    This is my solution, based on this SO question.

    The idea is that ImageView gets color filter when user touches it, and color filter is removed when user stops touching it. Only 1 drawable/bitmap is in memory, so no need to waste it. It works as it should.

    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;
        }
    }
    

    usage:

    Drawable drawable = new FastBitmapDrawable(bm);
    imageView.setImageDrawable(new PressedEffectStateListDrawable(drawable, 0xFF33b5e5));
    
    0 讨论(0)
提交回复
热议问题