线
圆角线参考网址:Android自定义View(二) 画圆角线_perfectnihil的博客-CSDN博客_android paint 圆角
private void drawLine(Canvas canvas,
float startX,float startY,float stopX,float stopY,
float width,int color){
Paint paint = new Paint();
paint.setAntiAlias(true);//抗锯齿
paint.setStyle(Paint.Style.STROKE);//不加这个不显示
paint.setColor(color);
paint.setStrokeWidth(width);
Path mPath = new Path();
mPath.moveTo(startX, startY);
mPath.lineTo(stopX, stopY);
mPath.close();
//***************旋转线
//1.
canvas.save();
canvas.translate(startX, startY);//根据指定坐标旋转
//水平翻转
canvas.scale(-1,1);
//垂直翻转
canvas.scale(1,-1);
canvas.translate(-startX, -startY);
//2.
canvas.rotate(90, startX, startY);//根据指定角度、坐标来旋转
canvas.drawPath(mPath, paint);
canvas.restore();
//圆角线(线的两头是圆角),前提是线的起始点坐标不能是画布的边框坐标(不能是0,0和宽、高边)
paint .setStrokeCap(Paint.Cap.ROUND);
//设置线条渐变色(颜色可以设置多个)
int[] colors = new int[2];
colors[0]= Color.argb(255, 255, 255, 255);
colors[1]= Color.argb(255, 0, 255, 0);
LinearGradient shader = new LinearGradient(startX,
startY,endX,e,colors,null,Shader.TileMode.CLAMP);
//Shader.TileMode里有三种模式:CLAMP(拉伸)、MIRROR(镜像)、REPEAT(重复)
}
虚线
参考网址:Android 画虚线 DashPathEffect 使用详解_Android研发曹新雨的博客-CSDN博客
说明:
mPath.close();通过测试发现,此方法是用来形成一个闭合图;例如:只画一条虚线并带有流动效果,如果调用此方法则呈现的效果相当于是两条虚线对向流动,把此方法去掉则可以直观看到流动效果。
private void drawXuXian(Canvas canvas,float startX,float startY,float stopX,float stopY){
xuXianPaint.setStyle(Paint.Style.STROKE);//不加这个不显示
xuXianPaint.setColor(context.getResources().getColor(R.color.orange_light));
xuXianPaint.setStrokeWidth(2);
//意思是所画虚线规则是先画5个长度的实线,留下10个长度的空白
//数组规则(必须是偶数个数):实、虚、实、虚---先虚再实,每个数代表长度
//offSet:代表偏移量(>=0第一个先加实线长度,<0第一个先加虚线长度);配合定时器使用可实现跑马灯效果
PathEffect effects = new DashPathEffect(new float[]{5, 10}, offSet);
xuXianPaint.setPathEffect(effects);
Path mPath = new Path();
mPath.moveTo(startX, startY);
mPath.lineTo(stopX, stopY);
mPath.close();//如果画的不是闭合图形需要把这句去掉
canvas.drawPath(mPath, xuXianPaint);
}
//虚线实现跑马灯效果
int offSet = 0;
private Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if(offSet > 15){//15表示new float[]{5,10}这个数组中总和
offSet = 0;
}
offSet++;
invalidate();
}
};
Runnable task = new Runnable() {
@Override
public void run() {
handler.sendEmptyMessage(0);
handler.postDelayed(task,10);
}
};
矩形
private void drawRectangle(Canvas canvas,boolean choose,
float left,float top,float right,float bottom,int color){
Paint paint = new Paint();
paint.setAntiAlias(true);//抗锯齿
paint.setColor(color);
if (choose){
//设置实心矩形
paint.setStyle(Paint.Style.FILL);
}else{
//设置空心矩形
paint.setStyle(Paint.Style.STROKE);
}
//使用画笔在画布上画矩形
canvas.drawRect(left,top,right,bottom,paint);
}
多边形
private void drawJuXing(Canvas canvas,int color,float startX,float startY,float startX1,float startY1,
float startX2,float startY2,float startX3,float startY3){
juxingPaint.setStyle(Paint.Style.STROKE);//不加这个不显示
juxingPaint.setColor(color);
juxingPaint.setStrokeWidth(2);
juxingPaint.setStyle(Paint.Style.FILL);//是否填充
Path mPath = new Path();
float sX = startX*scale+pianyix_huitu;
float sY = startY*scale+pianyiy_huitu;
float sX1 = startX1*scale+pianyix_huitu;
float sY1 = startY1*scale+pianyiy_huitu;
float sX2 = startX2*scale+pianyix_huitu;
float sY2 = startY2*scale+pianyiy_huitu;
float sX3 = startX3*scale+pianyix_huitu;
float sY3 = startY3*scale+pianyiy_huitu;
mPath.moveTo(sX, sY);
mPath.lineTo(sX1, sY1);
mPath.lineTo(sX2, sY2);
mPath.lineTo(sX3, sY3);
mPath.close();
canvas.drawPath(mPath, juxingPaint);
}
圆形
private void drawYuan(Canvas canvas,boolean choose,
float startX,float startY,float radius,int color){
Paint paint = new Paint();
paint.setAntiAlias(true);//抗锯齿
paint.setColor(color);
if (choose){
//设置实心圆
paint.setStyle(Paint.Style.FILL);
}else{
//设置空心圆
paint.setStyle(Paint.Style.STROKE);
}
//X、Y坐标,radius半径
canvas.drawCircle(startX, startY, radius, paint);
}
曲线
private void drawQuXian(Canvas canvas,boolean choose,float startX,float startY,
float afterX,float afterY,
float stopX,float stopY,
float width,int color){
quxianPaint.setStrokeWidth(width);
quxianPaint.setColor(color);
if (choose){
//设置实心曲线
quxianPaint.setStyle(Paint.Style.FILL);
}else{
//设置空心曲线
quxianPaint.setStyle(Paint.Style.STROKE);
}
Path mPath = new Path();
mPath.moveTo(startX, startY);//开始点
mPath.quadTo(afterX, afterY, stopX, stopY);
canvas.drawPath(mPath, quxianPaint);
}
半圆
private void drawBanYuan(Canvas canvas,float left, float top, float right, float bottom,
float width,int color){
//参考网址:https://blog.csdn.net/fanleiym/article/details/84255231
banyuanPaint.setStrokeWidth(width);
banyuanPaint.setStyle(Paint.Style.FILL);
banyuanPaint.setColor(color);
if (userCenter){
banyuanPaint.setStyle(Paint.Style.FILL);//实心
}else{
banyuanPaint.setStyle(Paint.Style.STROKE);
}
RectF oval = new RectF(left,top,right,bottom);
//定义的圆弧的形状和大小的范围
//设置圆弧是从哪个角度来顺时针绘画的
//设置圆弧扫过的角度
//true:设置我们的圆弧在绘画的时候,是否经过圆形;设置空心(STROKE)时,参数true没效果
canvas.drawArc(oval,270,180,userCenter,banyuanPaint);
}
三角形
private void drawTriangle(Canvas canvas,boolean choose,
float startX,float startY,
float afterX,float afterY,
float stopX,float stopY,
float width,int color){
Paint paint = new Paint();
paint.setAntiAlias(true);//抗锯齿
paint.setStrokeWidth(width);
paint.setColor(color);
if (choose){
//设置实心三角形
paint.setStyle(Paint.Style.FILL);
}else{
//设置空心三角形
paint.setStyle(Paint.Style.STROKE);
}
Path mPath = new Path();
mPath.moveTo(startX, startY);
mPath.lineTo(afterX, afterY);
mPath.lineTo(stopX, stopY);
//将mpath封闭,也可以写 mpath.lineTo(100, 100);代替
mPath.close();
//绘制path路径
canvas.drawPath(mPath, paint);
}
旋转文字
private void drawText(Canvas canvas,String str,int size,float degrees,float startX,float
startY,int color){
Paint paint = new Paint();
paint.setAntiAlias(true);//抗锯齿
paint.setColor(color);
paint.setTypeface(Typeface.DEFAULT_BOLD);//字体
Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);//字体风格
paint.setTypeface(font);
paint.setTextSize(size);
//Paint设置水平居中
paint.setTextAlign(Paint.Align.CENTER);
float length = paint.measureText(str);//获取字体的长度
//获取文字的高度
//参考网址:http://www.voidcn.com/article/p-zqzznoyl-ce.html
//1.获取文字高度
Paint.FontMetrics fm = paint.getFontMetrics();
float fFontHeight = (float)Math.ceil(fm.descent - fm.ascent);
//2.获取文字高度---1和2获取到的高度不同
//参考网址:https://blog.csdn.net/u010661782/article/details/52805939
//Rect rect = new Rect();
//textPaint.getTextBounds(str,0,str.length(), rect);
//fFontHeight = rect.height();
float ncenterx = startX + (size - length) / 2;
if (degrees!=0){
//以指定坐标点旋转指定角度
canvas.rotate(degrees, ncenterx, startY);
}
canvas.drawText(str, ncenterx,startY,paint);
}
//***设置文字居中显示***
private void setTextLocation(){
String text = “123”;
textPain.setTextSize(textSize);
Rect rect = new Rect();
textPain.getTextBounds(text, 0, text.length(), rect);
height+rect.height();//获取字体高度
float length = textPain.measureText(text);//获取字体长度
//x坐标是文字第一个字的位置,y坐标是文字顶部的位置,所以上下居中需要+字体高度
canvas.drawText(text, (width-length)/2, (height+rect.height())/2, textPain);
}
Canvas转Bitmap,可把bitmap转png图片保存到手机
try {
Bitmap mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mBitmap);
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawLine(10, 10, 50, 50, paint);
//把Bitmap显示到控件中
ImageView iv = findViewById(R.id.iv);
iv.setImageBitmap(mBitmap);
//把Bitmap转png并保存到手机
FileOutputStream out = new FileOutputStream(FileHelper.getFileDefaultPath()+"123.png");
mBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
在指定图片上画图
Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.test);
Paint paint= new Paint();
paint.setColor(Color.BLUE);
canvas.drawLine(10, 10, 50, 50, paint);
Rect srcRect = new Rect(0, 0, mBitmap.getHeight(), mBitmap.getWidth());
Rect srcRect2 = new Rect(0, 0, width, height);
//Bitmap bitmap:要绘制的位图对象
//Rect src: 是对图片进行裁截,若是空null则显示整个图片
//RectF dst:是图片在Canvas画布中显示的区域
//Paint paint:画笔,这个不用多说
canvas.drawBitmap(bitmap , srcRect , srcRect2, paint);
//***canvas中引用项目中图片,并填充***
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.bg);
bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
//Bitmap:图片对象,left:偏移左边的位置,top: 偏移顶部的位置
canvas.drawBitmap(bitmap,0,0,null);
Canvas引用项目中图片,并支持移动和缩放(以图片为中心点缩放,效果并不是以图片中心缩放)
//获取Res下的drawable或mipmap文件夹下图片资源
private Bitmap getRes(Context context,String imageName) {
ApplicationInfo appInfo = context.getApplicationInfo();
int resID = context.getResources().getIdentifier(imageName, "mipmap", appInfo.packageName);
return BitmapFactory.decodeResource(context.getResources(), resID);
}
//postTranslate+postScale控制移动和缩放
//dL+pianyix_huitu/scale----这样是为了和点、线、圆等其他画的图形平移、缩放保持一致
private void addPeople(Canvas canvas,float dL,float dB){
Bitmap bgimg = getRes(context,"user");
Matrix matrix = new Matrix();
matrix.postTranslate(dL+pianyix_huitu/scale,
dB+pianyiy_huitu/scale);//平移(初始位置+移动位置)
matrix.postScale(scale, scale);//缩放
canvas.drawBitmap(bgimg, matrix, textPaint);
}
Canvas中显示图片,并支持移动和缩放(第2中方法,缩放效果是以图片中心缩放)
//canvas中显示图片,并支持移动和缩放
private void drawPic(Canvas canvas,String picName,float x,float y){
float sX = x*scale+pianyix_huitu;
float sY = y*scale+pianyiy_huitu;
Bitmap bitmap =choosePIC(picName);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
//src只是整张图片的一部分
Rect src = new Rect((int)sX, (int)sY,width,height);
int width2 = (int) (width*scale+pianyix_huitu);
int height2 = (int) (height*scale+pianyiy_huitu);
Rect dst = new Rect((int)sX, (int)sY,width2,height2);
canvas.drawBitmap(bitmap,null,dst,picPaint);
}
//加载项目中assets中图片资源,根据自己需求也可以加载网络图片
//通过地址获取到图片的InputStream,再转成bitmap即可
private Bitmap choosePIC(String pic){
String lowerCaseStr = pic.toLowerCase();
Bitmap bitmap = null;
try {
InputStream is = context.getAssets().open("pic/"+lowerCaseStr+".jpg");
if (is==null){
is = context.getAssets().open("pic/nopic.jpg");
}
bitmap = BitmapFactory.decodeStream(is);
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
人员位置(自己画的,给图形加了个边框,为了支持点击)
private void drawPeople(Canvas canvas,float x,float y,int color){
float leftX = 500;//测试坐标X
float topY = 200;//测试坐标Y
float juxingW = 40;//宽
float juxingH = 20;//高
int strokeW = 3;//线宽
//该图形放置到指定坐标点上边位置
leftX = x-juxingW/2;//实际使用X
topY = y-5-juxingH;//实际使用Y
bkPaint.setStyle(Paint.Style.STROKE);//不加这个不显示
bkPaint.setColor(context.getResources().getColor(R.color.myquantouming));
canvas.drawRect(leftX*scale+pianyix_huitu,topY*scale+pianyiy_huitu,
(leftX+juxingW)*scale+pianyix_huitu,(topY+juxingH)*scale+pianyiy_huitu,bkPaint);
peoplePaint.setStyle(Paint.Style.STROKE);//不加这个不显示
if (color==0){//选择颜色
peoplePaint.setColor(context.getResources().getColor(R.color.kgl_people_me));
}else{
peoplePaint.setColor(context.getResources().getColor(R.color.my_blue));
}
peoplePaint.setStrokeWidth(strokeW);
peoplePaint.setStyle(Paint.Style.STROKE);
//头
canvas.drawCircle((leftX+juxingW/4)*scale+pianyix_huitu,
(topY+juxingH/4)*scale+pianyiy_huitu+strokeW,
juxingH/4*scale, peoplePaint);
//身体
RectF oval = new RectF(leftX*scale+pianyix_huitu+strokeW,
(topY+juxingH/2)*scale+pianyiy_huitu+strokeW,
(leftX+juxingW/2)*scale+pianyix_huitu,
(topY+juxingH+juxingH/2)*scale+pianyiy_huitu-strokeW);
//定义的圆弧的形状和大小的范围
//设置圆弧是从哪个角度来顺时针绘画的
//设置圆弧扫过的角度
//true:设置我们的圆弧在绘画的时候,是否经过圆形;设置空心(STROKE)时,参数true没效果
canvas.drawArc(oval,-180,180,false,peoplePaint);
//武器1
Path mPath = new Path();
float startX = (leftX+juxingW/2+juxingW/2/4)*scale+pianyix_huitu;
float startY = (topY+juxingH/2+juxingH/2/2)*scale+pianyiy_huitu;
float stopX = startX;
float stopY = (topY+juxingH/2+juxingH/2/2+juxingH/2/2)*scale+pianyiy_huitu;
mPath.moveTo(startX, startY);
mPath.lineTo(stopX, stopY);
mPath.close();
canvas.drawPath(mPath, peoplePaint);
//武器2
mPath = new Path();
startX = (leftX+juxingW/2+juxingW/2/4*2)*scale+pianyix_huitu;
startY = (topY+juxingH/2)*scale+pianyiy_huitu;
stopX = startX;
stopY = (topY+juxingH/2+juxingH/2)*scale+pianyiy_huitu;
mPath.moveTo(startX, startY);
mPath.lineTo(stopX, stopY);
mPath.close();
canvas.drawPath(mPath, peoplePaint);
//武器3
mPath = new Path();
startX = (leftX+juxingW/2+juxingW/2/4*3)*scale+pianyix_huitu;
startY = topY*scale+pianyiy_huitu;
stopX = startX;
stopY = (topY+juxingH)*scale+pianyiy_huitu;
mPath.moveTo(startX, startY);
mPath.lineTo(stopX, stopY);
mPath.close();
canvas.drawPath(mPath, peoplePaint);
}
简单汽车图形(自己画的,给图形加了个边框,为了支持点击)
private void drawCar(Canvas canvas,float x,float y){
float leftX = 500;
float topY = 200;
leftX = x-juxingW/2;
topY = y-5-juxingH;
bkPaint.setStyle(Paint.Style.STROKE);//不加这个不显示
bkPaint.setColor(context.getResources().getColor(R.color.myquantouming));
bkPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(leftX*scale+pianyix_huitu,topY*scale+pianyiy_huitu,
(leftX+juxingW)*scale+pianyix_huitu,(topY+juxingH+juxingW/8)*scale+pianyiy_huitu,bkPaint);
//车头
bkPaint.setColor(context.getResources().getColor(R.color.myblue));
bkPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(leftX*scale+pianyix_huitu,topY*scale+pianyiy_huitu,
(leftX+juxingW)*scale+pianyix_huitu,(topY+juxingH)*scale+pianyiy_huitu,bkPaint);
//轱辘
peoplePaint.setStyle(Paint.Style.STROKE);//不加这个不显示
peoplePaint.setColor(context.getResources().getColor(R.color.myblue));
peoplePaint.setStyle(Paint.Style.FILL);
canvas.drawCircle((leftX+juxingW/4)*scale+pianyix_huitu,
(topY+juxingH)*scale+pianyiy_huitu,
juxingW/8*scale, peoplePaint);
canvas.drawCircle((leftX+juxingW-juxingW/4)*scale+pianyix_huitu,
(topY+juxingH)*scale+pianyiy_huitu,
juxingW/8*scale, peoplePaint);
}
获取控件的宽高
参考网址:Android 获取控件的宽和高_Chiclaim-CSDN博客_android 获取控件高度
ImageView test = findViewById(R.id.test);
ViewTreeObserver vto2 = draw_test.getViewTreeObserver();
vto2.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
draw_test.getViewTreeObserver().removeGlobalOnLayoutListener(this);
width = test.getWidth();
height = test.getHeight();
}
});