老样子,先说下背景,最近做的一个音视频通话,要求对端画箭头、矩形,圆圈,android端能及时画出来,研究了半天,不得不说,有同事的帮助,,感谢我的同事给予我的帮助,让我学习了不少,现在总结一下 我的工作
首先自定义view 绘制,主要是在onDraw方法里面通过view的 invalidate()重绘方法去执行的,另有一个postinvalidate()是在子线程执行,这个区别我就不介绍了,自行查找一堆。。
先来看看我的自定义View类吧
/**
* Created by Jane on 2019/2/21.
*/
public class DrawView extends View {
private final String TAG = "DrawView";
private String jsonInfo;
public String getJsonInfo() {
return jsonInfo;
}
public void setJsonInfo(String jsonInfo) {
this.jsonInfo = jsonInfo;
}
public DrawView(Context context) {
super(context);
}
public DrawView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public DrawView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/*
* 方法 说明 drawRect 绘制矩形 drawCircle 绘制圆形 drawOval 绘制椭圆 drawPath 绘制任意多边形
* drawLine 绘制直线 drawPoin 绘制点
*/
// 创建画笔
String jsonInfo = getJsonInfo();
try {
if (!TextUtils.isEmpty(jsonInfo)) {
JSONObject json_info = new JSONObject(jsonInfo);
if (json_info.has("rectangle")) {
parseData(canvas, json_info, "rectangle");
} if (json_info.has("circle")) {
Log.e("sssss","circlr==");
parseData(canvas, json_info, "circle");
} if (json_info.has("arrow")) {
parseData(canvas, json_info, "arrow");
} if (json_info.has("dot")) {
JSONObject jsonDot=new JSONObject(json_info.optString("dot"));
int canvasX = ScreenUtils.getScreenWidth();
int canvasY = ScreenUtils.getScreenHeight();
float finX = Float.parseFloat(jsonDot.optInt("finl_X")+"");
float finY = Float.parseFloat(jsonDot.optInt("final_Y")+"");
int cavX = jsonDot.optInt("canvas_X");
int cavY = jsonDot.optInt("canvas_Y");
Log.e("sssss","鼠标值==finX=="+finX+"----finY=="+finY);
if (cavX!=0&&cavY!=0){
float cX = canvasX / cavX;
float cY = canvasY / cavY;
float fX = finX * cX;
float fY = finY * cY;
drawMouse(canvas, fX, fY, p);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* 解析数据
*/
public void parseData(Canvas canvas, JSONObject jsonInfo, String type) {
int canvasX = ScreenUtils.getScreenWidth();
int canvasY = ScreenUtils.getScreenHeight();
try {
JSONArray jsonArrayR = new JSONArray(jsonInfo.optString(type));
for (int i = 0; i < jsonArrayR.length(); i++) {
JSONObject jsonObjectR = jsonArrayR.optJSONObject(i);
float finX = Float.parseFloat(jsonObjectR.optString("finl_X"));
float finY = Float.parseFloat(jsonObjectR.optString("final_Y"));
int cavX = jsonObjectR.optInt("canvas_X");
int cavY = jsonObjectR.optInt("canvas_Y");
float startX = Float.parseFloat(jsonObjectR.optString("start_X"));
float startY = Float.parseFloat(jsonObjectR.optString("start_Y"));
String color = jsonObjectR.optString("color");
int lineWidth = jsonObjectR.optInt("lineWidth");
createPaint(color, lineWidth);
float cX = canvasX / cavX;
float cY = canvasY / cavY;
float sX = startX * cX;
float sY = startY * cY;
float fX = finX * cX;
float fY = finY * cY;
if (type.equals("circle")) {
drawCircle(sX, sY, fX, fY, canvas, p);//圆圈
} if (type.equals("rectangle")) {
canvas.drawRect(sX, sY, fX, fY, p);//矩形
} if (type.equals("arrow")) {
drawAL(canvas, p, sX, sY, fX, fY);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* 创建画笔
**/
Paint p = new Paint();
public void createPaint(String color, int lineWidth) {
/*
* 方法 说明 drawRect 绘制矩形 drawCircle 绘制圆形 drawOval 绘制椭圆 drawPath 绘制任意多边形
* drawLine 绘制直线 drawPoin 绘制点
*/
// 创建画笔
if (!TextUtils.isEmpty(color)) {
p.setColor(Color.parseColor(color));
} else {
p.setColor(Color.parseColor("#0000FF"));// 设置默认颜色
}
p.setStyle(Paint.Style.STROKE);//设置空心
p.setStrokeWidth(lineWidth);
}
/*画圆
*
* **/
public void drawCircle(float sX, float sY, float fX, float fY, Canvas canvas, Paint p) {
//算出圆心坐标 起点+终点坐标除以2
//半径 起点-终点坐标除以2
float centerX = (sX + fX) / 2;
float centerY = (sY + fY) / 2;
float rx = (sX - fX) / 2;
float ry = (sY - fY) / 2;
float r = Float.parseFloat(Math.sqrt(rx * rx + ry * ry) + "");
canvas.drawCircle(centerX, centerY, r, p);// 大圆
}
/**
* 画箭头
*
* @param sx
* @param sy
* @param ex
* @param ey
*/
public void drawAL(Canvas canvas, Paint paint, float sx, float sy, float ex, float ey) {
double H = 8; // 箭头高度
double L = 3.5; // 底边的一半
int x3 = 0;
int y3 = 0;
int x4 = 0;
int y4 = 0;
double awrad = Math.atan(L / H); // 箭头角度
double arraow_len = Math.sqrt(L * L + H * H); // 箭头的长度
double[] arrXY_1 = rotateVec(ex - sx, ey - sy, awrad, true, arraow_len);
double[] arrXY_2 = rotateVec(ex - sx, ey - sy, -awrad, true, arraow_len);
double x_3 = ex - arrXY_1[0]; // (x3,y3)是第一端点
double y_3 = ey - arrXY_1[1];
double x_4 = ex - arrXY_2[0]; // (x4,y4)是第二端点
double y_4 = ey - arrXY_2[1];
Float X3 = new Float(x_3);
x3 = X3.intValue();
Float Y3 = new Float(y_3);
y3 = Y3.intValue();
Float X4 = new Float(x_4);
x4 = X4.intValue();
Float Y4 = new Float(y_4);
y4 = Y4.intValue();
// 画线
canvas.drawLine(sx, sy, ex, ey, paint);
Path triangle = new Path();
triangle.moveTo(ex, ey);
triangle.lineTo(x3, y3);
triangle.lineTo(x4, y4);
triangle.close();
canvas.drawPath(triangle, paint);
}
/**
* 图片固定点
*/
Bitmap bitmap = null;
public void drawMouse(Canvas canvas, float x, float y, Paint paint) {
//画图片,就是贴图
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.mouse);
canvas.drawBitmap(bitmap, x, y, paint);
}
// 计算
public double[] rotateVec(float px, float py, double ang, boolean isChLen, double newLen) {
double mathstr[] = new double[2];
// 矢量旋转函数,参数含义分别是x分量、y分量、旋转角、是否改变长度、新长度
double vx = px * Math.cos(ang) - py * Math.sin(ang);
double vy = px * Math.sin(ang) + py * Math.cos(ang);
if (isChLen) {
double d = Math.sqrt(vx * vx + vy * vy);
vx = vx / d * newLen;
vy = vy / d * newLen;
mathstr[0] = vx;
mathstr[1] = vy;
}
return mathstr;
}
public void clear(Canvas canvas) {
Paint p = new Paint();
//清屏
p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawPaint(p);
p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
}
}
不难看出,这里面有参考别的小伙伴的,我也不求能涨个粉丝,只是为了让自己长知识,首先说一下遇到过的问题,需求是:绘制的矩形、圆圈、箭头 是多个,出现了一个bug就是,每次绘制的时候 ,只有最新的,之前的都自动清除,原因是,每次调用invalidate()方法,onDraw方法里面是if else 只会执行其中的一个,所以会把之前清除的自动刷新掉,只怪自己当时不明白,同事给我讲了一通。。我也是后知后觉的。。。
知道问题之后,就要想办法解决的哦,既然每次调用invalidate()都会重绘,那我能不能把之前每次收到的数据统一放入一个json中,将矩形、圆圈、箭头分别分成三个数组,绘制的时候遍历数组,逐一绘制呢,目前就是按照这种思路去写的。。
,为避免drawview重复创建 要判空的哦,,要不,画一个 创建一个对象,清除的时候会发现只清除了最后一次绘制的图形
以上就是这次的;理解,真的没说太好,,,大概就这样,有问题 一起交流哈