当前位置: 代码迷 >> Android >> 在dispatchDraw中交换Android ViewGroup子颜色
  详细解决方案

在dispatchDraw中交换Android ViewGroup子颜色

热度:86   发布时间:2023-08-04 10:03:25.0

我有一个ViewGroup(特别是一个FrameLayout),它应该具有流畅的填充效果,我使用一条动画路径很好地显示了下面的子视图。

问题是,在液体填充线上方,我需要用相反的两种颜色显示子项。 (Black <-> White)如果不简单地迭代位图,就看不到实现此目的的方法,该位图提供了非常糟糕的副本并带有很多别名,并且渲染速度太慢。

这是我在dispatchDraw中的当前功能的简化版本:

@Override
protected void dispatchDraw(Canvas canvas)
{
    filter.setXfermode(null);
    if (subBitmap == null || mLastWidth != mWidth) {
        subBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        subCanvas = new Canvas(subBitmap);
    }
    super.dispatchDraw(subCanvas);
    if (mLiquidPaint == null || mLiquidPath == null || waveOval.size() == 0 || bitmapPixels == null || !mLiquidAnimator.isRunning()) {
        canvas.drawBitmap(subBitmap, 0, 0, filter);
        return;
    }

    if (revealBitmap == null || mLastWidth != mWidth) {
        revealBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        revealCanvas = new Canvas(revealBitmap);
    }
    if (mLastWidth != mWidth) {
        calculateLiquid();
        mLastWidth = mWidth;
    }
    int yOffset = mFillOffset;
    int xOffset = ellipseWidth * -1;
    PointF firstPoint = new PointF();
    PointF lastPoint = new PointF();
    PointF nextPoint = new PointF();
    Pair<Integer, Float> nextWavePoint = wavePoints.get(0);
    PointF ovalPoint = waveOval.get((nextWavePoint.first + mWaveOffset) % waveOval.size());
    lastPoint.set(xOffset + nextWavePoint.second + ovalPoint.x, yOffset + ovalPoint.y);
    mLiquidPath.moveTo(lastPoint.x, lastPoint.y);
    firstPoint.set(lastPoint);
    for (int i = 1; i < wavePoints.size(); i++) {
        nextWavePoint = wavePoints.get(i);
        ovalPoint = waveOval.get((nextWavePoint.first + mWaveOffset) % waveOval.size());
        nextPoint.set(xOffset + nextWavePoint.second + ovalPoint.x, ovalPoint.y + yOffset);
        mLiquidPath.lineTo(nextPoint.x, nextPoint.y);
        lastPoint.set(nextPoint);
    }
    mLiquidPath.lineTo(getWidth(), lastPoint.y);
    mLiquidPath.lineTo(getWidth(), getHeight());
    mLiquidPath.lineTo(0, getHeight());
    mLiquidPath.lineTo(firstPoint.x, firstPoint.y);

    //This definitely draws a nice liquid path that fills from the bottom up.
    revealCanvas.drawPath(mLiquidPath, mLiquidPaint);
    //The next two lines successfully reveal the views underneath
    filter.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
    revealCanvas.drawBitmap(subBitmap, 0, 0, filter);

    filter.setXfermode(null);
    filter.setColorFilter(null);
    canvas.drawBitmap(revealBitmap, 0, 0, filter);
}

我尝试了无数种不同的ColorFilters和传输模式。 孩子们不能让背景透明,让我做更简单的颜色替换。

最后,使用ColorMatrixColorFilter找出了问题,如下所示:

对于两种颜色color1color2你交换它们具有以下ColorMatrix

float[] colorSwapMatrix = new float[] {
    -1, 0, 0, 0, Color.red(color1) + Color.red(color2),    //Red
    0, -1, 0, 0, Color.green(color1) + Color.green(color2),//Green
    0, 0, -1, 0, Color.blue(color1) + Color.blue(color2),  //Blue
    0, 0, 0, 1f, 0                                         //Alpha
}

在绘制了上面的波路径之后,将应用此方法,如下所示:

    //Draw the swapped image above the wave
    filter.setColorFilter(new ColorMatrixColorFilter(colorSwapMatrix));
    filter.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
    revealCanvas.drawBitmap(subBitmap, 0, 0, filter);

    //Draw the regular image below the wave
    filter.setColorFilter(null);
    filter.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
    revealCanvas.drawBitmap(subBitmap, 0, 0, filter);

    //Draw the combined image onto the canvas
    filter.setXfermode(null);
    filter.setColorFilter(null);
    canvas.drawBitmap(revealBitmap, 0, 0, filter);
  相关解决方案