一直对画画相关不感冒,但是Android的绘图机制还是要硬着头皮学
绘画主要是使用paint(画笔)在canvas(画布)进行各种图形的绘制,画矩形、圆、三角形等点线构成的2维图形
//矩形 drawRect (float left, float top, float right, float bottom, Paint paint)
canvas.drawRect(50, 100, 200, 200, paint);
//圆 drawCircle (float cx, float cy, float radius, Paint paint)
canvas.drawCircle(width / 2, height / 2, 100, paint);
//三角形(画线)
//实例化路径
Path path = new Path();
path.moveTo(80, 300);// 此点为多边形的起点
path.lineTo(120, 250);
path.lineTo(80, 250);
path.close(); // 使这些点构成封闭的多边形
canvas.drawPath(path, paint);
//扇形 RectF (float left, float top, float right, float bottom)
RectF rectF = new RectF(160, 200, 400, 400);
// drawArc (RectF oval, float startAngle 起始弧度, float sweepAngle 扫过的弧度, boolean useCenter, Paint paint)
canvas.drawArc(rectF, 200, 130, true, paint);
//椭圆
rectF = new RectF(300, 300, 600, 600);
// set (float left, float top, float right, float bottom)
rectF.set(210,100,450,200);
// drawOval (RectF oval, Paint paint)
canvas.drawOval(rectF, paint);
//曲线
//设置空心
paint.setStyle(Paint.Style.STROKE);
path = new Path();
path.moveTo(500, 500);//设置Path的起点
path.quadTo(550, 510, 670, 600); //设置路径点和终点
canvas.drawPath(path, paint);
//文字+ 图片
paint.setTextSize(30);
//文本 drawText (String text, float x, float y, Paint paint)
canvas.drawText("slack", 350, 330, paint);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
//图片 drawBitmap (Bitmap bitmap, float left, float top, Paint paint)
canvas.drawBitmap(bitmap, 320, 360, paint);
canvas有几个重要的方法,画图时会使用到,类似ps里的图层,旋转,位移的概念
/*
* Canvas.save() 将之前的图像保存起来,让后续的操作能像在新的画布一样操作
* Canvas.restore() 合并图层
* Canvas.translate() 平移 我们绘制的时候默认坐标点事左上角的起始点,那么我们调用translate(x,y)之后,
则将原点(0,0)移动到(x,y)之后的所有绘图都是在这一点上执行的
* Canvas.roate() 旋转
* */
画一个时钟,就把这些理解了
//画时钟
// 画外圆
Paint paintCircle = new Paint();
paintCircle.setAntiAlias(true);
paintCircle.setStyle(Paint.Style.STROKE);
paintCircle.setStrokeWidth(5);
canvas.drawCircle(width / 2, height / 2, width / 3, paintCircle);
// 画刻度
Paint paintDegree = new Paint();
paintDegree.setStrokeWidth(3);
canvas.rotate(30, width / 2, height / 2);
for (int i = 1; i <= 12; i++) {
// 区别整点和非整点
if (i == 3 || i == 6 || i == 9 || i == 12 ) {
paintDegree.setStrokeWidth(5);
paintDegree.setTextSize(30);
// drawLine (float startX, float startY, float stopX, float stopY, Paint paint)
canvas.drawLine(width / 2, height / 2 - width / 3,
width / 2, height / 2 - width / 3 + 60, paintDegree);
String degree = String.valueOf(i);
canvas.drawText(degree,
width / 2 - paintDegree.measureText(degree) / 3,
height / 2 - width / 3 + 90, paintDegree);
} else {
paintDegree.setStrokeWidth(3);
paintDegree.setTextSize(15);
// 圆上的一点(x = 屏幕宽一半, y = 屏幕的一半 - 半径)
canvas.drawLine(width / 2, height / 2 - width / 3,
width / 2, height / 2 - width / 3 + 30, paintDegree);
String degree = String.valueOf(i);
canvas.drawText(degree,
width / 2 - paintDegree.measureText(degree) / 3,
height / 2 - width / 3 + 60, paintDegree);
}
// 通过旋转画布——实际上是旋转了画图的坐标轴 简化坐标运算
canvas.rotate(30, width / 2, height / 2);
}
canvas.save();
// 画指针
Paint paintHour = new Paint();
paintHour.setStrokeWidth(15);
Paint paintMinute = new Paint();
paintMinute.setStrokeWidth(10);
//绘制的时候默认坐标点事左上角的起始点,那么我们调用translate(x,y)之后,则将原点(0,0)移动到(x,y)之后的所有绘图都是在这一点上执行的
canvas.translate(width / 2, height / 2);
canvas.drawPoint(0, 0, paintHour);//圆点
canvas.drawLine(0, 0, 100, 100, paintHour);
canvas.drawLine(0, 0, 100, -200, paintMinute);
canvas.restore();
模拟刮刮乐
// PorterDuffXfermode 刮刮乐 通过DST_IN.SRC_IN模式来实现将一个矩形变成圆角图片的效果
mPaint = new Paint();
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeWidth(50);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPath = new Path();
// createBitmap (int width, int height, Bitmap.Config config)
mFgBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mFgBitmap);
mCanvas.drawColor(Color.GRAY);
/**
* 触摸事件
* 画一条透明的线 曲线
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPath.reset();
lastX = event.getX();
lastY = event.getY();
mPath.moveTo(lastX, lastY);//起点
break;
case MotionEvent.ACTION_UP:
mPath.lineTo(event.getX(), event.getY());
break;
case MotionEvent.ACTION_MOVE:
//移动时,记录这一次的点位置
mPath.quadTo(lastX, lastY, event.getX(), event.getY()); //设置曲线路径点和终点
lastX = event.getX();
lastY = event.getY();
break;
}
mCanvas.drawPath(mPath, mPaint);
invalidate();
return true;
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
//刮刮乐
canvas.drawBitmap(mFgBitmap, 0, 0, null);
}
SurfaceView主要用于频繁刷新处,做一个画板
SurfaceView的简单使用也简单
public class SurfaView extends SurfaceView implements SurfaceHolder.Callback, Runnable
在线程里处理绘画的事件,贴上代码
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
* SurfaceView的使用
* Created by chenling on 2016/5/9.
* 1.View主要用于自动更新的情况下,而surfaceVicw主要适用于被动更新,例如频繁刷新
* 2.View在主线程中刷新,而surfaceView通常会通过一 个子线程来进行页面刷新。
* 3.View在绘制的时候没有双缓冲机制,而surfaceVicw在底层实现机制中就已经实现了双缓冲机制;
*/
public class SurfaView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
//SurfaceHolder
private SurfaceHolder mHolder;
//用于绘制的Canvas
private Canvas mCanvas;
//子线程标志位
private boolean mIsDrawing;
private float lastX,lastY;
private Path mPath;
private Paint mPaint;
/**
* 构造方法
*
* @param context
* @param attrs
*/
public SurfaView(Context context, AttributeSet attrs) {
super(context, attrs);
mPath = new Path();
mPaint = new Paint();
mPaint.setStrokeWidth(20);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mHolder = getHolder();
mHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
setKeepScreenOn(true);
}
// 创建
@Override
public void surfaceCreated(SurfaceHolder holder) {
mIsDrawing = true;
new Thread(this).start();
}
// 改变
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
//销毁
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsDrawing = false;
}
@Override
public void run() {
while (mIsDrawing) {
draw();
// lastX += 1;
// lastY = (int) (100 * Math.sin(lastX * 2 * Math.PI / 180) + 400);
// mPath.lineTo(lastX, lastY);
}
}
// 负责绘画,频繁刷新
private void draw() {
try {
mCanvas = mHolder.lockCanvas();
mCanvas.drawColor(Color.WHITE);
mCanvas.drawPath(mPath, mPaint);
} catch (Exception e) {
} finally {
if (mCanvas != null) {
//提交
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
/**
* 触摸事件
*
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
lastX = event.getX();
lastY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPath.moveTo(lastX, lastY);
break;
case MotionEvent.ACTION_MOVE:
mPath.lineTo(lastX,lastY);
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
}
附件:源码:
https://github.com/CL-window/android_paint