2016-10-24 5 views
2

Dies ist meine erste Frage hier auf Stackoverflow, also gehen Sie einfach auf mich. Ich versuche, einen radialen Bloom-Effekt um einen Punkt herum zu zeichnen und finde RadialGradient sowie GradientDrawable. Jedoch gibt keine vollständige Lösung.Wie man Größe, Position und Farbe eines RadialGradient einstellt oder XferMode auf GradientDrawable setzt

Hier ist, wie ich die Zeichnung gerade jetzt so mache:

//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);  

Dies gibt das erwartete Ergebnis:

Screenshot

jedoch die neue RadialGradient jedes Bild im Speicher aufbaut pro Punkt. Was später offensichtlich ein Problem wird. Die einzige öffentliche Sache in dieser Klasse ist ein Konstruktor. Alles, was Sie mit RadialGradient tun können, ist, jedes Mal, wenn Sie eine neue Größe, Position oder Farbe benötigen, ein neues Objekt zu erstellen. Der Grund, warum ich das so machen will, ist, dass Sie dem Paint-Objekt, mit dem Sie es zeichnen wollen, den Farbverlauf zuweisen, mit dem Sie setXferMode() verwenden können. Der andere Weg, mit GradientDrawable, ermöglicht es Ihnen, nur eine Instanz von sich selbst zu erstellen, so dass Sie die Größe, Position und Farbe ändern können, aber das Paint-Objekt, das verwendet wird, um sich selbst zu malen, ist privat Setzen Sie den XferMode nicht darauf. Das ist notwendig, damit Sie, wenn Sie mehr als einen Punkt haben, nicht nur übereinander malen. Es hat einen Farbfilter, aber es sieht nicht aus wie Farbfilter sich Sorgen um das Ziel macht, nur eine bestimmte Farbe und die Quelle.

Da ich neu bin, kann ich nur zwei Links posten, und anstatt nur zwei Bilder zu posten, verlinke ich auf die gleiche Frage, die ich auf reddit geschrieben habe, die alle Bilder für den Kontext enthält. (Und noch keine Antworten, weshalb ich hier bin, ha ha)

https://www.reddit.com/r/learnandroid/comments/590uce/having_a_shader_issue_using_radialgradient_and/

Also, wie sollte dies geschehen, ich weiß, ich brauche eine Klasse oder das andere. Soweit ich das beurteilen kann, wäre RadialGradient perfekt, wenn ich nicht jedes Mal ein neues erstellen müsste, wenn ich eine andere Größe, Position oder Farbe benötige. GradientDrawable wäre genauso groß, da Sie nur eine Instanz haben können, aber ich muss in der Lage sein, den XferMode auf die Farbe einzustellen, die er verwendet. Gibt es eine andere Klasse, oder fehlt mir etwas zwischen diesen beiden?

Danke !!

Antwort

0

Also, während ich eine Lösung gefunden habe, führt es immer noch zu mehr Problemen. Die Lösung, die ich fand, war teilweise here. Das einzige, was es vermisste, war die Farbe der zuvor zugewiesenen RadialGradient Bitmap ändern zu können. So kam ich mit auf den Punkt:

// 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); 

Mit diesem der RadialGradient verwendet, um ein Graustufen Bitmap zu erstellen, wird eine Palette von 360 PorterDuffColorFilters verwendet HSVtoColor gemacht. Alle 360 ​​haben ihre Modi zum Multiplizieren eingestellt. Wenn Sie diese Farbe zum Zeichnen der Bitmap verwenden, verwenden Sie den durch den Farbton angegebenen ColorFilter. Der Farbfilter schattiert die Graustufen-Bitmap auf die Farbe des Filters. Und keine weiteren Speicherlecks :)

Dies dauerte länger, um die Bitmap eines RadialGradient vs Rendern eines Kreises mit einem RadialGradient zu rendern. Mit 30 Kreisen brauchte mein Galaxy S5 15-20ms pro Frame Draw, während die Bitmaps etwa 30-35ms benötigten. Es könnte wahrscheinlich mit ein wenig mehr Arbeit und Anpassung ausgearbeitet werden.

Verwandte Themen