2015-09-21 15 views
6

Próbuję narysować płótno w kształcie serca za pomocą ścieżki w Androidzie. Kod jest w następujący sposób:Android - Wypełnij ścieżkę kolorem częściowo

@Override 
    protected void onDraw(Canvas canvas) { 
     super.onDraw(canvas); 


     // Fill the canvas with background color 
     canvas.drawColor(Color.WHITE); 
     // paint.setShader(null); 

     // Defining of the heart path starts 
     path.moveTo(left + WIDTH/2, top + HEIGHT/4); // Starting point 
     // Create a cubic Bezier cubic left path 
     path.cubicTo(left+WIDTH/5,top, 
       left+WIDTH/4,top+4*HEIGHT/5, 
       left+WIDTH/2, top+HEIGHT); 
     // This is right Bezier cubic path 
     path.cubicTo(left + 3 * WIDTH/4, top + 4 * HEIGHT/5, 
       left + 4 * WIDTH/5, top, 
       left + WIDTH/2, top + HEIGHT/4); 

     paint.setShader(new LinearGradient(0, canvas.getHeight()/4, canvas.getWidth(), canvas.getHeight()/4, new int[]{Color.RED, Color.YELLOW, Color.GREEN}, new float[]{0, 0.6f, 1}, Shader.TileMode.CLAMP)); 

     canvas.drawPath(path, paint); 

     heart_outline_paint.setColor(getResources().getColor(R.color.heart_outline_color)); // Change the boundary color 
     heart_outline_paint.setStrokeWidth(4); 
     heart_outline_paint.setStyle(Paint.Style.STROKE); 
     canvas.drawPath(path, heart_outline_paint); 



    } 

jestem w stanie narysować serce bez problemu i jestem w stanie wypełnić kolor wewnątrz serca za pomocą opcji w programie Paint Fill. Ale powinienem być w stanie dynamicznie napełnić serce zgodnie z niektórymi danymi i nie można go całkowicie wypełnić przez cały czas. Co udało mi się osiągnąć do tej pory jest w następujący sposób:

Heart Shape with Filled Color

zrobiłem szeroko zakrojone poszukiwania i natknąłem się na wiele rzeczy podobnych do tego. Niektóre z nich należą:

  1. Android fill in part of a path?
  2. filling a circle gradually from bottom to top android

doszedłem również całej koncepcji przekształcania kanwę do mapy bitowej i wypełnienie kolor wewnątrz bitmapy używając Flood Fill Algorithm który pozwala użytkownikom wypełnić kolory wewnątrz bitmapa. Nie chcę jednak, aby bitmapa wypełniała kolor, dotykając serca, ale wypełniając, gdy kliknę przycisk akcji.

Pomyślałem, że pomógł mi filling a circle gradually from bottom to top android , ale używa koła i nie jestem dobrze zorientowany w płótnie, co sprawia, że ​​bardzo słabo dostosowuję kod koła do takiego kształtu.

Jeśli ktoś ma jakieś pomysły lub jakiekolwiek wskazówki, jak to osiągnąć, będzie to naprawdę pomocne. Twoje zdrowie. Z góry dziękuję.

P.S: Próbowałem również kilka sztuczek za pomocą setShader w programie Paint, ale nic nie da mi to, co chcę.

EDIT:

Właśnie natknął się pomysł rysując prostokąt nad sercem z innym kolorem samego jako tło płótno tak, że będzie wyglądać jej pół napełniony !! Nadal pracuję nad pomysłem i nie wiem, jak dokładne będzie to dla mnie. Jeśli ktoś ma lepszy pomysł, jesteś mile widziany.

enter image description here

+0

'" Ale powinienem być w stanie dynamicznie napełnić serce zgodnie z niektórymi danymi i nie da się go wypełnić cały czas. "Co oznacza w praktyce? – pskink

+0

Podobnie jak serce musi być wypełnione 10% lub 20% w zależności od punktów zdobytych przez użytkownika. – San

Odpowiedz

1

Użyłem funkcji clipPath dostępnej w Canvas, aby osiągnąć to, czego potrzebowałem. Rysuję serce powyższą metodą i narysuję na nim prostokąt, a ja używam funkcji clipPath, aby wyciąć obszar znajdujący się poza sercem.

 public static double filled_amount = .90; 
    path.moveTo(left_x_moveto, left_y_moveto); 
    path.cubicTo(left_x1, left_y1, left_x2, left_y2, left_x3, left_y3); 
    path.cubicTo(right_x2, right_y2, right_x1, right_y1, left_x_moveto, left_y_moveto); 
    path.close(); 
    Rect rect = new Rect((int)(canvas.getWidth()*.10),(int)(canvas.getHeight()*filled_amount),(int) canvas.getWidth(), (int) canvas.getHeight()); 
     canvas.clipPath(path); 
     paint.setColor(Color.WHITE); 
     paint.setStyle(Paint.Style.FILL); 
     canvas.drawPath(path, paint); 
     canvas.drawRect(rect, rect_paint); 
     heart_outline_paint.setColor(getResources().getColor(R.color.heart_outline_color)); // Change the boundary color 
     heart_outline_paint.setStrokeWidth(15); 
     heart_outline_paint.setStyle(Paint.Style.STROKE); 
     canvas.drawPath(path, heart_outline_paint); 

To da mi pożądany rezultat napełniania serca dynamicznie. Zmiana wartości filled_amount dynamicznie i wywołanie invalidate() spowoduje, że będzie wyglądało, jakby serce było wypełniane dynamicznie.

@ Odpowiedź Henry'ego może być lepsza, ale to mi się udało i nie patrzę głęboko w krawędzie, więc trochę zygzaków tu i tam jest w porządku.

1

Można użyć Bitmap Masking uzyskać częściowo wypełnione serca. Najlepiej tutaj użyć jednej bitmapy do zamaskowania drugiej.

W twoim przypadku możesz mieć wypełniony prostokąt w obszarze roboczym, a następnie masz kształt heart w nowej bitmapie, aby działał jak maska. Następnie można dynamicznie zmieniać wypełnienie serca, zmieniając wysokość prostokąta tła.

Patrz: https://stackoverflow.com/a/33483600/4747587. Zawiera implementację częściowo wypełniając gwiazdę. Pomysł jest taki sam.

+0

Dzięki za odpowiedź, osiągnąłem to, używając Path in Canvas i funkcji clipPath. – San

+0

Tak. Ale 'clipPath' nie obsługuje antyaliasingu. Bazując na innym kształcie, możesz zacząć dostrzegać krawędzie zygzakowate. Jeśli nie masz zbyt wiele szczegółów, a kształt jest odpowiedni, to "clipPath" będzie działał dobrze. – Henry

+0

Nie mam zbyt wiele szczegółów, więc clipPath działa idealnie dla mnie, dzięki za cenne sugestie. – San