android - make - Cómo animar gradiente?
drawcircle android (1)
Mientras buscaba en Google, encontré 2 maneras de hacerlo para Android: use ShaderFactory o extiende View, usando el new Shader(new LinearGradient())
. Ambas respuestas hacen lo mismo: llamadas a new Shader()
View.onDraw(Canvas canvas)
cada llamada al método View.onDraw(Canvas canvas)
. Es realmente caro si el número de tales gradientes animados es más de ~ 3.
Así que lo hice de otra manera. onDraw()
llamar a new
cada onDraw()
, usando un único LinearGradient
precalculado. Así es como se ve (gif, entonces la animación decayó):
El truco consiste en crear LinearGradient
que es colorsCount
veces mayor que View.getWidth()
. Después de eso, puede usar canvas.translate()
, mientras dibuja el degradado, para cambiar su color, para que no haya llamadas new
en onDraw()
.
Para crear degradado, necesita ancho y alto actuales. Lo hice en onSizeChanged()
. También configuré Shader
aquí también.
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = getWidth();
height = getHeight();
LinearGradient gradient = new LinearGradient(
0, height / 2, width * colors.length - 1, height / 2,
colors, null, Shader.TileMode.REPEAT);
fillPaint.setShader(gradient);
shapePath = getParallelogrammPath(width, height, sidesGap);
shapeBorderPath = getParallelogrammPath(width, height, sidesGap);
}
Yo uso path debido a las vistas en paralelogramo, puedes usar lo que quieras. Al implementar el dibujo, debe observar 2 cosas: debe translate()
todo el canvas
en el desplazamiento actual y offset()
su forma de relleno:
@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
}
También debe usar canvas.save()
y canvas.restore()
. Salvará la matriz interna del lienzo para apilarlo y restaurarlo correspondientemente.
Así que lo último que debes hacer es animar gradientOffset
. Puede usar todo lo que desee como ObjectAnimator (Animación de propiedades) . Usé TimeAnimator , porque necesitaba controlar updateTick
e iniciar el desplazamiento directamente. Aquí está mi realización (un poco difícil y dura):
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();
}
El código de View
completo que puedes encontrar aquí