studio make drawpath drawcircle custom create control android animation gradient android-custom-view ondraw

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í

Cómo animar degradado del color # 1 al color # 2? Algo similar a

Estoy planeando usarlo como barra de salud para la unidad (por lo tanto, se terminará la animación comenzando con verde y terminando con rojo)