不知曾几何时,渐变色变得流行起来了,各大手机厂商都发布了各自的渐变色手机,同时越来越多的 App ,也开始应用了渐变色的设计。为了满足工作需要,我们也要学习下 Android 中的渐变着色器 Shader。
效果图
Shader 介绍
Shader 单词为 着色器,在 Android 中的文档解释为:
Shader is the based class for objects that return horizontal spans of colors during drawing. A subclass of Shader is installed in a Paint calling paint.setShader(shader). After that any object (other than a bitmap) that is drawn with that paint will get its color(s) from the shader
着色器是在绘制过程中返回水平颜色范围的对象的基类。 Shader的子类安装在Paint中,调用paint.setShader(着色器)之后,使用该绘制绘制的任何对象(位图除外)都将从着色器中获取其颜色
Shader 相关类:
可以看出: Shader 有五个子类
- BitmapShader 位图渲染
- ComposeShader 组合渲染
- LinearGradient 线性渲染
- SweepGradient 梯度渲染
- RadialGradient 光束渲染
Shader 用法
(1)调用 Shader 子类对象的构造方法创建着色器,设定 渲染模式。
// 创建线性着色器
linearGradient = new LinearGradient(0, 0, mViewWidth, 0,
new int[]{
Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW},
new float[]{
0.2f, 0.5f, 0.8f, 0.9f},
Shader.TileMode.REPEAT);
其中渲染模式 TileMode 有:
- CLAMP 边缘拉伸模式,他会拉伸边缘的一个像素来填充其他区域。
- REPEAT 重复模式,水平和垂直重复着色器的图像
- MIRROR 镜像模式,水平和垂直重复着色器的图像,交替镜像,使相邻的图像始终接缝
(2)给画笔设置 Shader 着色器
// 为画笔设置渐变渲染器
paint.setShader(linearGradient);
(3)在 onDraw() 方法中使用 paint 进行绘制。
canvas.drawRect(rectF, paint);
LinearGradient
LinearGradient 构造方法:
public LinearGradient(float x0, float y0, float x1, float y1,@ColorInt int color0, @ColorInt int color1, @NonNull TileMode tile)
public LinearGradient(float x0, float y0, float x1, float y1,
@NonNull @ColorInt int colors[],@Nullable float positions[], @NonNull TileMode tile)
上面一个构造函数很好理解,(x0,y0),(x1,y1) 分别表示起点和终点的坐标,颜色从 color0 到 color1 线性变化;
下面一个构造函数参数有点不好理解了。我们先看下使用这个构造函数后的效果:
/**
* 线性渐变
*/
public class LinearGradientView extends View {
private Paint paint;
private Paint linePaint;
private LinearGradient linearGradient;
private int mViewWidth;
private int mViewHeight;
private RectF rectF;
public LinearGradientView(Context context) {
super(context);
init();
}
public LinearGradientView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
linePaint.setStrokeWidth(DensityUtil.dp2Px(getContext(), 2));
linePaint.setStyle(Paint.Style.FILL);
linePaint.setColor(Color.BLACK);
linePaint.setTextSize(DensityUtil.dp2Px(getContext(), 14));
linePaint.setTextAlign(Paint.Align.CENTER);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mViewWidth = w;
mViewHeight = h;
rectF = new RectF(0, 0, mViewWidth, mViewHeight);
/**
* 渐变范围为 左上角顶点 (0,0) -> 右上角顶点 (mViewWidth,0) ,
* 超出这个范围以 Shader.TileMode.REPEAT 重复的形式填充, 颜色渐变的方向为 水平方向,
*
*
* 如果渐变范围: (0,0) -> (mViewWidth,mViewHeight), 则 渐变方向为 对角线方向
*/
linearGradient = new LinearGradient(0, 0, mViewWidth, 0,
new int[]{
Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW},
new float[]{
0.2f, 0.5f, 0.8f, 0.9f},
Shader.TileMode.REPEAT);
paint.setShader(linearGradient);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(rectF, paint);
for (int i = 0; i <= 10; i++) {
canvas.drawLine(rectF.width() * i * 0.1f, rectF.bottom, rectF.width() * i * 0.1f, rectF.bottom - 20, linePaint);
canvas.drawText(String.valueOf(i / 10f), rectF.width() *