# Android实现流光和光影移动效果代码

## 实现思路：

1.首先我们先了解一下光影怎么绘制

``` /**
* Create a shader that draws a linear gradient along a line.
*
* @param x0           The x-coordinate for the start of the gradient line
* @param y0           The y-coordinate for the start of the gradient line
* @param x1           The x-coordinate for the end of the gradient line
* @param y1           The y-coordinate for the end of the gradient line
* @param colors       The sRGB colors to be distributed along the gradient line
* @param positions    May be null. The relative positions [0..1] of
*                     each corresponding color in the colors array. If this is null,
*                     the the colors are distributed evenly along the gradient line.
* @param tile         The Shader tiling mode
*
*
* 翻译过来：
* x0，y0为渐变起点，x1，y1为渐变的终点
*
* colors数组为两点间的渐变颜色值，positions数组取值范围是0~1
* 传入的colors[]长度和positions[]长度必须相等，一一对应关系，否则报错
* position传入null则代表colors均衡分布
*
* tile有三种模式
*/
LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int[] colors,
@Nullable float[] positions, @NonNull TileMode tile)
```

colors[]和positions[]的说明结合下图，这样理解起来应该就比较明朗了

```LinearGradient(a的x坐标, a的y坐标, c的x坐标, c的y坐标, new int[]{Color.parseColor("#00FFFFFF"), Color.parseColor("#FFFFFFFF"), Color.parseColor("#00FFFFFF")}, new float[]{0f, 0.5f, 1f}, Shader.TileMode.CLAMP)
```

3.给定一个数值范围利用数值生成器ValueAnimator产生数值，监听数值变化。每次回调都将该数值传入光影的起点和终点并进行绘制

## 代码如下：

```/**
* author: caoyb
* created on: 2021/12/20 15:13
* description:
*/

private Paint mPaint;
private Path mPath;
private ValueAnimator mValueAnimator;

this(context, null);
}

this(context, attrs, 0);
}

super(context, attrs, defStyleAttr);
init();
}

private void init() {
mPaint = new Paint();
mPath = new Path();
}

private void initPointAndAnimator(int w, int h) {
Point point1 = new Point(0, 0);
Point point2 = new Point(w, 0);
Point point3 = new Point(w, h);
Point point4 = new Point(0, h);

mPath.moveTo(point1.x, point1.y);
mPath.lineTo(point2.x, point2.y);
mPath.lineTo(point3.x, point3.y);
mPath.lineTo(point4.x, point4.y);
mPath.close();

// 斜率k
float k = 1f * h / w;
// 偏移
float offset = 1f * w / 2;
// 0f - offset * 2 为数值左边界（屏幕外左侧）， w + offset * 2为数值右边界（屏幕外右侧）
// 目的是使光影走完一遍，加一些时间缓冲，不至于每次光影移动的间隔都那么急促
mValueAnimator = ValueAnimator.ofFloat(0f - offset * 2, w + offset * 2);
mValueAnimator.setRepeatCount(-1);
mValueAnimator.setInterpolator(new LinearInterpolator());
mValueAnimator.setDuration(1500);
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
mLinearGradient = new LinearGradient(value, k * value, value + offset, k * (value + offset),
new int[]{Color.parseColor("#00FFFFFF"), Color.parseColor("#1AFFFFFF"), Color.parseColor("#00FFFFFF")}, null, Shader.TileMode.CLAMP);
invalidate();
}
});
mValueAnimator.start();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
initPointAndAnimator(widthSize, heightSize);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(mPath, mPaint);
}

@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mValueAnimator.cancel();
}
}
```