Nex*_*xen 28
谷歌搜索时,我找到了两种方法来为Android做:使用ShaderFactory或扩展View,使用new Shader(new LinearGradient()).两个答案都是一样的 - 调用new Shader()每个View.onDraw(Canvas canvas)方法的调用.如果这样的动画渐变数超过~3,它真的很贵.
所以我采取了另一种方式.我避免调用new每一个onDraw(),使用一个预先计算LinearGradient.这就是它的样子(gif,所以动画腐烂):
关键是要建立LinearGradient是colorsCount大于倍View.getWidth().之后,您可以canvas.translate()在绘制渐变时使用,以更改其颜色,因此根本不会new调用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, height / 2,
colors, null, Shader.TileMode.REPEAT);
fillPaint.setShader(gradient);
shapePath = getParallelogrammPath(width, height, sidesGap);
shapeBorderPath = getParallelogrammPath(width, height, sidesGap);
}
Run Code Online (Sandbox Code Playgroud)
我使用路径因为平行四边形视图,你可以使用你想要的任何东西.在实现绘图时,您应该注意两件事:您需要对当前偏移量和填充形状进行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
}
Run Code Online (Sandbox Code Playgroud)
你也应该使用canvas.save()&canvas.restore().它将保存画布的内部矩阵进行堆叠并相应地恢复.
所以最后你需要做的是动画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();
}
Run Code Online (Sandbox Code Playgroud)
View您可以在此处找到完整的代码
Krz*_*tal 10
我已经找到了不同的,更短的方法.随着时间的推移,只需使用它的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()
Run Code Online (Sandbox Code Playgroud)
结果如下:
刚刚将@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();
}
Run Code Online (Sandbox Code Playgroud)
其中view是一个简单View的渐变背景:
//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>
Run Code Online (Sandbox Code Playgroud)
风景 :
<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" />
Run Code Online (Sandbox Code Playgroud)
希望我的回答会有所帮助
| 归档时间: |
|
| 查看次数: |
9547 次 |
| 最近记录: |