Цветовые эффекты PorterDuff в android для просмотра под данным видом

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

filtering view

Простое прямоугольное представление, которое инвертирует цвета всего под ним. Конечно, когда пользователь прокручивает список, он также отображается в перевернутом поле. Есть ли простой способ сделать это, используя цветные фильтры, режимы PorterDuff и т.д.

Ответ 1

Вы пытаетесь решить эту проблему, используя иерархию вида, например:

  • Родитель
    • ListView
    • InverterView

Проблема в том, что InverterView не имеет контроля над тем, как рисуется ListView. Но вы знаете, кто имеет контроль над тем, как рисуется ListView? ListView родительский макет. Другими словами, то, что вы действительно хотите, - это такая иерархия:

  • Родитель
    • InverterLayout
      • ListView

Теперь InverterLayout отвечает за рисование ListView и может применять к нему эффекты.

class InverterLayout extends FrameLayout
{
    // structure to hold our color filter
    private Paint paint = new Paint();
    // the color filter itself
    private ColorFilter cf;
    // the rectangle we want to invert
    private Rect inversion_rect = new Rect(100, 100, 300, 300);

    public InverterLayout(Context context)
    {
        super(context);
        // construct the inversion color matrix
        float[] mat = new float[]
        {
            -1,  0,  0, 0,  255,
             0, -1,  0, 0,  255,
             0,  0, -1, 0,  255,
             0,  0,  0, 1,  0
        };
        cf = new ColorMatrixColorFilter(new ColorMatrix(mat));
    }

    @Override protected void dispatchDraw(Canvas c)
    {
        // create a temporary bitmap to draw the child views
        Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
        Canvas cc = new Canvas(b);
        // draw them to that temporary bitmap
        super.dispatchDraw(cc);
        // copy the temporary bitmap to screen without the inversion filter
        paint.setColorFilter(null);
        c.drawBitmap(b, 0, 0, paint);
        // copy the inverted rectangle
        paint.setColorFilter(cf);
        c.drawBitmap(b, inversion_rect, inversion_rect, paint);
    }
}

При использовании этого параметра убедитесь, что у вашего дочернего представления есть собственный фон. Если представление прозрачно и фон окна показывает, этот фон окна не будет инвертирован, потому что InverterLayout не имеет никакого контроля над тем, как выглядит окно.

Ответ 2

Если бы я мог просто прокомментировать это, потому что я не уверен, что я здесь прав. Поэтому покупатель остерегается, вот оно:

Я думаю, что вы сможете достичь этого эффекта, воспользовавшись View.OnDragEve [] ntListener. Здесь документация.

Я думаю, вы должны настроить триггерную модель перетаскивания, используемую в android (т.е. средства для связи между приложением и ОС). Как вы его настраиваете, это будет полностью зависеть от механизма (ов) в вашем приложении, который заставляет один вид в границах другого. Как только вы это выясните, вы сможете сделать расширенную цветовую магию с помощью: ColorMatrix, PorterDuffColorFilter и несколько других.

Мне это намного легче, чем альтернатива Xfermode. Удачи!

Ответ 3

Вот что я сделал бы:

Просмотр иерархии:

  • RelativeLayout (или FrameLayout)
    • ListView
      • CustomInverterView

InverterView позиционируется OnTouch родительского представления (RelativeLayout)  в onTouchListener:

if (event.getAction() == MotionEvent.ACTION_MOVE)
           // Set Coordinates for the custom View.
           // Copy the bitmapCache of the ListView (jsut the portion you need
           // and send it to the customView.
           // Apply the filters you want.
           // Invalidate!

Я использовал этот луп, используя этот метод. Отлично работает. Возможно, я смогу опубликовать еще несколько кода позже, но сейчас я немного занят.