2011-01-18 12 views
9

Potrzebuję pomalować tło mojego płótna jednym kolorem z zastosowanym cieniowaniem/gradientem, ale każde wywołanie onDraw chcę zmienić kolor.Jak pomalować kolor gradientu w systemie Android na płótnie ze zmianą kolorów?

Mam problem z wykonaniem tego bez tworzenia nowego obiektu dla każdego wywołania onDraw. Ktoś ma jakieś pomysły? Jeśli użyję funkcji drawPaint() i ustawię nowy moduł cieniujący() do mojego obrazu, to utworzę nowy obiekt cieniujący i jeśli utworzę nowy obiekt GradientDrawable(), również go mam. Chcę uniknąć GC.

Pomyślałem, że mogę ponownie użyć jednego obiektu GradientDrawable() i zadzwonić do metody .setColor(), ale to po prostu resetuje wszystkie powiązane dane gradientem i maluje rysunki jako stały kolor.

Ktoś?

Odpowiedz

5

Niestety za każdym razem trzeba utworzyć nowy LinearGradient. Zauważ, że nie musisz używać GradientDrawable, możesz narysować kształt samodzielnie przy pomocy Paint, na którym ustawisz moduł cieniujący.

+0

Dzięki Romain, czy mógłbyś podzielić się z tobą swoją wiedzą na temat mojego komentarza do campingu? Zastanawiam się, jaka jest najbardziej efektywna metoda .draw ...(), to albo narysuj dwie warstwy wymagane do stworzenia tego efektu, albo jeśli LayerDrawable jest dokładnie tym, czego potrzebuję. – Greg

+0

@Romain Guy Próbowałem użyć SweepGradient, aby uzyskać stożkowy efekt gradientu.Ale wydaje się, że działa tylko z dwoma kolorami. Jeśli używam tablicy czterech kolorów, ** SweepGradient ** nie działa zgodnie z oczekiwaniami. Próbowałem różnych kombinacji wartości ** position, a także próbowałem ustawień pozycji jako ** NULL **, ale większość otrzymuję tylko dwa kolory lub gradient, który nie jest stożkowy. Każda pomoc byłaby bardzo cenna. –

0

Myślę, że to, co chcesz zrobić, to jest to. Utwórz LayerDrawable, a następnie wstaw do niego dwa Drawables. Pierwsza wstawka do wstawienia powinna mieć kolor ustawiony na kolor, który ma być tłem, a druga powinna być gradientem ustawionym na czarny i przejściem z alfa 0 na alfa 255.

Więcej informacji informacje, zobacz: http://developer.android.com/guide/topics/resources/drawable-resource.html#LayerList

+0

campnic - dziękuję za to, do czego dążyłem, gdy myślałem o wywołaniu canvas.drawARGB() z alpha xFF, a następnie pomalowanie w cieniu lub gradientu z mniejszą alfa na wierzchu. Martwię się tylko o wydajność. Chciałem uniknąć rysowania całego płótna z dwiema warstwami i chciałem się dowiedzieć, czy istnieje wbudowany konstruktor, aby zrobić to za jednym razem. Czy warstwa LayerDrawable może to osiągnąć, czy faktycznie tworzy kolejne warstwy po warstwie? – Greg

+0

Zrobiłem trochę kopania, a to, co widzę, sugeruje, że skończyłoby się rysowanie dwóch pełnych warstw na całym ekranie. Kod dla LayerDrawable.draw tylko iteruje nad dzieckiem Drawables w malejącej kolejności indeksowej. Myślę, że wydajność warstwy LayerDRawable może nie być tym, czego chcesz użyć. Romain ma o wiele więcej doświadczenia z tymi rzeczami, więc prawdopodobnie może dać ci lepszy pomysł :) –

+0

Naprawdę doceniam, że tego chcesz - to także znalazłem i podejrzewałem, przeglądając dokumentację. Będę musiał wymyślić coś kreatywnego na ładne dynamiczne tło, jeśli nie ma wbudowanego rozwiązania. – Greg

0

To pytanie jest nadal aktualne prawie w połowie 2017 roku. Chciałem stworzyć płynne przejście dla zmian kolorów dla mojego widoku niestandardowego. Użyłem shaderów z LinearGradients.

Moim zamiarem było sprawne przejście między stanem włączenia i wyłączenia mojego widoku.

Moja sprawa jest jeszcze bardziej skomplikowana ze względu na konstrukcję i cel widoku. To suwak. Tak więc mój widok składa się z prawie 2 identycznych warstw narysowanych jedna na drugiej za pomocą płótna. Trzecim elementem jest wskaźnik.

Obie warstwy używają LinearGradients, wskaźnik używa jednego koloru.

zsumowanie wszystkich trzeba wykonać przejście między 5 kolorów jednocześnie:

  • start i barwą dla dolnej warstwy - jeden lineargradient,
  • początkowy i końcowy kolor warstwy wierzchniej - druga lineargradient ,
  • kolor wskaźnika - normalny kolor;

Rozwiązaniem tego problemu jest posiadanie 5 oddzielnych ValueAnimatorów. Najważniejszą rzeczą jest, aby używać ValueAnimator.ofArgb():

private ValueAnimator frontStartColorAnimator; 
private ValueAnimator frontEndColorAnimator; 
private ValueAnimator bottomStartColorAnimator; 
private ValueAnimator bottomEndColorAnimator; 
private ValueAnimator pointerColorAnimator; 
private AnimatorSet colorsAnimatorSet; 

... 

frontStartColorAnimator = ValueAnimator.ofArgb(frontLayerStartColor, frontLayerDisabledStartColor); 
frontStartColorAnimator.setDuration(animationDuration); 
frontStartColorAnimator.setInterpolator(new LinearInterpolator()); 
frontStartColorAnimator.addUpdateListener(animation 
      -> shaderFrontLayerStartColor = (int) animation.getAnimatedValue()); 

frontEndColorAnimator = ValueAnimator.ofArgb(frontLayerEndColor, frontLayerDisabledEndColor); 
frontEndColorAnimator.setDuration(animationDuration); 
frontEndColorAnimator.setInterpolator(new LinearInterpolator()); 
frontEndColorAnimator.addUpdateListener(animation -> { 
     shaderFrontLayerEndColor = (int) animation.getAnimatedValue(); 
     frontLayerPaint.setShader(new LinearGradient(0, 0, getWidth(), 0, shaderFrontLayerStartColor, 
       shaderFrontLayerEndColor, Shader.TileMode.CLAMP)); 
    }); 

bottomStartColorAnimator = ValueAnimator.ofArgb(bottomLayerStartColor, bottomLayerDisabledStartColor); 
bottomStartColorAnimator.setDuration(animationDuration); 
bottomStartColorAnimator.setInterpolator(new LinearInterpolator()); 
bottomStartColorAnimator.addUpdateListener(animation -> 
      shaderBottomLayerStartColor = (int) animation.getAnimatedValue()); 

bottomEndColorAnimator = ValueAnimator.ofArgb(bottomLayerEndColor, bottomLayerDisabledEndColor); 
bottomEndColorAnimator.setDuration(animationDuration); 
bottomEndColorAnimator.setInterpolator(new LinearInterpolator()); 
bottomEndColorAnimator.addUpdateListener(animation -> { 
     shaderBottomLayerEndColor = (int) animation.getAnimatedValue(); 
     backLayerPaint.setShader(new LinearGradient(0, 0, 0, getHeight(), shaderBottomLayerStartColor, 
       shaderBottomLayerEndColor, Shader.TileMode.CLAMP)); 
    }); 

pointerColorAnimator = ValueAnimator.ofArgb(pointerEnabledColor, pointerDisabledColor); 
pointerColorAnimator.setDuration(animationDuration); 
pointerColorAnimator.setInterpolator(new LinearInterpolator()); 
pointerColorAnimator.addUpdateListener(animation -> { 
     pointerColor = (int) animation.getAnimatedValue(); 
     pointerPaint.setColor(pointerColor); 
    }); 

colorsAnimatorSet = new AnimatorSet(); 
colorsAnimatorSet.playTogether(frontStartColorAnimator, frontEndColorAnimator, 
      bottomStartColorAnimator, bottomEndColorAnimator, pointerColorAnimator); 

... 

colorsAnimatorSet.start(); 

Ja też na początku chodziło o stworzenie nowego lineargradient na każdej aktualizacji animacji ale potem rozpoczęła profilowanie GPU na urządzeniu z „Na ekranie barów” . Wszystko jest w porządku i działa w bezpiecznym marginesie.

Powiązane problemy