解决方法
在谷歌搜索时,我找到了两种方法来为android:
use ShaderFactory或扩展View,使用新的Shader(新的LinearGradient()).两个答案都是一样的 – 每次调用View.onDraw(Canvas canvas)方法调用新的Shader().如果这样的动画渐变数量超过~3,它真的很贵.
所以我采取了另一种方式.我使用单个预先计算的LinearGradient避免使用onDraw()调用new.这就是它的样子(gif,所以动画衰败):
诀窍是创建LinearGradient,它的colorsCount大于View.getWidth().之后,您可以使用canvas.translate(),同时绘制渐变,以更改其颜色,因此onDraw()中根本没有新的调用.
要创建渐变,您需要当前的宽度和高度.我是在onSizeChanged()中完成的.我也在这里设置了Shader.
@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,colors,null,Shader.TileMode.REPEAT); fillPaint.setShader(gradient); shapePath = getParallelogrammPath(width,height,sidesGap); shapeBorderPath = getParallelogrammPath(width,sidesGap); }
我使用路径因为平行四边形视图,你可以使用你想要的任何东西.在实现绘图时,您应该注意两件事:您需要在当前偏移量上翻译()整个画布,并在填充形状上使用offset():
@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 }
你也应该使用canvas.save()& canvas.restore().它会将canvas的内部矩阵保存到堆栈中并相应地恢复它.
所以你需要做的最后一件事是为gradientOffset设置动画.你可以使用你想要的一切,如ObjectAnimator (Property Animation).我使用TimeAnimator,因为我需要控制updateTick并直接开始偏移.这是我的认识(有点困难和苛刻):
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(); }