2015-08-26 1 views
7

Comment animer un dégradé de la couleur # 1 à la couleur # 2? Quelque chose de semblable àComment animer un dégradé?

enter image description here

Je prévois de l'utiliser comme barre de santé pour l'unité (donc, il sera l'animation FINIT commençant par le vert et se terminant par le rouge)

Répondre

22

Alors que googler, je trouvé 2 façons de le faire pour Android: use ShaderFactory ou étend View, en utilisant new Shader(new LinearGradient()). Les deux réponses font la même chose - en appelant new Shader() chaque appel de la méthode View.onDraw(Canvas canvas). C'est vraiment cher si nombre de ces dégradés animés plus de ~ 3.

Donc, je l'ai fait d'une autre manière. J'ai évité d'appeler new tous les onDraw(), en utilisant un seul LinearGradient précalculé. Voilà comment il est ressembler à (gif, animation si cariées):

enter image description here

L'astuce est de créer LinearGradient qui est colorsCount fois plus grande que View.getWidth(). Après cela, vous pouvez utiliser canvas.translate(), tout en dessin gradient, pour changer sa couleur, donc pas new appelle onDraw() du tout.

Pour créer un dégradé, vous avez besoin de la largeur et de la hauteur actuelles. Je l'ai fait en onSizeChanged(). J'ai également mis Shader ici aussi. J'utilise le chemin à cause des vues parallélogrammes, vous pouvez utiliser ce que vous voulez. Lors de la mise en œuvre dessin, vous remarquerez 2 choses: vous devez translate() toute canvas sur la forme actuelle et décalage offset() votre remplissage:

@Override 
protected void onDraw(Canvas canvas) { 
    canvas.save(); 
    canvas.translate(-gradientOffset, 0); 
    shapePath.offset(gradientOffset, 0f, tempPath); 
    canvas.drawPath(tempPath, fillPaint); 
    canvas.restore(); 

    canvas.drawPath(shapeBorderPath, borderPaint); 

    super.onDraw(canvas); // my View is FrameLayout, so need to call it after 
} 

Aussi, vous devez utiliser canvas.save() & canvas.restore(). Cela permettra d'économiser la matrice interne de la toile à empiler et de la restaurer en conséquence.

Donc le dernier ce que vous devez faire est d'animer gradientOffset. Vous pouvez utiliser tout ce que vous voulez comme ObjectAnimator (Property Animation). J'ai utilisé TimeAnimator, parce que je devais contrôler updateTick et commencer le décalage directement. Voici ma réalisation (un peu difficile et dure):

static public final int LIFETIME_DEAFULT = 2300; 
private long lifetime = LIFETIME_DEAFULT, updateTickMs = 25, timeElapsed = 0; 
private long accumulatorMs = 0; 
private float gradientOffset = 0f; 

public void startGradientAnimation() { 
    stopGradientAnimation(); 
    resolveTimeElapsed(); 

    final float gradientOffsetCoef = (float) (updateTickMs)/lifetime; 
    final int colorsCount = this.colors.length - 1; 
    gradientAnimation.setTimeListener(new TimeAnimator.TimeListener() { 
     @Override 
     public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) { 
      final long gradientWidth = width * colorsCount; 
      if (totalTime > (lifetime - timeElapsed)) { 
       animation.cancel(); 
       gradientOffset = gradientWidth; 
       invalidate(); 
      } else { 
       accumulatorMs += deltaTime; 

       final long gradientOffsetsCount = accumulatorMs/updateTickMs; 
       gradientOffset += (gradientOffsetsCount * gradientWidth) * gradientOffsetCoef; 
       accumulatorMs %= updateTickMs; 

       boolean gradientOffsetChanged = (gradientOffsetsCount > 0) ? true : false; 
       if (gradientOffsetChanged) { 
        invalidate(); 
       } 
      } 
     } 
    }); 

    gradientAnimation.start(); 
} 

Le code View complet, vous pouvez trouver here

+0

Je ne comprends pas ... vous avez posé la question et a répondu en même temps le même jour? Ce n'était jamais une question. –

+4

@ Chris-Jr, j'ai beaucoup cherché et je n'ai pas trouvé la réponse que je voulais. J'ai donc fait une sorte de recherche et finalement je l'ai eu. Puis j'ai pensé "hm, peut-être que quelqu'un d'autre va le chercher dans le futur et être coincé avec comme je le fais?" - Alors j'ai créé la question avec la réponse. En outre, il y a une fonctionnalité intégrée pour le faire. Essayez de cliquer sur "Poser une question". Il y a un chèque 'Réponds à ta propre question - partage tes connaissances, Q & A-style' – Nexen

+0

Ah, d'accord, je suis juste confus par le timing. Merci pour cela, et merci de partager votre solution. –