2015-02-25 5 views
9

Я пытаюсь развернуть разные цвета на экране через регулярные интервалы (несколько раз в секунду).setColorFilter() взломан на Android 4, работая на Android 5

Для изменения цвета я использую Drawable.setColorFilter(int color, Mode mode) на фоне моего главного вида:

  • myView.getBackground().setColorFilter(Color.RED, PorterDuff.Mode.SRC);

Для целей отладки, я добавил еще один вид, что я могу изменить с помощью View.setBackgroundColor(int color).

проблема в том, что setColorFilter() звонки работают на леденец, но разбиты на предыдущих версиях (в частности Nexus 7 v4.4.4, Galaxy Nexus v4.2.1).


Я называю изменения цвета кода внутри Runnable, который срабатывает через регулярные промежутки времени с помощью Handler.

Обработчик вызывается на всех платформах (я вижу изменения фона из-за отладки вызовов setBackgroundColor()).

Ниже приведен код цвета езда на велосипеде:

Handler mHandler; 
RunnableOnTick thisRunnable; 
View vDebug; 
View vBroken; 

class RunnableOnTick implements Runnable 
{ 
    int backgroundColor; 

    @Override 
    public void run() 
    { 
     color = random.nextInt(2); 

     switch (color) 
     { 
      case 0: 
      { 
       backgroundColor = Color.RED; 
       break; 
      } 
      case 1: 
      { 
       backgroundColor = Color.GREEN; 
       break; 
      } 
     } 

     // this works on all platforms 
     vDebug.setBackgroundColor(backgroundColor); 

     // this works only on Lollipop 
     vBroken.getBackground().setColorFilter(backgroundColor, PorterDuff.Mode.SRC); 
     vBroken.invalidate(); 

     mHandler.postDelayed(thisRunnable, 100); 
    } 
} 

Я пробовал разные PorterDuff.Mode значения - до сих пор не может получить его работу на Android 4.

Чем отличается между Android v4 и v5, который изменит способ работы setColorFilter()?

+0

Какой именно «Drawable» вы используете? Это может зависеть от конкретной реализации. –

+0

@ Dmitry Если я правильно помню, я просто использовал значок зеленой андроидной ракеты-носителя, так как это было доказательством концепции, которую я бросил вместе. В конце я использовал другой метод и не смотрел на это приложение через несколько месяцев. –

+0

Тогда это было «BitmapDrawable». Ну, если у вас больше нет приложения, тогда трудно найти проблему сейчас. Я могу, конечно, сказать, что в KitKat работает цветной фильтр (вы можете просто попробовать использовать атрибут «tint» в «ImageView» - он поддерживается ColorFilter) –

ответ

-4
/** 
    * Tint/Colorise the Supplied {@code drawable} into another color of supplied {@code colorResId} 
    * @param context 
    * @param drawable 
    * @param colorResId 
    * @return 
    */ 
    public Drawable tintThisDrawable(Context context ,Drawable drawable,@ColorRes int colorResId) 
    { 
     Resources res = context.getResources(); 
     int color = res.getColor(colorResId); 
     if (drawable != null) { 
      drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); 
     } 
     return drawable; 
    } 

Я помню эту функцию, работающую где-то в моем проекте. Пожалуйста, проверьте это самостоятельно.

+0

Это почти то, что написано в его ответе –

+0

Ну! теперь я вижу это, он имеет дело с drawables, а не с цветом. Если он может использовать Drawable для установки Background, это сработает. – Y2K

+0

Это именно то, что он делает. Пожалуйста, прочитайте вопрос, прежде чем отвечать. –

0

Вы пробовали прямо так?

vBroken.getBackground().setColorFilter(Color.argb(255, 255, 255, 255),PorterDuff.Mode.MULTIPLY)); 
6

В конце концов, похоже, проблема заключается в том, что KitKat не поддерживает использование ColorFilter (или неявно альфа) на Drawable, что в свою очередь, быть в StateListDrawable. Мое решение было использовать то же самый код для построения сложной вытяжки, а затем делает это в простой BitMapDrawable:

static Drawable createDrawable(Context context, int color, boolean disabled) { 
OvalShape oShape = new OvalShape(); 
ShapeDrawable background = new ShapeDrawable(oShape); 
background.getPaint().setColor(color); 

ShapeDrawable shader = new ShapeDrawable(oShape); 
shader.setShaderFactory(new ShapeDrawable.ShaderFactory() { 
    @Override 
    public Shader resize(int width, int height) { 
     return new LinearGradient(0, 0, 0, height, 
       new int[]{ 
         Color.WHITE, 
         Color.GRAY, 
         Color.DKGRAY, 
         Color.BLACK 
       }, null, Shader.TileMode.REPEAT); 
    } 
}); 

Drawable icon = ContextCompat.getDrawable(context, R.drawable.ic_chat_button).mutate(); 
icon.setColorFilter(context.getResources().getColor(R.color.control_tint_color), PorterDuff.Mode.SRC_IN); 

Drawable layer = new LayerDrawable(new Drawable[]{ shader, background, icon }); 
layer.setAlpha(disabled ? 128 : 255); 

// Note that on KitKat, setting a ColorFilter on a Drawable contained in a StateListDrawable 
// apparently doesn't work, although it does on later versions, so we have to render the colored 
// bitmap into a BitmapDrawable and then put that into the StateListDrawable 
Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 
Canvas canvas = new Canvas(bitmap); 

layer.setBounds(0, 0, layer.getIntrinsicWidth(), layer.getIntrinsicHeight()); 
layer.draw(canvas); 

return new BitmapDrawable(context.getResources(), bitmap); 
} 
+1

У вас есть ссылки на это заявление о том, что KitKat не поддерживает его? –

+0

Нет, у меня нет такой ссылки, но над решением работает ... отметьте мой ответ ... если это поможет .. –

+0

Решите мою проблему, а не только kitkat, но я обнаружил, что она не работает для API < 21, но с этим обходным путем. выиграл щедрость. –

0

Для меня ColorFilter не будет применяться к цветовому элементу в StateListDrawable.

Создание Drawable для представления этого цвета и использование этого вместо этого в StateListDrawable sawColorFilter, работающем на устройствах pre-Lollipop, которые я тестировал.

В качестве побочного примечания я сделал чистый белый Drawable, чтобы цвет тонирования был применен при полной непрозрачности.

2

Там же проблема в AppCompat с соединением Drawable ниже API 21, который мне думает связана: https://code.google.com/p/android/issues/detail?id=191111

Простое решение не использует XML из вводимого коэффициента, но создавать их в коде, а затем применить setColorFilter. Вот почему сработало решение @Hardeep.

Забавные мелочи: В моем случае setColorFilter на созданном XML TextViewdrawableLeft работал нормально, но только при вызове с помощью обработчика кликов/задержки. При вызове в onCreate/onResume и т. Д. Ничего не произошло.

+0

lol благодаря вашим забавным мелочам, потраченным почти 3 часа на поиски решения, публикация замедленного запуска сделала трюк в OnClick – Flux

0

Я была такая же проблема на пре-леденец, я решил заменить:

vBroken.getBackground().setColorFilter(backgroundColor, PorterDuff.Mode.SRC); 

с:

Drawable d = vBroken.getBackground(); 
    d.setColorFilter(backgroundColor, PorterDuff.Mode.MULTIPLY); 
    vBroken.setBackground(d); 
0

Для того, чтобы краска рисуем столько разных государств, как вы хотите на всех андроид версии, вы можете использовать этот вспомогательный класс:

public class MagicDrawable extends StateListDrawable { 

private Map<Integer, Integer> stateColorsMap; 
private int defaultColor; 

public static MagicDrawable create(Drawable drawable, int defaultColor, int pressedColor, int selectedColor){ 
    Map<Integer, Integer> map = new HashMap(); 
    map.put(android.R.attr.state_selected, selectedColor); 
    map.put(android.R.attr.state_pressed, pressedColor); 

    MagicDrawable stateDrawable = new MagicDrawable(drawable, defaultColor, map); 
    return stateDrawable; 
} 

public static MagicDrawable createSelected(Drawable drawable, int defaultColor, int selectedColor){ 
    Map<Integer, Integer> map = new HashMap(); 
    map.put(android.R.attr.state_selected, selectedColor); 

    MagicDrawable stateDrawable = new MagicDrawable(drawable, defaultColor, map); 
    return stateDrawable; 
} 

public static MagicDrawable createPressed(Drawable drawable, int defaultColor, int pressedColor){ 
    Map<Integer, Integer> map = new HashMap(); 
    map.put(android.R.attr.state_pressed, pressedColor); 

    MagicDrawable stateDrawable = new MagicDrawable(drawable, defaultColor, map); 
    return stateDrawable; 
} 

/** 
* Create state list drawable programmatically - just pass drawable, default color of drawable, and Map of (state , color) 
* @param drawable resourse for icons 
* @param defaultColor color for normal state 
* @param stateColorsMap map of for ex. android.R.attr.state_pressed and ColorManager.someColor 
* 
*      Map<Integer, Integer> map = new HashMap<>(); 
map.put(android.R.attr.state_pressed, ColorManager.rose); 
*/ 
public MagicDrawable(Drawable drawable, int defaultColor, Map<Integer, Integer> stateColorsMap) { 
    super(); 
    this.stateColorsMap = stateColorsMap; 
    this.defaultColor = defaultColor; 

    drawable.setColorFilter(defaultColor, PorterDuff.Mode.SRC_IN); 

    if (stateColorsMap != null) { 
     for (int state : stateColorsMap.keySet()) { 
      addState(new int[]{state}, drawable); 
     } 
    } 

    addState(new int[] {}, drawable); 
} 

@Override 
protected boolean onStateChange(int[] states) { 

    if (stateColorsMap == null) { 
     super.setColorFilter(defaultColor, PorterDuff.Mode.SRC_IN); 
     return super.onStateChange(states); 
    } 

    boolean colorSet = false; 

    for (int state : states) { 

     for (int st : stateColorsMap.keySet()){ 

      if (state == st) { 
       super.setColorFilter(stateColorsMap.get(st), PorterDuff.Mode.SRC_IN); 
       colorSet = true; 
       break; 
      } 
     } 
    } 

    if (!colorSet) { 
     super.setColorFilter(defaultColor, PorterDuff.Mode.SRC_IN); 
    } 

    return super.onStateChange(states); 
} 

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

}