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):
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
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. –
@ 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
Ah, d'accord, je suis juste confus par le timing. Merci pour cela, et merci de partager votre solution. –