Android 如何设置渐变动画?

Android 如何设置渐变动画?,android,animation,gradient,android-custom-view,ondraw,Android,Animation,Gradient,Android Custom View,Ondraw,如何设置从颜色1到颜色2的渐变动画?类似于 我计划将它用作unit的健康栏(因此,它将是以绿色开始,以红色结束的有限动画)在谷歌搜索它时,我发现了两种方法用于android:或扩展视图,使用新着色器(new LinearGradient())。两个答案的作用相同-调用newshader()everyView.onDraw(Canvas Canvas)method的调用。如果此类动画渐变的数量超过~3,则其成本将非常昂贵 所以我用另一种方法。我避免调用neweveryonDraw(),使用单个预

如何设置从颜色1到颜色2的渐变动画?类似于


我计划将它用作unit的健康栏(因此,它将是以绿色开始,以红色结束的有限动画)

在谷歌搜索它时,我发现了两种方法用于android:或扩展视图,使用
新着色器(new LinearGradient())
。两个答案的作用相同-调用
newshader()
every
View.onDraw(Canvas Canvas)
method的调用。如果此类动画渐变的数量超过~3,则其成本将非常昂贵

所以我用另一种方法。我避免调用
new
every
onDraw()
,使用单个预先计算的
LinearGradient
。这就是它的样子(gif,所以动画衰减):

诀窍是创建
LinearGradient
,它比
View.getWidth()大
colorsCount
倍。之后,您可以在绘制渐变时使用
canvas.translate()

要创建渐变,需要当前的宽度和高度。我是在
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, height / 2,
            colors, null, Shader.TileMode.REPEAT);
    fillPaint.setShader(gradient);

    shapePath = getParallelogrammPath(width, height, sidesGap);
    shapeBorderPath = getParallelogrammPath(width, height, sidesGap);
}
我使用路径,因为平行四边形视图,你可以使用任何你想要的。在执行绘图时,您应该注意两件事:您需要对当前偏移量进行
translate()
整个
canvas
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()
。它将保存画布的内部矩阵以进行堆栈并相应地恢复

因此,您需要做的最后一件事是设置
gradientOffset
的动画。你想用什么就用什么。我使用了,因为我需要直接控制
updateTick
和起始偏移量。以下是我的体会(有点困难和苛刻):


完整的
视图
您可以找到的代码

我找到了不同的、更短的方法。只需使用
setColors(int[]colors)
GradientDrawable的方法
并随时间对其进行动画制作

这是一个如何执行此操作的示例:

val start = Color.DKGRAY
val mid = Color.MAGENTA
val end = Color.BLUE

//content.background is set as a GradientDrawable in layout xml file 
val gradient = content.background as GradientDrawable

val evaluator = ArgbEvaluator()
val animator = TimeAnimator.ofFloat(0.0f, 1.0f)
animator.duration = 1500
animator.repeatCount = ValueAnimator.INFINITE
animator.repeatMode = ValueAnimator.REVERSE
animator.addUpdateListener {
    val fraction = it.animatedFraction
    val newStart = evaluator.evaluate(fraction, start, end) as Int
    val newMid = evaluator.evaluate(fraction, mid, start) as Int
    val newEnd = evaluator.evaluate(fraction, end, mid) as Int

    gradient.colors = intArrayOf(newStart, newMid, newEnd)
}

animator.start()
结果是:


刚刚重写了@Krzysztof Misztal对
java
的回答:

public static void startAnimation(final int view, final Activity activity) {
        final int start = Color.parseColor("#FDB72B");
        final int mid = Color.parseColor("#88FDB72B");
        final int end = Color.TRANSPARENT;


        final ArgbEvaluator evaluator = new ArgbEvaluator();
        View preloader = activity.findViewById(R.id.gradientPreloaderView);
        preloader.setVisibility(View.VISIBLE);
        final GradientDrawable gradient = (GradientDrawable) preloader.getBackground();

        ValueAnimator animator = TimeAnimator.ofFloat(0.0f, 1.0f);
        animator.setDuration(500);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.REVERSE);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                Float fraction = valueAnimator.getAnimatedFraction();
                int newStrat = (int) evaluator.evaluate(fraction, start, end);
                int newMid = (int) evaluator.evaluate(fraction, mid, start);
                int newEnd = (int) evaluator.evaluate(fraction, end, mid);
                int[] newArray = {newStrat, newMid, newEnd};
                gradient.setColors(newArray);
            }
        });

        animator.start();
    }




public static void stopAnimation(final int view, final Activity activity){

    ObjectAnimator.ofFloat(activity.findViewById(view), "alpha", 0f).setDuration(125).start();
}
其中
视图
是具有渐变背景的简单
视图

//gradient_preloader
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <gradient
        android:startColor="#FDB72B"
        android:endColor="#00000000"
        android:angle="0"/>
</shape>
//gradient\u预加载程序
观点:

<View
    android:id="@+id/gradientPreloaderView"
    android:layout_width="match_parent"
    android:visibility="gone"
    android:layout_height="@dimen/basic_8_dp"
    android:background="@drawable/gradient_preloader" />


希望我的答案能帮助你找到最新的备选答案

class GradientAnimationDrawable(
  start: Int = Color.rgb(0, 143, 209),
  center: Int = Color.rgb(1, 106, 154),
  end: Int = Color.rgb(28, 179, 249),
  frameDuration: Int = 3000,
  enterFadeDuration: Int = 0,
  exitFadeDuration: Int = 3000
) : AnimationDrawable() {

  private val gradientStart = GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, intArrayOf(start, center, end))
    .apply {
      shape = GradientDrawable.RECTANGLE
      gradientType = GradientDrawable.LINEAR_GRADIENT
    }

  private val gradientCenter = GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, intArrayOf(center, end, start))
    .apply {
      shape = GradientDrawable.RECTANGLE
      gradientType = GradientDrawable.LINEAR_GRADIENT
    }

  private val gradientEnd = GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, intArrayOf(end, start, center))
    .apply {
      shape = GradientDrawable.RECTANGLE
      gradientType = GradientDrawable.LINEAR_GRADIENT
    }

  init {
    addFrame(gradientStart, frameDuration)
    addFrame(gradientCenter, frameDuration)
    addFrame(gradientEnd, frameDuration)
    setEnterFadeDuration(enterFadeDuration)
    setExitFadeDuration(exitFadeDuration)
    isOneShot = false
  }

}


我不明白。。。你在同一天的同一时间提出并回答了这个问题?“这从来不是一个问题,是吗?”小克里斯,我搜索了很多,没有找到我想要的答案。所以我做了一些研究,最终得到了它。然后我想,“嗯,也许将来会有其他人搜索它,然后像我一样被困在里面?”-所以我用答案创造了这个问题。此外,还有一个内置功能可以实现这一点。尝试单击询问问题
。这里有一个检查
回答你自己的问题-分享你的知识,问答式
啊,好的,我明白了,我只是被时间弄糊涂了。谢谢,谢谢分享你的解决方案。谢谢Nexen,这绝对是正确的做法。我很感激你的回答,我很高兴能从你的回答开始我自己的研究。谢谢你的指点,节省了时间。同样,TimeAnimator需要api16,带有AnimatorUpdateListener的Objectanimator也会这样做。你能用Java写吗?
class GradientAnimationDrawable(
  start: Int = Color.rgb(0, 143, 209),
  center: Int = Color.rgb(1, 106, 154),
  end: Int = Color.rgb(28, 179, 249),
  frameDuration: Int = 3000,
  enterFadeDuration: Int = 0,
  exitFadeDuration: Int = 3000
) : AnimationDrawable() {

  private val gradientStart = GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, intArrayOf(start, center, end))
    .apply {
      shape = GradientDrawable.RECTANGLE
      gradientType = GradientDrawable.LINEAR_GRADIENT
    }

  private val gradientCenter = GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, intArrayOf(center, end, start))
    .apply {
      shape = GradientDrawable.RECTANGLE
      gradientType = GradientDrawable.LINEAR_GRADIENT
    }

  private val gradientEnd = GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, intArrayOf(end, start, center))
    .apply {
      shape = GradientDrawable.RECTANGLE
      gradientType = GradientDrawable.LINEAR_GRADIENT
    }

  init {
    addFrame(gradientStart, frameDuration)
    addFrame(gradientCenter, frameDuration)
    addFrame(gradientEnd, frameDuration)
    setEnterFadeDuration(enterFadeDuration)
    setExitFadeDuration(exitFadeDuration)
    isOneShot = false
  }

}