Android Shader渲染以及实现水波纹霓虹文字雷达等效果

少年乘勇气,百战过乌孙。这篇文章主要讲述Android Shader渲染以及实现水波纹霓虹文字雷达等效果相关的知识,希望能为你提供帮助。
Shader概述 Shader是绘图过程中的着色器, 实现绘制各种不同的效果, 比如镜像, 水波纹, 雷达等等, Shader有以下五个子类:
- BitmapShader用于Bitmap图片的渲染
- ComposeShader用于混合渲染
- LinearGradient用于线性渲染
- RadialGradient用于环形渲染
- SweepGradient用于梯度渲染
Shader的三种模式TileMode

  • CLAMP 当绘制的区域超过了原始的大小, 超出的区域就会用边缘的颜色进行拉伸
  • REPEAT 重复水平或者竖直方向的图片
  • MIRROR 用图片的镜像填充
BitmapShader 构造方法 BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY)
- bitmap: 需要着色的位图
- tileX: X方向的填充模式
- tileY: Y方向的填充模式
实例
Android Shader渲染以及实现水波纹霓虹文字雷达等效果

文章图片

这是一个充值后的影魔, 直接看看代码的实现:
public class ShaderView extends View { Bitmap mBitmap; BitmapShader mBitmapShader; Paint mPaint; int mWidth; int mHeight; public ShaderView(Context context) { super(context); init(); }private void init() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test); mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.MIRROR); }public ShaderView(Context context, AttributeSet attrs) { super(context, attrs); init(); }@ Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); }@ Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setShader(mBitmapShader); canvas.drawRect(0, 0, mWidth, mHeight, mPaint); } }

这里的X轴采用的是CLAMP, 所以右边是拉伸边缘的像素点, Y轴采用的是MIRROR, 上下都是镜像的。
现在我们把drawRect注释点, 来绘制一个圆
//canvas.drawRect(0, 0, mWidth, mHeight, mPaint); canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, mPaint);

Android Shader渲染以及实现水波纹霓虹文字雷达等效果

文章图片

可以看到以上的效果, 所以可不可以这样理解呢, 这里的BitmapShader就是给绘制的内容加上我们所设置的Bitmap作为背景。
RadialGradient 主要用于在某一区域内实现环形的渐变效果, RadialGradient的意思是放射渐变, 即它会向一个放射源一样, 从一个点开始向外从一个颜色渐变成另一种颜色。
构造方法
  1. RadialGradient(float centerX, float centerY, float radius,int centerColor, int edgeColor, TileMode tileMode)
    - centerX: 渐变中心点X坐标
    - centerY: 渐变中心点Y坐标
    - radius: 渐变半径
    - centerColor: 渐变中心的颜色, 取值类型必须是八位的0xAARRGGBB色值
    - edgeColor: 渐变结束的颜色
    - tileMode: 填充的模式
  2. RadialGradient(float centerX, float centerY, float radius,int colors[], float stops[], @ NonNull TileMode tileMode)
    • int[] colors: 表示所需要的渐变颜色数组
    • float[] stops: 表示每个渐变颜色所在的位置百分点, 取值0-1
示例 下面是两种构造函数实现的
Android Shader渲染以及实现水波纹霓虹文字雷达等效果

文章图片
Android Shader渲染以及实现水波纹霓虹文字雷达等效果

文章图片

代码
public class RadialGradientView extends View { private RadialGradient mRadialGradient; private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); int mWidth; int mHeight; public RadialGradientView(Context context) { super(context); }public RadialGradientView(Context context, AttributeSet attrs) { super(context, attrs); }@ Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); //mRadialGradient = new RadialGradient(mWidth / 2, mHeight / 2, mWidth / 2, 0xffff0000, 0xff00ff00, Shader.TileMode.CLAMP); int[] colors = new int[]{0xffff0000, 0xff00ff00, 0xff0000ff, 0xffffff00}; float[] stops = new float[]{0f, 0.3f, 0.7f, 1f}; mRadialGradient = new RadialGradient(mWidth / 2, mHeight / 2, mWidth / 2, colors, stops, Shader.TileMode.REPEAT); mPaint.setShader(mRadialGradient); }@ Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, mPaint); } }

再次修改一下
@ Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); int[] colors = new int[]{0xffff0000, 0xff00ff00, 0xff0000ff, 0xffffff00}; float[] stops = new float[]{0f, 0.3f, 0.7f, 1f}; mRadialGradient = new RadialGradient(mWidth / 2, mHeight / 2, 200, colors, stops, Shader.TileMode.REPEAT); mPaint.setShader(mRadialGradient); }@ Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawRect(new Rect(0,0,mWidth,mHeight),mPaint); }

效果如下
Android Shader渲染以及实现水波纹霓虹文字雷达等效果

文章图片

水波纹效果实现
Android Shader渲染以及实现水波纹霓虹文字雷达等效果

文章图片

代码如下, 就不多说了
public class RippleView extends TextView { private int mX, mY; private ObjectAnimator mAnimator; private int DEFAULT_RADIUS = 50; private int mCurRadius = 0; private RadialGradient mRadialGradient; private Paint mPaint = new Paint(); public RippleView(Context context) { super(context); }public RippleView(Context context, AttributeSet attrs) { super(context, attrs); }@ Override public boolean onTouchEvent(MotionEvent event) { if (mX != event.getX() || mY != event.getY()) { mX = (int) event.getX(); mY = (int) event.getY(); setRadius(DEFAULT_RADIUS); }if (event.getAction() = = MotionEvent.ACTION_DOWN) { //如果不返回true, 后续的事件收不到 return true; } else if (event.getAction() = = MotionEvent.ACTION_UP) { if (mAnimator != null & & mAnimator.isRunning()) { mAnimator.cancel(); } if (mAnimator = = null) { //这里第一个对象传递当前对象, 在当前对象中设置了setRadius方法, 所以这里传递radius //每当值变化时就会调用这个setRadius方法 mAnimator = ObjectAnimator.ofInt(this, " radius" , DEFAULT_RADIUS, getWidth()); } mAnimator.setInterpolator(new AccelerateInterpolator()); mAnimator.addListener(new Animator.AnimatorListener() { @ Override public void onAnimationStart(Animator animation) { }@ Override public void onAnimationEnd(Animator animation) { setRadius(0); }@ Override public void onAnimationCancel(Animator animation) { }@ Override public void onAnimationRepeat(Animator animation) { } }); mAnimator.start(); }return super.onTouchEvent(event); }//注意这里的方法名必须是setRadius public void setRadius(final int radius) { mCurRadius = radius; if (mCurRadius > 0) { mRadialGradient = new RadialGradient(mX, mY, mCurRadius, 0x00FFFFFF, 0xFF58FAAC, Shader.TileMode.CLAMP); mPaint.setShader(mRadialGradient); } invalidate(); }@ Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(mX, mY, mCurRadius, mPaint); } }

LinearGradient 线性渲染, 对某一区域实现线性渐变效果。
构造函数
  1. LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,TileMode tile)
    • x0,y0是渐变的起点坐标
    • x1,y1是渐变的终点坐标
    • color0是开始颜色
    • color1是结束颜色
  2. LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],TileMode tile)
    • colors和positions意义和之前的RadialGradient一样。
示例
Android Shader渲染以及实现水波纹霓虹文字雷达等效果

文章图片

public class LinearGradientView extends View { Paint mPaint = new Paint(); LinearGradient mLinearGradient; int[] colors = new int[]{ 0xFFFF0000, 0xffFF7F00, 0xffFFFF00, 0xff00FF00, 0xff00FFFF, 0xff0000FF, 0xff8B00FF}; public LinearGradientView(Context context) { super(context); }public LinearGradientView(Context context, AttributeSet attrs) { super(context, attrs); }@ Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mLinearGradient = = null) { mLinearGradient = new LinearGradient(0, 0, 0, 400, colors, null, Shader.TileMode.CLAMP); mPaint.setShader(mLinearGradient); } canvas.drawRect(new Rect(0,0,getWidth(),getHeight()),mPaint); } }

霓虹文字效果
Android Shader渲染以及实现水波纹霓虹文字雷达等效果

文章图片

这里实现主要是继承TextView, 获得它绘制文字的Paint, 给这个Paint设置LinearGradient的Shader, 把这个Shader从左边开始向右移动, 实现霓虹效果。
public class LinearGradientText extends TextView { Paint mPaint; LinearGradient mLinearGradient; private Matrix mMatrix; private int mX; public LinearGradientText(Context context) { super(context); init(); }public LinearGradientText(Context context, AttributeSet attrs) { super(context, attrs); init(); }private void init() { //注意这里必须是TextView的Paint, 因为绘制文字就是用这个Paint mPaint = getPaint(); mMatrix = new Matrix(); }private void initAnimtor(int width) { ValueAnimator animator = ValueAnimator.ofInt(0, width * 2); //我们设置value的值为0-getMeasureWidth的3 倍 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @ Override public void onAnimationUpdate(ValueAnimator animation) { mX = (Integer) animation.getAnimatedValue(); postInvalidate(); } }); animator.setRepeatMode(ValueAnimator.RESTART); //重新播放 animator.setRepeatCount(ValueAnimator.INFINITE); //无限循环 animator.setDuration(2000); animator.start(); }@ Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //设置LinearGradient,绘制的范围这里设置的是-w到w, 相当于两个宽度, 然后把Shader向右移动实现了效果 mLinearGradient = new LinearGradient(-w, 0, w, 0, new int[]{getCurrentTextColor(), Color.RED, Color.YELLOW, Color.BLUE, getCurrentTextColor(),} , null, Shader.TileMode.CLAMP); mPaint.setShader(mLinearGradient); initAnimtor(w); }@ Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mMatrix.reset(); mMatrix.preTranslate(mX, 0); mLinearGradient.setLocalMatrix(mMatrix); } }

SweepGradient 梯度渲染, 是指在某一中心以x轴正方向逆时针旋转一周而形成的扫描效果的渲染形式
构造函数
  1. SweepGradient(float cx, float cy, int colors[], float positions[])
    • cx,cy: 中心坐标点
    • colors、positions同样和之前一样
  2. SweepGradient(float cx, float cy, int color0, int color1)
    • cx, cy中心坐标点
    • color0、color1开始和结束的颜色
简单示例
Android Shader渲染以及实现水波纹霓虹文字雷达等效果

文章图片

@ Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); width = w; height = h; mSweepGradient = new SweepGradient(w / 2, h / 2, colors, null); mPaint.setShader(mSweepGradient); }@ Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawRect(new Rect(0, 0, width, height), mPaint); }

雷达扫描实现
Android Shader渲染以及实现水波纹霓虹文字雷达等效果

文章图片

/** * Created by lzy on 2017/4/13. */ public class RadarView extends View {private static final int MSG_WHAT = 10086; private static final int DELAY_TIME = 20; //设置默认宽高, 雷达一般都是圆形, 所以我们下面取宽高会去Math.min(宽,高) private final int DEFAULT_WIDTH = 200; private final int DEFAULT_HEIGHT = 200; private int mRadarRadius; //雷达的半径private Paint mRadarPaint; //雷达画笔private Paint mRadarBg; //雷达底色画笔private int radarCircleCount = 4; //雷达圆圈的个数, 默认4个private int mRadarLineColor = Color.WHITE; //雷达线条的颜色, 默认为白色private int mRadarBgColor = Color.BLACK; //雷达圆圈背景色 private Shader radarShader; //paintShader//雷达扫描时候的起始和终止颜色 private int startColor = 0x0000ff00; private int endColor = 0xaa00ff00; public RadarView(Context context) { this(context, null); }public RadarView(Context context, AttributeSet attrs) { this(context, attrs, 0); }public RadarView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); mRadarPaint = new Paint(Paint.ANTI_ALIAS_FLAG); //设置抗锯齿 mRadarPaint.setColor(mRadarLineColor); //画笔颜色 mRadarPaint.setStyle(Paint.Style.STROKE); //设置空心的画笔, 只画圆边 mRadarPaint.setStrokeWidth(2); //画笔宽度mRadarBg = new Paint(Paint.ANTI_ALIAS_FLAG); //设置抗锯齿 mRadarBg.setColor(mRadarBgColor); //画笔颜色 mRadarBg.setStyle(Paint.Style.FILL); //设置空心的画笔, 只画圆边radarShader = new SweepGradient(0, 0, startColor, endColor); matrix = new Matrix(); }//初始化, 拓展可设置参数供布局使用 private void init(Context context, AttributeSet attrs) { if (attrs != null) { TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RadarView); startColor = ta.getColor(R.styleable.RadarView_startColor, startColor); endColor = ta.getColor(R.styleable.RadarView_endColor, endColor); mRadarBgColor = ta.getColor(R.styleable.RadarView_bgColor, mRadarBgColor); mRadarLineColor = ta.getColor(R.styleable.RadarView_lineColor, mRadarLineColor); radarCircleCount = ta.getInteger(R.styleable.RadarView_circleCount, radarCircleCount); ta.recycle(); } }@ Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = measureSize(1, DEFAULT_WIDTH, widthMeasureSpec); int height = measureSize(0, DEFAULT_HEIGHT, heightMeasureSpec); int measureSize = Math.max(width, height); //取最大的 宽|高 setMeasuredDimension(measureSize, measureSize); }/** * 测绘measure * * @ param specType1为宽, 其他为高 * @ param contentSize 默认值 */ private int measureSize(int specType, int contentSize, int measureSpec) { int result; //获取测量的模式和Size int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode = = MeasureSpec.EXACTLY) { result = Math.max(contentSize, specSize); } else { result = contentSize; if (specType = = 1) { // 根据传人方式计算宽 result + = (getPaddingLeft() + getPaddingRight()); } else { // 根据传人方式计算高 result + = (getPaddingTop() + getPaddingBottom()); } }return result; }@ Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mRadarRadius = Math.min(w / 2, h / 2); }//旋转的角度 private int rotateAngel = 0; @ Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.translate(mRadarRadius, mRadarRadius); //将画板移动到屏幕的中心点mRadarBg.setShader(null); canvas.drawCircle(0, 0, mRadarRadius, mRadarBg); //绘制底色(默认为黑色), 可以使雷达的线看起来更清晰for (int i = 1; i < = radarCircleCount; i+ + ) {//根据用户设定的圆个数进行绘制 canvas.drawCircle(0, 0, (float) (i * 1.0 / radarCircleCount * mRadarRadius), mRadarPaint); //画圆圈 }canvas.drawLine(-mRadarRadius, 0, mRadarRadius, 0, mRadarPaint); //绘制雷达基线 x轴 canvas.drawLine(0, mRadarRadius, 0, -mRadarRadius, mRadarPaint); //绘制雷达基线 y轴//canvas.rotate(rotateAngel,0,0); //设置颜色渐变从透明到不透明 mRadarBg.setShader(radarShader); canvas.concat(matrix); canvas.drawCircle(0, 0, mRadarRadius, mRadarBg); }private Matrix matrix; private Handler mHandler = new Handler() { @ Override public void handleMessage(Message msg) { super.handleMessage(msg); rotateAngel + = 3; postInvalidate(); matrix.reset(); matrix.preRotate(rotateAngel, 0, 0); mHandler.sendEmptyMessageDelayed(MSG_WHAT, DELAY_TIME); } }; public void startScan() { mHandler.removeMessages(MSG_WHAT); mHandler.sendEmptyMessage(MSG_WHAT); }public void stopScan() { mHandler.removeMessages(MSG_WHAT); } }

ComposeShader 组合渲染
构造函数
  1. ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode)
    • shaderA : 渲染器A
    • shaderB : 渲染器B
    • Xfermode : 两种渲染器组合的模式,Xfermode对象
  2. ComposeShader(Shader shaderA, Shader shaderB, Mode mode)
    • Mode : 两种渲染器组合的模式,ProterDuff.Mode对象
    简单实例
    Android Shader渲染以及实现水波纹霓虹文字雷达等效果

    文章图片

    这里是结合了BitmapShader和LinearGradient实现的效果
    public class ComposeShaderView extends View { Bitmap mBitmap; BitmapShader mBitmapShader; Paint mPaint; LinearGradient mLinearGradient; ComposeShader mComposeShader; int mWidth; int mHeight; public ComposeShaderView(Context context) { super(context); init(); }public ComposeShaderView(Context context, AttributeSet attrs) { super(context, attrs); init(); }private void init() { mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test_3); mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); }@ Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = w; mHeight = h; mLinearGradient = new LinearGradient(0, 0, w, h, new int[] { Color.WHITE, Color.LTGRAY, Color.TRANSPARENT, Color.GREEN }, null, Shader.TileMode.CLAMP); mComposeShader = new ComposeShader(mBitmapShader, mLinearGradient, PorterDuff.Mode.MULTIPLY); mPaint.setShader(mComposeShader); }@ Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawOval(0, 0, mWidth, mHeight, mPaint); } }

    【Android Shader渲染以及实现水波纹霓虹文字雷达等效果】关于Mode可以看看这里
    Demo下载链接

    推荐阅读