Canvas的drawXXXX这个方法是画具体的形状,画笔的shader定义的就是图形的着色和外观
(一)BitmapShader 位图图像渲染,用BitMap对绘制的图形进行渲染着色,简单来说是用图片对图形进行贴图 例如:圆形头像,放大镜效果
TileMode 拉伸形式
CLAMP --是拉伸最后一个像素铺满
MIRROR —是横向纵向不足处不断翻转镜像平铺
REPEAT —类似电脑壁纸,横向纵向不足的重复放置
(二)LinearGradient 线性渲染 例如:霓虹灯文字,倒影图片
LinearGradient( x0, y0,x1, y1, mColors, positions, Shader.TileMode.CLAMP);
x0, y0, 起始点
x1, y1, 结束点
int[] mColors, 中间依次要出现的几个颜色
float[] positions,数组大小跟colors数组一样大,中间依次摆放的几个颜色分别放置在那个位置上(参考比例从左往右)
(三)SweepGradient 渐变渲染/梯度渲染 例如:雷达扫描效果
SweepGradient(float cx, float cy,int colors[], float positions[]);
cx,cy:表示渐变的起点坐标(中心点)
colors:传入多个颜色,产生更加丰富的渐变效果。
positions:与LinearGradient的positions[]效果一致 可以为null
(四)RadialGradient 环形渲染 例如:水波纹效果
RadialGradient(float centerX, float centerY, float radius, @NonNull int colors[], @Nullable float stops[], @NonNull TileMode tileMode)
centerX,centerY:表示渐变的起点坐标(中心点)
radius:表示渐变半径长度
colors[]:传入多个颜色,产生更加丰富的渐变效果。
float[]:可以设置在不同的渲染阶段渲染不同的颜色
TileMode:和上面讲的完全一致
(五)ComposeShader 组合渲染
ComposeShader (Shader shaderA, Shader shaderB, Xfermode mode)
例子一:圆形头像与圆角头像的实现
public class CircleImageView extends View {
private Paint paint;
private Bitmap bitmap;
private boolean isCircle;//是不是圆形
private float round;//圆角半径
public CircleImageView(Context context) {
super(context);
init();
}
public CircleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
isCircle=typedArray.getBoolean(R.styleable.CircleImageView_isCircle,true);
round=typedArray.getDimension(R.styleable.CircleImageView_round,10);
typedArray.recycle();
init();
}
private void init(){
paint=new Paint();
paint.setAntiAlias(true);//抗锯齿,图片更平滑
bitmap=((BitmapDrawable)getResources().getDrawable(R.mipmap.one)).getBitmap();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//缩放到控件大小
bitmap=Bitmap.createScaledBitmap(bitmap,getMeasuredWidth(),getMeasuredHeight(),false);
//创建渲染
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(bitmapShader);
if(isCircle){
//绘制圆形
canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2,paint);
}else{
RectF rectF=new RectF(0,0,getWidth(),getHeight());
canvas.drawRoundRect(rectF,round,round,paint);
}
}
}
使用ShadeDrawable来绘制圆形图片
ShapeDrawable shapeDrawable=new ShapeDrawable(new OvalShape());
shapeDrawable.getPaint().setShader(bitmapShader);
//设置drawable的大小
shapeDrawable.setBounds(0,0,getWidth(),getHeight());
shapeDrawable.draw(canvas);
例子二:放大镜效果
public class ZoomImageView extends View {
//放大倍数
private static final int FACTOR = 2;
//放大镜的半径
private static final int RADIUS = 100;
// 原图
private Bitmap mBitmap;
// 放大后的图
private Bitmap mBitmapScale;
// 制作的圆形的图片(放大的局部),盖在Canvas上面
private ShapeDrawable mShapeDrawable;
private Matrix mMatrix;
public ZoomImageView(Context context) {
super(context);
mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.xyjy3);
mBitmapScale = mBitmap;
//放大后的整个图片
mBitmapScale = Bitmap.createScaledBitmap(mBitmapScale,mBitmapScale.getWidth() * FACTOR,
mBitmapScale.getHeight() * FACTOR,true);
BitmapShader bitmapShader = new BitmapShader(mBitmapScale, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
mShapeDrawable = new ShapeDrawable(new OvalShape());
mShapeDrawable.getPaint().setShader(bitmapShader);
// 切出矩形区域,用来画圆(内切圆)
mShapeDrawable.setBounds(0,0,RADIUS * 2,RADIUS * 2);
mMatrix = new Matrix();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 1、画原图
canvas.drawBitmap(mBitmap, 0 , 0 , null);
// 2、画放大镜的图
mShapeDrawable.draw(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
// 将放大的图片往相反的方向挪动
mMatrix.setTranslate(RADIUS - x * FACTOR, RADIUS - y *FACTOR);
mShapeDrawable.getPaint().getShader().setLocalMatrix(mMatrix);
// 切出手势区域点位置的圆
mShapeDrawable.setBounds(x-RADIUS,y - RADIUS, x + RADIUS, y + RADIUS);
invalidate();
return true;
}
}
例子三:霓虹灯文字效果
public class NeonLightView extends AppCompatTextView {
private int DELTAX = 20;
private TextPaint paint;
private LinearGradient linearGradient;
private int move;//移动的距离
private float textWidth;//文字宽度
public NeonLightView(Context context) {
super(context);
}
public NeonLightView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
String text= getText().toString();
paint=getPaint();
textWidth=getPaint().measureText(text);
linearGradient=new LinearGradient(0,0,200,0,new int[]{0x22ffffff,0xffffffff,0x22ffffff},null, Shader.TileMode.CLAMP);
paint.setShader(linearGradient);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
move+=DELTAX;
float textWidth = getPaint().measureText(getText().toString());
if(move > textWidth + 1 || move < 1){
DELTAX = - DELTAX;
}
Matrix matrix=new Matrix();
matrix.setTranslate(move,0);
linearGradient.setLocalMatrix(matrix);
postInvalidateDelayed(100);
}
}
例子四:雷达扫描效果
public class RadarView extends View {
private final String TAG = "RadarView";
private static final int MSG_WHAT = 1;
private static final int DELAY_TIME = 20;
//设置默认宽高
private final int DEFAULT_WIDTH = 200;
private final int DEFAULT_HEIGHT = 200;
//雷达的半径
private int mRadarRadius;
//雷达画笔
private Paint mRadarPaint;
//雷达底色画笔
private Paint mRadarBg;
//雷达圆圈的个数,默认4个
private int mCircleNum = 4;
//雷达线条的颜色,默认为白色
private int mCircleColor = Color.WHITE;
//雷达圆圈背景色
private int mRadarBgColor = Color.BLACK;
//paintShader
private Shader mRadarShader;
//雷达扫描时候的起始和终止颜色
private int mStartColor = 0x0000ff00;
private int mEndColor = 0xaa00ff00;
private Matrix mMatrix;
//旋转的角度
private int mRotate = 0;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mRotate += 3;
postInvalidate();
mMatrix.reset();
mMatrix.preRotate(mRotate, 0, 0);
mHandler.sendEmptyMessageDelayed(MSG_WHAT, DELAY_TIME);
}
};
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);
mRadarBg = new Paint(Paint.ANTI_ALIAS_FLAG); //设置抗锯齿
mRadarBg.setColor(mRadarBgColor); //画笔颜色
mRadarBg.setStyle(Paint.Style.FILL); //画实心圆
mRadarPaint = new Paint(Paint.ANTI_ALIAS_FLAG); //设置抗锯齿
mRadarPaint.setColor(mCircleColor); //画笔颜色
mRadarPaint.setStyle(Paint.Style.STROKE); //设置空心的画笔,只画圆边
mRadarPaint.setStrokeWidth(2); //画笔宽度
mRadarShader = new SweepGradient(0, 0, mStartColor, mEndColor);
mMatrix = new Matrix();
}
//初始化,拓展可设置参数供布局使用
private void init(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RadarView);
mStartColor = ta.getColor(R.styleable.RadarView_startColor, mStartColor);
mEndColor = ta.getColor(R.styleable.RadarView_endColor, mEndColor);
mRadarBgColor = ta.getColor(R.styleable.RadarView_backgroundColor, mRadarBgColor);
mCircleColor = ta.getColor(R.styleable.RadarView_lineColor, mCircleColor);
mCircleNum = ta.getInteger(R.styleable.RadarView_circleNum, mCircleNum);
ta.recycle();
}
}
@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);
}
@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 specType 1为宽, 其他为高
* @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 onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.d(TAG, "onDraw " + mRotate);
mRadarBg.setShader(null);
//将画板移动到屏幕的中心点
canvas.translate(mRadarRadius, mRadarRadius);
//绘制底色,让雷达的线看起来更清晰
canvas.drawCircle(0, 0, mRadarRadius, mRadarBg);
//画圆圈
for (int i = 1; i <= mCircleNum; i++) {
canvas.drawCircle(0, 0, (float) (i * 1.0 / mCircleNum * mRadarRadius), mRadarPaint);
}
//绘制雷达基线 x轴
canvas.drawLine(-mRadarRadius, 0, mRadarRadius, 0, mRadarPaint);
//绘制雷达基线 y轴
canvas.drawLine(0, mRadarRadius, 0, -mRadarRadius, mRadarPaint);
// canvas.rotate(mRotate,0,0);
//设置颜色渐变从透明到不透明
mRadarBg.setShader(mRadarShader);
canvas.concat(mMatrix);
canvas.drawCircle(0, 0, mRadarRadius, mRadarBg);
}
public void startScan() {
mHandler.removeMessages(MSG_WHAT);
mHandler.sendEmptyMessage(MSG_WHAT);
}
public void stopScan() {
mHandler.removeMessages(MSG_WHAT);
}
}
例子五:水波纹效果
public class RippleView extends AppCompatButton {
// 点击位置
private int mX, mY;
private ObjectAnimator mAnimator;
// 默认半径
private int DEFAULT_RADIUS = 50;
private int mCurRadius = 0;
private RadialGradient mRadialGradient;
private Paint mPaint;
public RippleView(Context context) {
super(context);
init();
}
public RippleView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// 禁用硬件加速
setLayerType(LAYER_TYPE_SOFTWARE,null);
mPaint = new Paint();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mX != event.getX() || mY != mY) {
mX = (int) event.getX();
mY = (int) event.getY();
setRadius(DEFAULT_RADIUS);
}
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_UP:
{
if (mAnimator != null && mAnimator.isRunning()) {
mAnimator.cancel();
}
if (mAnimator == null) {
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);
}
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);
}
postInvalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(mX, mY, mCurRadius, mPaint);
}
}