一、Canvas--画布
可以理解为美术课上的画板,这个类提供了绘制各种基本图形的方法,如下图所示,
只截取了部分drawXXX方法,从上面方法的名字看来我们可以知道Canvas可以绘制的对象有:弧线(arcs)、填充颜色(argb和color)、 Bitmap、圆(circle和oval)、点(point)、线(line)、矩形(Rect)、图片(Picture)、圆角矩形 (RoundRect)、文本(text)、顶点(Vertices)、路径(path)。通过组合这些对象我们可以画出各种各样的图像。为了满足不同场合的需求,还提供了一些对Canvas进行操作的方法:rorate、scale、translate、skew(扭曲)等,而且它允许你通过获得它的转换矩阵对象直接操作它。这些操作就像是虽然你的笔还是原来的地方画,但是画纸旋转或者移动了,所以你画的东西的方位就产生变化。为了方便一些转换操作,Canvas 还提供了保存和回滚属性的方法(save和restore),比如你可以先保存目前画纸的位置(save),然后旋转90度,向下移动100像素后画一些图形,画完后调用restore方法返回到刚才保存的位置。
二、Paint--画笔
Paint即画笔,在绘图过程中起到了极其重要的作用,画笔主要保存了颜色,样式等绘制信息,指定了如何绘制文本和图形,画笔对象有很多设置方法,大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关。
1.图形绘制
setARGB(int a,int r,int g,int b);
设置绘制的颜色,a代表透明度,r,g,b代表颜色值。
setAlpha(int a);
设置绘制图形的透明度。
setColor(int color);
设置绘制的颜色,使用颜色值来表示,该颜色值包括透明度和RGB颜色。
setAntiAlias(boolean aa);
设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。
setDither(boolean dither);
设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
setFilterBitmap(boolean filter);
如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作,加快显示速度,本设置项依赖于dither和xfermode的设置
setMaskFilter(MaskFilter maskfilter);
设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等
setColorFilter(ColorFilter colorfilter);
设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果
setPathEffect(PathEffect effect);
设置绘制路径的效果,如点画线等
setShader(Shader shader);
设置图像效果,使用Shader可以绘制出各种渐变效果
setShadowLayer(float radius ,float dx,float dy,int color);
在图形下面设置阴影层,产生阴影效果,radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色
setStyle(Paint.Style style);
设置画笔的样式,为FILL,FILL_AND_STROKE,或STROKE
setStrokeCap(Paint.Cap cap);
当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式Cap.ROUND,或方形样式Cap.SQUARE
setSrokeJoin(Paint.Join join);
设置绘制时各图形的结合方式,如平滑效果等
setStrokeWidth(float width);
当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度
setXfermode(Xfermode xfermode);
设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果
2.文本绘制
setFakeBoldText(boolean fakeBoldText);
模拟实现粗体文字,设置在小字体上效果会非常差
setSubpixelText(boolean subpixelText);
设置该项为true,将有助于文本在LCD屏幕上的显示效果
setTextAlign(Paint.Align align);
设置绘制文字的对齐方向
setTextScaleX(float scaleX);
设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果
setTextSize(float textSize);
设置绘制文字的字号大小
setTextSkewX(float skewX);
设置斜体文字,skewX为倾斜弧度
setTypeface(Typeface typeface);
设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等
setUnderlineText(boolean underlineText);
设置带有下划线的文字效果
setStrikeThruText(boolean strikeThruText);
设置带有删除线的效果
3.其他设置bitmapShader--位图平铺,常用来实现图片圆角的绘制
linearGradient--线性渐变
radialGradient--环形渐变
sweepGradient--角度渐变
composeShader--组合效果(组合以上几种)
三、Rect/RectF
Rect和RectF用法一样,区别仅仅在于精度,一般用于设置绘图区域,
public RectF(float left, float top, float right, float bottom) { this.left = left; this.top = top; this.right = right; this.bottom = bottom; }构造函数的四个参数表示,矩形的左边坐标,顶部坐标,右边坐标,底部坐标,这样就限定了矩形的大小,我们绘制的图像就在这个矩形里面。它还有一个构造方法,已现有的RectF对象作为参数,就相当于拷贝。public RectF(RectF r) { if (r == null) { left = top = right = bottom = 0.0f; } else { left = r.left; top = r.top; right = r.right; bottom = r.bottom; } }Rect/RectF了解这么多就行了。
四、实例1.矩形public class CustomView extends View { Paint mPaint; RectF rectF; public CustomView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { mPaint = new Paint(); mPaint.setAntiAlias(false);// 不使用锯齿 mPaint.setColor(Color.GREEN);// 绿色 mPaint.setStyle(Paint.Style.FILL);// 填充 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawRect(0, 250, 400, 450, mPaint); } }
也可以先生成RectF对象,然后传入该参数,效果是一样的。
rectF = new RectF(0, 250, 400, 450); canvas.drawRect(rectF, mPaint);2.圆canvas.drawCircle(200, 200, 100, mPaint);
3.圆弧
canvas.drawArc(rectF, 0, 90, false, mPaint);
如果将第三个参数设为true,
rectF = new RectF(0,0,400,400); canvas.drawArc(rectF, 0, 90, true, mPaint);
4.文字
public class CustomView extends View { Paint mPaint; RectF rectF; public CustomView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { mPaint = new Paint(); mPaint.setAntiAlias(false);// 不使用锯齿 mPaint.setColor(Color.RED);// 红色 mPaint.setStyle(Paint.Style.FILL);// 填充 mPaint.setTextSize(64); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawText("Test draw text!!!", 20, 200, mPaint); } }
5.图像
Bitmap bitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(context.getResources(), R.drawable.head)); canvas.drawBitmap(bitmap, 100, 100, null);
基本图形就举这几个例子,其他的drawXXX方法也是类似的使用,再看几个渐变效果,
Shader mLinearGradient = new LinearGradient(100, 100, 800, 100, new int[]{Color.YELLOW, Color.GREEN, Color.BLUE, Color.RED}, null, Shader.TileMode.REPEAT); mPaint.setShader(mLinearGradient); mPaint.setStrokeWidth(30); canvas.drawLine(100, 100, 800, 100, mPaint); Shader mRadialGradient = new RadialGradient(400, 400, 160, new int[]{Color.YELLOW, Color.GREEN, Color.BLUE, Color.RED}, null, Shader.TileMode.REPEAT); mPaint.setShader(mRadialGradient); canvas.drawCircle(400, 400, 160, mPaint); Shader mSweepGradient = new SweepGradient(400, 800, new int[]{Color.YELLOW, Color.GREEN, Color.BLUE, Color.RED}, new float[]{0, 0.08f, 0.15f, 0.25f}); mPaint.setShader(mSweepGradient); RectF rectF = new RectF(200,600,600,1000); canvas.drawArc(rectF, 0, 360, true, mPaint);LinearGradient的构造函数,如下有两种,public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[], TileMode tile) public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, TileMode tile)第二种适用于两种颜色的渐变,第一种可以有多个颜色的渐变,还可以指定位置,参数具体含义,@param x0 起始x坐标
@param y0 起始y坐标
@param x1 结束x坐标
@param y1 结束y坐标
@param colors 颜色数组
@param positions 位置数组,可以为空
@param tile Shader模式--CLAMP,REPEAT,MIRRORRadialGradient和SweepGradient的构造函数与LinearGradient类似,不再赘述,还有一个组合模式ComposeShader,其实就是讲几种Shader组合起来使用。
public RadialGradient(float centerX, float centerY, float radius, @NonNull int colors[], @Nullable float stops[], @NonNull TileMode tileMode) public RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, @NonNull TileMode tileMode)public SweepGradient(float cx, float cy, int colors[], float positions[]) public SweepGradient(float cx, float cy, int color0, int color1)
五、自定义一个扫描效果之前讲的几个例子都是绘制静态的图片,这里做一个动态扫描的动画,先贴效果图,
其实就是一个扇形--drawArc,然后绕着圆心旋转--rotate,为了有一个渐变的效果,设置着色器--SweepGradient;然后用一个布尔变量IsScanning来判断是否正在扫描,如果是的话,就将画布Canvas旋转一个角度,进行绘制,直到停止。按照这个思路就可以很容易把这个效果画出来了,代码如下。package com.example.drawdemo; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.SweepGradient; import android.util.AttributeSet; import android.util.Log; import android.view.View; /** * Created by dingfeng on 2016/6/13. */ public class ScanView extends View { int width = 0; // View宽度,可在xml中设置android:layout_width="360dp" int height = 0; // View高度,可在xml中设置android:layout_height="360dp" Paint mPaint; RectF rectF; float firstAngle = 0; //初始角度,3点钟方向是0度 float radian = 60; // 弧度,扫过的角度 float offsetArc = 0; // 偏移角度 boolean IsScanning = false; public ScanView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { mPaint = new Paint(); mPaint.setColor(Color.GREEN); mPaint.setAntiAlias(false); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 注意,在构造函数中无法获取宽高的 width = getWidth(); height = getHeight(); int center = Math.min(width, height); rectF = new RectF(0, 0, center, center); // 绘图区域 // 设置渐变色 Shader mShader = new SweepGradient(center / 2, center / 2, new int[]{Color.TRANSPARENT, Color.BLUE}, null); mPaint.setShader(mShader); if (IsScanning) { canvas.rotate(offsetArc, center / 2, center / 2); canvas.drawArc(rectF, firstAngle, radian, true, mPaint); offsetArc = offsetArc + 3; // 每次增加3个角度 } else { canvas.rotate(offsetArc, center / 2, center / 2); canvas.drawArc(rectF, firstAngle, radian, true, mPaint); } if (IsScanning) { invalidate(); } } public void start() { IsScanning = true; invalidate(); } public void stop() { IsScanning = false; } }