2012-01-27 25 views
21

Próbuję utworzyć łuk (zmienną liczbę stopni), który stopniowo przechodzi od jednego koloru do drugiego. Z przykładu z niebieskiego na czerwony:

enter image description hereAndroid - Jak narysować gradient w oparciu o łuk

To jest mój kod:

SweepGradient shader = new SweepGradient(center.x, center.y, resources.getColor(R.color.startColor),resources.getColor(R.color.endColor)); 
Paint paint = new Paint() 
paint.setStrokeWidth(1); 
paint.setStrokeCap(Paint.Cap.FILL); 
paint.setStyle(Paint.Style.FILL); 
paint.setShader(shader); 
canvas.drawArc(rectF, startAngle, sweepAngle, true, paint); 

Ale wynik jest cały łuk jest pomalowany w tym samym kolorze.

Edit:
Po więcej eksperymentowanie, okazało się, że spread kolor zależy od kąta łuku. Jeśli rysuję łuk pod małym kątem, wyświetlany jest tylko pierwszy kolor. Im większy kąt, tym więcej kolorów zostanie narysowanych. Jeśli kąt jest mały, wydaje się, że nie ma gradientu.
Oto przykład. Mam rysunek 4 łuków - 90, 180, 270 i 360:

RectF rect1 = new RectF(50, 50, 150, 150); 
Paint paint1 = new Paint(); 
paint1.setStrokeWidth(1); 
paint1.setStrokeCap(Paint.Cap.SQUARE); 
paint1.setStyle(Paint.Style.FILL); 

SweepGradient gradient1 = new SweepGradient(100, 100, 
     Color.RED, Color.BLUE); 
paint1.setShader(gradient1); 

canvas.drawArc(rect1, 0, 90, true, paint1); 

RectF rect2 = new RectF(200, 50, 300, 150); 
Paint paint2 = new Paint(); 
paint2.setStrokeWidth(1); 
paint2.setStrokeCap(Paint.Cap.SQUARE); 
paint2.setStyle(Paint.Style.FILL); 

SweepGradient gradient2 = new SweepGradient(250, 100, 
     Color.RED, Color.BLUE); 
paint2.setShader(gradient2); 

canvas.drawArc(rect2, 0, 180, true, paint2); 

RectF rect3 = new RectF(50, 200, 150, 300); 
Paint paint3 = new Paint(); 
paint3.setStrokeWidth(1); 
paint3.setStrokeCap(Paint.Cap.SQUARE); 
paint3.setStyle(Paint.Style.FILL); 

SweepGradient gradient3 = new SweepGradient(100, 250, 
     Color.RED, Color.BLUE); 
paint3.setShader(gradient3); 

canvas.drawArc(rect3, 0, 270, true, paint3); 

RectF rect4 = new RectF(200, 200, 300, 300); 
Paint paint4 = new Paint(); 
paint4.setStrokeWidth(1); 
paint4.setStrokeCap(Paint.Cap.SQUARE); 
paint4.setStyle(Paint.Style.FILL); 

SweepGradient gradient4 = new SweepGradient(250, 250, 
     Color.RED, Color.BLUE); 
paint4.setShader(gradient4); 

canvas.drawArc(rect4, 0, 360, true, paint4); 

A oto wynik:

enter image description here

Jest to zaskakujące, ponieważ będę oczekiwać RED być na początek łuku, NIEBIESKI na końcu i cały obiekt pomiędzy równomiernie rozłożony, niezależnie od kąta.
Próbowałem przestrzeni kolorów ręcznie za pomocą parametru pozycje, ale wyniki były takie same:

int[] colors = {Color.RED, Color.BLUE}; 
float[] positions = {0,1}; 
SweepGradient gradient = new SweepGradient(100, 100, colors , positions); 

Każdy pomysł jak rozwiązać ten problem?

Odpowiedz

27

Rozwiązaniem tego problemu jest ustawienie pozycji NIEBIESKIEJ. Odbywa się to tak:

int[] colors = {Color.RED, Color.BLUE}; 
float[] positions = {0,1}; 
SweepGradient gradient = new SweepGradient(100, 100, colors , positions); 

Problemem jest to, że przy ustalaniu pozycji niebieskiego na „1”, to nie oznacza, że ​​zostanie on umieszczony na końcu narysowanej łuku, ale zamiast na końcu koła, którego częścią jest łuk. Aby rozwiązać ten problem, pozycja NIEBIESKA powinna uwzględniać liczbę stopni w łuku. Więc jeśli Rysuję łuk o X stopni, pozycja zostanie ustawiona tak:

float[] positions = {0,Xf/360f}; 

więc jeśli X jest 90, gradient umieści NIEBIESKI 0,25 okręgu:

enter image description here

+1

Przynajmniej na Android 4.2, rozwiązanie podane jako nie działa.Na końcu tablicy istnieje potrzeba posiadania wartości 1. Coś takiego: int [] colors = {Color.RED, Color.BLUE, Color.BLUE}; float [] pozycje = {0, Xf/360f, 1}; –

+0

Czy wiesz, dlaczego rozdzielczość jest tak zła, jeśli kąt jest bardzo mały? jak łuk o szerokości 10 stopni oznacza tylko 3 kolory. Możesz zobaczyć kroki również na zrzucie ekranu w topleft cake –

9

Aby dodać do rozwiązania Yoav's.

Na moim Galaxy Nexus 4.2 na stanie Android, podane rozwiązanie nie działa.

Jeśli tablica nie zawiera 0.0f i 1.0f, wygląda na to, że jest zignorowana.

Moje ostateczne rozwiązanie było:

int[] colors = {Color.RED, Color.BLUE, Color.RED}; 
float[] positions = {0, Xf/360f, 1}; 
1

pięć lat później, ale we właściwy sposób to zrobić 0.749f z 0.750f odrębnej linii, prosty kod jest podobny:

val colors = intArrayOf(0xffff0000.toInt(), 0xff0000ff.toInt(), 0xffff0000.toInt(), 0xffff0000.toInt()) 
    val positions = floatArrayOf(0.0f, 0.749f, 0.750f, 1.0f) 
+0

dzięki za umieszczenie Kotlin – rundavidrun