在 dispatchDraw 中交换 Android ViewGroup Child 颜色
Swap Android ViewGroup Child Colors in dispatchDraw
我有一个 ViewGroup(特别是 FrameLayout),它应该有一个流体填充效果,我用一条路径动画,很好地显示下面的 child 视图。
问题是在液体填充线上方我需要显示 children 并且视图的两种颜色颠倒。 (黑色<->白色)如果不简单地遍历位图,我看不到实现此目的的方法,它提供的副本非常差,有很多锯齿,而且渲染速度太慢。
这是我当前在 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 和传输模式,但都无济于事。而且 children 不能让背景透明让我做更简单的颜色替换。
最终使用 ColorMatrixColorFilter
解决了这个问题,如下所述:
对于两种颜色 color1
和 color2
,您将它们与以下 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);
我有一个 ViewGroup(特别是 FrameLayout),它应该有一个流体填充效果,我用一条路径动画,很好地显示下面的 child 视图。
问题是在液体填充线上方我需要显示 children 并且视图的两种颜色颠倒。 (黑色<->白色)如果不简单地遍历位图,我看不到实现此目的的方法,它提供的副本非常差,有很多锯齿,而且渲染速度太慢。
这是我当前在 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 和传输模式,但都无济于事。而且 children 不能让背景透明让我做更简单的颜色替换。
最终使用 ColorMatrixColorFilter
解决了这个问题,如下所述:
对于两种颜色 color1
和 color2
,您将它们与以下 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);