Проблема с ComposeShader на Android 4.1.1

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

Shader fadeInRight = new LinearGradient(0, 0, pWidth, 0, 0x00000000, 0xFF000000, Shader.TileMode.CLAMP);
Shader blackToWhite = new LinearGradient(0, 0, 0, pHeight, 0xFF000000, 0xFFFFFFFF, Shader.TileMode.CLAMP);
Shader whiteMask = new ComposeShader(blackToWhite, fadeInRight, PorterDuff.Mode.DST_IN);
Shader blackToColor = new LinearGradient(0, 0, pWidth, 0, 0xFF000000, hue, Shader.TileMode.CLAMP);
Shader shader = new ComposeShader(blackToColor, whiteMask, PorterDuff.Mode.SCREEN);
paint.setShader(shader);
...
canvas.drawRect(new Rect(0, 0, pWidth, pHeight), paint);

Здесь проблема: enter image description here

(игнорируйте красную рамку ниже на Android 4.1.1. Я просто говорю о градиенте выше)

Любая идея, что неправильно? Я думаю, что в моем коде что-то не хватает, но я понятия не имею, что.

РЕД. # 1: Если я просто использую whiteMask для setShader, я также получаю разные результаты для обеих систем: на 2.3.7 я вижу текст меню конфигурации (который находится за всплывающим окном), проходящего через прямоугольник градиента. Кроме того, есть градиент от верхнего левого края до нижнего правого края (от черного до белого), но градиент на 4.1.1 идет горизонтально слева направо. Так что это проблема с ComposeShader

РЕДАКТИРОВАТЬ № 2: Я нашел более простой пример для описания проблемы:

Shader shader1 = new LinearGradient(0, 0, 0, pHeight, hue, 0xffffffff, Shader.TileMode.CLAMP);
Shader shader2 = new LinearGradient(0, 0, pWidth, 0, 0xff000000, 0xffffffff, Shader.TileMode.CLAMP);
Shader shader = new ComposeShader(shader1, shader2, PorterDuff.Mode.MULTIPLY);

Итак, у нас есть только вертикальный линейный градиент от любого цвета до черного и горизонтальный линейный градиент от черного до белого. Если мы умножим эти два слоя, мы должны получить правильный прямоугольник (как в левом скриншоте выше). Но на Android 4.1.1 я вижу только градиент shader2. Я также пробовал это в Gimp с двумя слоями, и результат был таким же, как на Android 2.3.7.

Ответы

Ответ 1

Обнаружена проблема: похоже, что это связано с аппаратным ускорением. Как описано здесь 'ComposeShader может содержать только шейдеры разных типов (например, BitmapShader и LinearGradient, но не два экземпляра BitmapShader)', Но: "Если ваше приложение затронуто любой из этих недостающих функций или ограничений, вы можете отключить аппаратное ускорение только для затронутой части вашего приложения, вызвав setLayerType(View.LAYER_TYPE_SOFTWARE, null)."

Я видел, что этот метод доступен с SDK 11. Мое приложение поддерживает все версии, начиная с SDK 7, поэтому я должен проверить, доступен ли этот метод:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

Теперь все отлично.