Android自定义view绘制颜色的时候,可以通过setShader可以让view绘制多彩渐变的效果。Android sdk中提供了五个Shader子类供开发者使用,分别是:LinearGradient线性渐变 SweetGradient角度渐变 RadialGradient辐射渐变 BitmapShader图片shader和ComposeShader组合着色器。本文将结合例子对线性渐变做一个介绍。
public LinearGradient(float x0, float y0, float x1, float y1,
@ColorInt int color0, @ColorInt int color1,
@NonNull TileMode tile)
该构造函数前四个参数代码颜色渐变的起点(x0,y0)和结束点(x1,y1)参数color0与color1代表startColor和endColor。TitleModel 有三个值(CLAMP、MIRROR、REPEAT)代表渐变模式。
列子代码:
public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[],
@Nullable float positions[], @NonNull TileMode tile)
该构造函数前四个参数代码颜色渐变的起点(x0,y0)和结束点(x1,y1)参数colors数组代表渐变过度颜色,positions数组代表各过度色的起点位置(浮点类型)。TitleModel 有三个值(CLAMP、MIRROR、REPEAT)代表渐变模式。
package com.xol.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.xol.util.CommonUtil;
/**
* Created by wwzhang on 2019/3/14
*/
public class LinearGradientView extends View {
private Paint mPaint;
private LinearGradient mLinearGradient;
private int mWidthNum = 3;
private int mHeightNum = 3;
private int[] colorThree;
private int[] colorTwo;
private int mSpace;
private float mWidth = 0;
private float mRectRadius = 5;
private String mContentText = "非淡泊无以明智,非宁静无以致远";
public LinearGradientView(Context context) {
super(context);
}
public LinearGradientView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public LinearGradientView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
{
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setTextSize(CommonUtil.sp2px(16, getContext()));
mRectRadius = CommonUtil.dp2px(mRectRadius, getContext());
colorThree = new int[]{
Color.parseColor("#ff0000"),
Color.parseColor("#00ff00"),
Color.parseColor("#0000ff")};
colorTwo = new int[]{Color.parseColor("#ff0000"),
Color.parseColor("#0000ff")};
mSpace = (int) CommonUtil.dp2px(2, getContext());
mPaint.setColor(Color.parseColor("#AAAAAA"));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawLinearRound(canvas);
}
public void drawLinearRound(Canvas canvas) {
//绘制两色渐变
int rectHeight = (int) CommonUtil.dp2px(20, getContext());
int space = 10;
//水平clamp
mLinearGradient = new LinearGradient(0, 0, getMeasuredWidth() / 2,
0, colorTwo[0], colorTwo[1], Shader.TileMode.CLAMP);
mPaint.setShader(mLinearGradient);
canvas.drawRect(0, 0 + space, getMeasuredWidth(), rectHeight + space, mPaint);
// 水平mirror
mLinearGradient = new LinearGradient(0, 0, getMeasuredWidth() / 2,
0, colorTwo[0], colorTwo[1], Shader.TileMode.MIRROR);
mPaint.setShader(mLinearGradient);
canvas.drawRect(0, rectHeight + space * 2, getMeasuredWidth(),
(rectHeight << 1) + space * 2, mPaint);
//水平repeat
mLinearGradient = new LinearGradient(0, 0, getMeasuredWidth() / 2,
0, colorTwo[0], colorTwo[1], Shader.TileMode.REPEAT);
mPaint.setShader(mLinearGradient);
canvas.drawRect(0, (rectHeight << 1) + space * 3, getMeasuredWidth(),
(rectHeight << 1) + rectHeight + space * 3, mPaint);
//对角线mirror渐变
mLinearGradient = new LinearGradient(0, 0, 20, 20,
colorTwo[0], colorTwo[1], Shader.TileMode.MIRROR);
mPaint.setShader(mLinearGradient);
canvas.drawRect(0, (rectHeight << 1) + rectHeight + space * 4, getMeasuredWidth(),
(rectHeight << 2) + space * 4, mPaint);
//计算
if (mWidth < 5) {
mWidth = (getMeasuredWidth() - (mWidthNum + 1) * mSpace) / mWidthNum;
mHeightNum = (int) (getMeasuredHeight() - CommonUtil.dp2px(120, getContext()) / mWidth);
}
//绘制三色渐变
int count = 0;
RectF rectF = new RectF();
for (int i = 0; i < mHeightNum; i++) {
rectF.top = i * mWidth + (i + 1) * mSpace + (int) CommonUtil.dp2px(120, getContext());
rectF.bottom = rectF.top + mWidth;
for (int j = 0; j < mWidthNum; j++) {
rectF.left = j * mWidth + (j + 1) * mSpace;
rectF.right = rectF.left + mWidth;
count++;
if (count > 9) {
break;
}
switch (count) {
case 1:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.left + (rectF.right - rectF.left) / 2, rectF.top + (rectF.bottom - rectF.top) / 2, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.REPEAT);
mPaint.setShader(mLinearGradient);
break;
case 2:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.left + (rectF.right - rectF.left) / 2, rectF.top + (rectF.bottom - rectF.top) / 2, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.MIRROR);
mPaint.setShader(mLinearGradient);
break;
case 3:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.left + (rectF.right - rectF.left) / 2, rectF.top + (rectF.bottom - rectF.top) / 2, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.CLAMP);
mPaint.setShader(mLinearGradient);
break;
case 4:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.left + (rectF.right - rectF.left) / 2, rectF.top, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.REPEAT);
mPaint.setShader(mLinearGradient);
break;
case 5:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.left + (rectF.right - rectF.left) / 2, rectF.top, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.MIRROR);
mPaint.setShader(mLinearGradient);
break;
case 6:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.left + (rectF.right - rectF.left) / 2, rectF.top, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.CLAMP);
mPaint.setShader(mLinearGradient);
break;
case 7:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.right, rectF.bottom, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.REPEAT);
mPaint.setShader(mLinearGradient);
break;
case 8:
mLinearGradient = new LinearGradient(rectF.left, rectF.bottom,
rectF.right, rectF.bottom, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.REPEAT);
mPaint.setShader(mLinearGradient);
break;
case 9:
mLinearGradient = new LinearGradient(rectF.left, rectF.bottom,
rectF.right, rectF.bottom, colorThree,
new float[]{0.5f, 0.75f, 1.0f}, Shader.TileMode.REPEAT);
mPaint.setShader(mLinearGradient);
break;
default:
break;
}
canvas.drawRoundRect(rectF, mRectRadius, mRectRadius, mPaint);
}
}
}
}
布局文件引入
运行结果:
实现原理,通过matrix水平移动线性shader开始的位置,达到文字闪动的效果
实现原理,通过设置线性shader的变色位置,实现文字的逐渐变色。
示例代码:
package com.xol.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Shader;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.xol.util.CommonUtil;
/**
* Created by wwzhang on 2019/3/18
*/
public class LinearGradientTextView extends View implements Runnable {
private Paint mPaint;
private Matrix mMatrix;
private String mText;
private LinearGradient mLinearGradient;
private long mDuration = 50;
private int mTransX = 0;
private Rect rect = new Rect();
private LinearGradient mKrcLinearGradient;
private float[] mfKrc = new float[2];
private String mSingText;
private Paint mSingPaint;
public LinearGradientTextView(Context context) {
super(context);
}
public LinearGradientTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public LinearGradientTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
{
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mSingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mMatrix = new Matrix();
mText = "疏疏晴雨弄斜阳,凭栏久,墙外杏花香";
mSingText = "很爱很爱你所以愿意,不牵绊你";
mPaint.setTextSize(CommonUtil.dp2px(16, getContext()));
mSingPaint.setTextSize(CommonUtil.dp2px(16, getContext()));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (null == mLinearGradient) {
mLinearGradient = new LinearGradient(0, 0, 200, 0,
new int[]{Color.parseColor("#440000"),
Color.parseColor("#ffffff"),
Color.parseColor("#440000")},
new float[]{0.0f, 0.5f, 1.0f}, Shader.TileMode.CLAMP);
mLinearGradient.setLocalMatrix(mMatrix);
mPaint.setShader(mLinearGradient);
mfKrc[0] = 0.0f;
mfKrc[1] = 0.0f;
mKrcLinearGradient = new LinearGradient(0, 0, getMeasuredWidth(), 0, new int[]{
Color.parseColor("#ff0000"),
Color.parseColor("#ffffff")},
mfKrc,
Shader.TileMode.CLAMP);
mSingPaint.setShader(mKrcLinearGradient);
postDelayed(this, mDuration);
}
mPaint.getTextBounds(mText, 0, mText.length(), rect);
canvas.drawText(mText, 0, rect.bottom - rect.top, mPaint);
canvas.drawText(mSingText, 0, getMeasuredHeight() / 2, mSingPaint);
}
@Override
public void run() {
mTransX += 10;
if (mTransX > rect.right - rect.left) {
mTransX = -10;
}
mfKrc[0] += 0.01f;
mfKrc[1] = mfKrc[0];
if (mfKrc[0] > 1.0f) {
mfKrc[0] = 0.0f;
mfKrc[1] = 0.0f;
}
mKrcLinearGradient = new LinearGradient(0, 0, getMeasuredWidth(), 0, new int[]{
Color.parseColor("#ff0000"),
Color.parseColor("#ffffff")},
mfKrc,
Shader.TileMode.CLAMP);
mSingPaint.setShader(mKrcLinearGradient);
mMatrix.setTranslate(mTransX, 0);
mLinearGradient.setLocalMatrix(mMatrix);
invalidate();
postDelayed(this, mDuration);
}
}
布局文件