如何设置一个RadialGradient的大小,位置和颜色,或者在GradientDrawable上设置XferMode

时间:2016-10-24 20:47:08

标签: java android shader

这是我在Stackoverflow上的第一个问题,所以对我来说很容易。我试图在一个点周围绘制径向绽放效果,并找到RadialGradient,以及GradientDrawable。然而,两者都没有完全给出解决

以下是我现在正在进行绘图的方式:

//global
PorterDuffXfermode xferMode = new PorterDuffXfermode(PorterDuff.Mode.ADD);
Paint mainP = new Paint();
Paint whiteP = new Paint();
whiteP.setColor(Color.WHITE);
RadialGradient gradient;

// in a drawing method with a canvas
gradient = new RadialGradient((int) x, (int) y, tempRadius, mainP.getColor(),
    0x00000000, Shader.TileMode.CL
mainP.setShader(gradient);
mainP.setXfermode(xferMode);

canvas.drawCircle((int) x, (int) y, tempRadius, mainP);

gradient = new RadialGradient((int) x, (int) y, tempRadius/2, whiteP.getColor(),
      0x00000000, Shader.TileMode.CLAMP);
whiteP.setXfermode(xferMode);
whiteP.setShader(gradient);

canvas.drawCircle((int) x, (int) y, tempRadius/2, whiteP);    

这将给出预期的结果:

curve_fit

然而,新的RadialGradient每帧每帧都会在内存中建立起来。这明显成为一个问题。该类中唯一的公共事物是构造函数,因此每次需要新的大小,位置或颜色时,RadialGradient所能做的就是创建一个新的。我想这样做的原因是因为你将渐变分配给你要绘制它的Paint对象,这允许你使用它的setXferMode()。

另一种方式,使用GradientDrawable,它允许您只创建一个自身实例,因此您可以更改大小,位置和颜色,但它用于绘制自身的Paint对象是私有的,因此您可以' t在其上设置XferMode。这是必要的,这样如果你有一个以上的点,它们不仅仅是相互涂抹。它有一个colorfilter,但它看起来不像colorfilter担心目的地,只有指定的颜色和来源。

由于我是新手,我只能发布两个链接,而不是仅发布两张图片,我将链接回我在reddit上写的相同问题,其中包含所有上下文的图片。 (还没有答案,这就是我来这里的原因,哈哈)

Screenshot

那么,应该怎么做呢,我知道我需要一个班级或另一个班级。据我所知,如果我不需要每次需要不同尺寸,位置或颜色时都必须创建一个新的RadialGradient,那么RadialGradient将是完美的。 GradientDrawable同样很棒,因为你可以只有一个实例,但我需要能够在它使用的绘图上设置XferMode。还有另一个班级,或者我在这两个班级之间遗漏了什么?

谢谢!

1 个答案:

答案 0 :(得分:0)

所以,虽然我确实找到了解决方案,但仍会导致更多问题。我找到的解决方案部分是here。它唯一缺少的是能够改变预分配的RadialGradient位图的颜色。所以我想出了这个:

// Global
int tempRadius;
Paint p = new Paint();
RadialGradient gradient;    
Bitmap circleBitmap = Bitmap.createBitmap((int) (tempRadius * 2.0f), (int) (tempRadius * 2.0f),
Bitmap.Config.ARGB_8888);
Canvas tempCanvas = new Canvas(circleBitmap);
Rect gradBMPRect = new Rect(0,0,200,200);
Rect destRect = new Rect();
int[] hsv = {0,1,1};
PorterDuffColorFilter[] myColors = new PorterDuffColorFilter[360];
PorterDuffXfermode xferMode = new PorterDuffXfermode(PorterDuff.Mode.ADD);


// Initialize
gradient = new RadialGradient(tempRadius, tempRadius, tempRadius, Color.WHITE, 0x00000000, Shader.TileMode.CLAMP);
circleBitmap = Bitmap.createBitmap((int) (100 * 2.0f), (int) (100 * 2.0f),
Bitmap.Config.ARGB_8888);
tempCanvas = new Canvas(circleBitmap);
for(int i = 0; i < 360; i++){
  hsv[0] = i;
  myColors[i] = new PorterDuffColorFilter(Color.HSVtoColor(hsv), PorterDuff.Mode.MULTIPLY)
}

// update/draw
p.setDither(true);
p.setShader(gradient);
tempCanvas.drawCircle(100, 100, 100, p);
p.setXfermode(xferMode);


if(p.getColor() != mainP.getColor()) {
p.setColorFilter(myColors[hue]);
p.setColor(mainP.getColor());

destRect.set((int)x-tempRadius,(int)y-tempRadius,(int)x+tempRadius,(int)y+tempRadius);
canvas.drawBitmap(circleBitmap,gradBMPRect,destRect,p);

p.setColorFilter(null);
destRect.set((int)x-(tempRadius/2),(int)y-(tempRadius/2),(int)x+(tempRadius/2),(int)y+(tempRadius/2));
canvas.drawBitmap(circleBitmap,gradBMPRect,destRect,p);

使用RadialGradient创建一个灰度位图,然后使用HSVtoColor制作360 PorterDuffColorFilters的调色板。所有360都将其模式设置为相乘。绘制这些用于绘制位图的绘制时,请使用其色调指定的ColorFilter。 colorfilter将灰度位图阴影化为滤镜的任何颜色。并没有更多的内存泄漏:))

渲染RadialGradient的位图与使用RadialGradient渲染圆形所需的时间更长。有30个圆圈,我的Galaxy S5每帧画15-20ms,而位图大约需要30-35ms。通过更多的工作和调整,它可能会得到解决。