Android Canvas、Paint、Path、drawBitmap
来源:互联网 发布:easybcd怎么引导linux 编辑:程序博客网 时间:2024/05/29 10:06
我们平常的画图都是通过Paint画笔在Canvas画布上进行绘制的,我们在画图之前首先就是要把我们的画笔设置好。就跟我们平时画图一样,先要选好画笔的粗细、颜色以及透明度,然后我们才开始作画,最后将Canvas画布呈现给用户。
我们来认识一些具体的方法:
画图之前我们是要准备好Pint(画笔)的,那么我们就来整一个画笔对象。
先了解一下画笔的一些样式
Paint.Style.FILL:填充内部也就是我们平时所说的实心的
Paint.Style.FILL_AND_STROKE :填充内部和描边 描边其实就是我们事先画好一个模型,然后再填充颜色空心圆到实心圆的变化
Paint.Style.STROKE :描边也就是我们所说的空心的
Paint paint= new Paint(Paint.ANTI_ALIAS_FLAG);
Paint.ANTI_ALIAS_FLAG就是消除锯齿使用以后边界就会变的稍微有点模糊,锯齿就看不到了
paint.setColor(Color.RED)设置画笔的颜色,画笔的颜色可以是系统的也可以自己设置
paint.setStrokeWidth(3);设置空心画笔的宽度,画笔的粗细可以通过此方法进行设置
有点也就有线,canvas里面有一个drawLine方法可以通过canvas.drawLine来画一条线。有线也有面的我们可以通过
canvas.drawLine(100,100,200,200,paint);里面的前四个参数分别是float startX, float startY, float stopX, float stopY。因为我们说话的其实是一条对角线,所以我们就以下面的矩形草图的AC两点来说明。startX则相当于A点的X坐标,startY则是A点的Y坐标,stopX则相当于C点的X坐标,stopY则是C点的Y坐标。
canvas.drawRect方法来画一个区域
示例代码为
@Override protected void onDraw(Canvas canvas) { canvas.drawLine(100,100,200,200,paint); canvas.drawRect(100,300,200,400,paint); }
我们还要了解一下paint的一些其他样式,以备用时之需。
paint.setStrokeJoin(Join join)设置结合处的样子使用为paint.setStrokeJoin(Paint.Join.ROUND),Round:结合处为圆弧,Miter:结合处为锐角, BEVEL:结合处为直线。设置时要注意:Paint.Style.FILL为默认的画笔样式,但是此种样式效果会显示不出来,所以建议使用另外Paint.Style.FILL_AND_STROKE 和Paint.Style.STROKE 两种样式其中的一种。
效果图为
示例代码为
@Override protected void onDraw(Canvas canvas) { paint.setStrokeWidth(20); paint.setStyle(Paint.Style.STROKE); paint.setStrokeJoin(Paint.Join.ROUND); canvas.drawRect(160, 80, 250, 180, paint); paint.setStrokeJoin(Paint.Join.MITER); canvas.drawRect(160, 240, 250, 340, paint); paint.setStrokeJoin(Paint.Join.BEVEL); canvas.drawRect(160, 400, 250, 500, paint); }
setStrokeCap(Cap cap)设置线末端的
paint.setStrokeCap(Paint.Cap.ROUND);它也有三种样式分别为ROUND、BUTT、SQUARE画笔样式虽然三种都可以设置,但是此种样式下显示的没有空心效果的,而且画笔在显示的区域内越粗效果越明显。由于是设置线的末端因此要调用的是canvas.drawLine的方法。
效果图为
示例代码为
@Override protected void onDraw(Canvas canvas) { paint.setStrokeWidth(100); paint.setStyle(Paint.Style.STROKE); paint.setStrokeCap(Paint.Cap.ROUND); canvas.drawLine(160, 80, 250, 80, paint); paint.setStrokeCap(Paint.Cap.BUTT); canvas.drawLine(160, 240, 250, 240, paint); paint.setStrokeCap(Paint.Cap.SQUARE); canvas.drawLine(160, 400, 250, 400, paint); }
Path类可以预先在View上将N个点连成一条”路径”,然后调用Canvas的drawPath(path,paint)即可沿着路径绘制图形
使用path也是要实例化一个对象然后调用其内部方法。
下面我们先来画一个三角形
示例代码为
@Override protected void onDraw(Canvas canvas) { Path path=new Path(); path.moveTo(210,210); path.lineTo(210,350); path.lineTo(280,350); canvas.drawPath(path,paint); }
画图肯定是是起笔点的位置,path.moveTo就是先把一个起点移动到屏幕的某个位置,然后再以这一点开始移动到其他坐标点连城线,图形的形成就是先有点到线,再有先到面,点与点之间连成线,线与线之间连接起来就是一个面,上面的代码就是把起点移动到下图(下图只是一个草图,方便讲解而已)的A点path.moveTo(210,210);public void moveTo(float x, float y)通过对比很容易发现,参数里面的第一个210就是Ax ,第二个210就是Ay。path.lineTo(210,350)lineTo很明显就是连线到的意思,就是在起点和lineTo的坐标点之间连成一条线(AB),最后一个lineTo也是一样,不过是与前面lineTo的点连成一条线(BC),最后就是闭合,也就是最后一个lineTo点连接起点,形成一条线也就是我们看到的(AC),我们看到的图形就是这么形成的。
关于四边形的我们上面的canvas.drawRect(100,300,200,400,paint);
如果不知道如何设置float left, float top, float right, float bottom, 这几个参数,可以参考下面的关于正方形ABCD四个顶点的草图。left就是A和B的X坐标值,top就是A和D的Y坐标值,right就是C和D的X坐标值,bottom就是B和C的Y坐标值。记住这几点就会很容易的运用drawRect方法画出我们想要的矩形了。
已经实现过了,但是我们也可以通过path来完成
图形还是那个图形
示例代码为
@Override protected void onDraw(Canvas canvas) { Path path=new Path(); path.moveTo(100,300); path.lineTo(100,400); path.lineTo(200,400); path.lineTo(200,300); canvas.drawPath(path,paint); }
作图前要先想好画什么样的图形,如果是正方形,那么就要考虑到正方形的四个顶点的位置,如何确定呢,关于lineTo上面画三角形的时候已经介绍过,可以看一下。我们首先要确定四个顶点,起点的位置可以随意锚点,但是剩下的三个点就要按照一定的方式去设置了。如下图,加入我们以A点为起点,那么B点的X坐标就要跟A点的一样,那么Y轴呢?如果我们想画一个边长为100的正方形,我们就要在A点坐标的Y值上面加上100设置为B的Y点坐标值,这样B坐标就确定了,C点的坐标跟B点坐标的Y值是一样的,X坐标值是什么呢?我们可以看到C和B是在一条水平线上,C在B的右侧那么就要在B点的X坐标值上面加上100设置为C点坐标的X值,确定了B和C两点坐标的值就可以确定D点的了,因为D点坐标的X值其实就是A的Y坐标值,X值就是C的X坐标值。这样我们就可以完美的画出上面的矩形了。
我们如果想要扇形怎么办?我们可以通过canvas的drawArc方法来实现。drawArc方法里面含有四个参数分辨是:oval :指定圆弧的外轮廓矩形区域。startAngle: 圆弧起始角度,就是我们画笔的起点位置,单位为度。sweepAngle: 圆弧扫过的角度,也就是想要画的扇形的弧度,顺时针方向,单位为度。useCenter: 如果为True时,在绘制圆弧时将圆心包括在内,通常用来绘制扇形。我们先来实现一下
示例代码为
@Overrideprotected void onDraw(Canvas canvas) { paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); canvas.drawRect(50, 300, 150, 400, paint); RectF rect = new RectF(50, 300, 150, 400); canvas.drawArc(rect, -180, 180, true, paint); paint.setStyle(Paint.Style.STROKE); RectF rect1 = new RectF(200, 300, 300, 400); canvas.drawArc(rect1, -180, 180, true, paint); paint.setStyle(Paint.Style.STROKE); RectF rect2 = new RectF(350, 300, 450, 400); canvas.drawArc(rect2, -180, 180, false,paint); }
之所以第一个画出矩形是为了让大家知道,矩形就是扇形显示的区域,我们设置的是一个内切圆,矩形的中心就是圆心。通过上面的代码和效果图我们可以看到useCenter: 如果为True时,在绘制圆弧时将圆心包括在内,来绘制扇形,如果为false的话就是一个弧线。
下面我们来实现一个大家都见过的一个自己画的钟表
示例代码
package demo.liuyongxiang.com.demo.activities;import android.app.Activity;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.RectF;import android.os.Bundle;import android.view.View;/** * Created by ytx on 2016/11/10. */public class MyCanvas extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new CustomView1(this)); } class CustomView1 extends View { Paint paint; public CustomView1(Context context) { super(context); paint = new Paint(); //设置一个笔刷大小是3的黄色的画笔 paint.setColor(Color.RED); } //在这里我们将测试canvas提供的绘制图形方法 @Override protected void onDraw(Canvas canvas) { paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); //将要画的位置移动到屏幕中间 canvas.translate(canvas.getWidth()/2, canvas.getHeight()/2); //将位置移动画纸的坐标点:150,150 //以半径为150和180画圆 canvas.drawCircle(0, 0, 150, paint); canvas.drawCircle(0, 0, 180, paint); //使用path绘制路径文字 canvas.save(); //移动绘制文字的位置 canvas.translate(0, 0); Path path = new Path(); //绘制的时候要注意左上不能大于右下,否则不会显示 RectF rect = new RectF(-100,-100,100,100); path.addArc(rect, -220, 280); Paint citePaint = new Paint(paint); citePaint.setTextSize(28); //设置画笔的粗细 citePaint.setStrokeWidth(3); //float hOffset, float vOffset// 设置水平位置 vOffset 设置垂直位置 // 如果hOffset为0 说明开始位置在path.addArc设置的startAngle开始角度 // 如果vOffset 为0说明经过的位置是在与RectF的顶部相切处 canvas.drawTextOnPath("http://blog.csdn.net/u014452224", path, 14, 0, citePaint); //为了方便一些转换操作,Canvas 还提供了保存和回滚属性的方法(save和restore), // 比如你可以先保存目前画纸的位置(save), // 然后旋转90度,向下移动100像素后画一些图形,画完后调用restore方法返回到刚才保存的位置 canvas.restore(); Paint smallPaint = new Paint(paint); //非数字刻度画笔对象 smallPaint.setStrokeWidth(2); smallPaint.setColor(Color.GRAY); float y=150; int count = 60; //总刻度数 Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setStrokeWidth(6); paint.setColor(Color.RED); paint.setTextSize(24); paint.setStrokeWidth(3); for(int i=0 ; i <count ; i++){ if(i%5 == 0){ //绘制数字刻度 canvas.drawText(i == 0 ? "12" : String.valueOf(i / 5),((i / 5)>9||i==0)?-15f:-6f , -y-5f, paint); }else{ //绘制非数字的刻度 canvas.drawLine(0f, y, 0f, y +15f, smallPaint); } canvas.rotate(360/count,0f,0f); //旋转画纸 } //绘制秒针 paint.setColor(Color.RED); paint.setStrokeWidth(4); //画固定的圆圈 canvas.drawCircle(0, 0, 7, paint); //画内部固定的点 paint.setStyle(Paint.Style.FILL); //float cx, float cy, float radius, Paint paint // cx中心点x坐标 cy中心点y坐标 canvas.drawCircle(0, 0, 5, paint); //float startX, float startY, float stopX, float stopY, Paint paint canvas.drawLine(0, 30, 0, -145, paint); } }}
对上面用到的canvas.save()和canvas.restore()来说明一下。它俩是两个相互匹配出现的,作用是用来保存画布的状态和取出保存的状态的。 当我们对画布进行旋转,缩放,平移等操作的时候其实我们是想对我们指定的元素进行操作,比如图片,一个矩形等,但是当你用canvas的方法来进行这些操作的时候,其实是对整个画布进行了操作,那么操作以后之前在画布上的元素都会受到影响,所以我们在对画布进行旋转,缩放,平移操作之前调用canvas.save()来保存画布当前的状态,当操作之后取出之前保存过的状态,这样就不会对其他的元素进行影响
我们来看看效果图就会知道怎么回事了
示例代码为
@Override protected void onDraw(Canvas canvas) { paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); canvas.translate(100, 100); canvas.drawCircle(0, 0, 50, paint); canvas.restore(); Path path=new Path(); path.moveTo(100,100); path.lineTo(100,200); path.lineTo(200,200); path.lineTo(200,100); path.close(); canvas.drawPath(path,paint); canvas.translate(100, 300); canvas.drawCircle(0, 0, 50, paint); Path path1=new Path(); path1.moveTo(100,100); path1.lineTo(100,200); path1.lineTo(200,200); path1.lineTo(200,100); path1.close(); canvas.drawPath(path1,paint); }
下面的效果图是在画布移动之前没有使用canvas.save()保存状态和使用
canvas不只是显示自己画的,也可以显示我们的资源图片,canvas里面有一个drawBitmap方法,我们可以通过canvas.drawBitmap在我们设置的位置展示图片
示例代码
Bitmap bitmap=null; bitmap=((BitmapDrawable)getResources().getDrawable(R.drawable.ubuntu)).getBitmap();canvas.drawBitmap(bitmap, 0, 0, null); bitmap=((BitmapDrawable)getResources().getDrawable(R.drawable.timer)).getBitmap();canvas.drawBitmap(bitmap, 50, 50, null);
如何让时钟转动起来很简单,就是在原来的时钟基础上面再重新画出时分秒针。然后设置一个定时器就可以了。
实现代码如下:
package demo.liuyongxiang.com.demo.activities;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.RectF;import android.graphics.drawable.BitmapDrawable;import android.os.Bundle;import android.os.Handler;import android.view.View;import java.util.Calendar;import demo.liuyongxiang.com.demo.R;/** * Created by ytx on 2016/11/10. */public class MyCanvas extends Activity { private Paint mPaint; private float mCenterX; private float mHourLength; private float mMinuteLength; private float mSecondLength; private Handler handler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new CustomView1(MyCanvas.this)); } class CustomView1 extends View implements Runnable{ Paint paint; public CustomView1(Context context) { super(context); paint = new Paint(); //设置一个笔刷大小是3的黄色的画笔 paint.setColor(Color.RED); handler.postDelayed(this, 1000); } //在这里我们将测试canvas提供的绘制图形方法 @Override protected void onDraw(Canvas canvas) { paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); //将要画的位置移动到屏幕中间 canvas.translate(canvas.getWidth()/2, canvas.getHeight()/2); //将位置移动画纸的坐标点:150,150 //以半径为150和180画圆 canvas.drawCircle(0, 0, 150, paint); canvas.drawCircle(0, 0, 180, paint); //使用path绘制路径文字 canvas.save(); //移动绘制文字的位置 canvas.translate(0, 0); Path path = new Path(); //绘制的时候要注意左上不能大于右下,否则不会显示 RectF rect = new RectF(-100,-100,100,100); path.addArc(rect, -220, 280); Paint citePaint = new Paint(paint); citePaint.setTextSize(28); //设置画笔的粗细 citePaint.setStrokeWidth(3); //float hOffset, float vOffset// 设置水平位置 vOffset 设置垂直位置 // 如果hOffset为0 说明开始位置在path.addArc设置的startAngle开始角度 // 如果vOffset 为0说明经过的位置是在与RectF的顶部相切处 canvas.drawTextOnPath("http://blog.csdn.net/u014452224", path, 14, 0, citePaint); //为了方便一些转换操作,Canvas 还提供了保存和回滚属性的方法(save和restore), // 比如你可以先保存目前画纸的位置(save), // 然后旋转90度,向下移动100像素后画一些图形,画完后调用restore方法返回到刚才保存的位置 canvas.restore(); Paint smallPaint = new Paint(paint); //非数字刻度画笔对象 smallPaint.setStrokeWidth(2); smallPaint.setColor(Color.GRAY); float y=150; int count = 60; //总刻度数 Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setStrokeWidth(6); paint.setColor(Color.RED); paint.setTextSize(24); paint.setStrokeWidth(3); for(int i=0 ; i <count ; i++){ if(i%5 == 0){ //绘制数字刻度 canvas.drawText(i == 0 ? "12" : String.valueOf(i / 5),((i / 5)>9||i==0)?-15f:-6f , -y-5f, paint); }else{ //绘制非数字的刻度 canvas.drawLine(0f, y, 0f, y +15f, smallPaint); } canvas.rotate(360/count,0f,0f); //旋转画纸 } Calendar calendar = Calendar.getInstance(); int currentMinute = calendar.get(Calendar.MINUTE); int currentHour = calendar.get(Calendar.HOUR); int currentSecond = calendar.get(Calendar.SECOND); // 计算分针和时间的角度 double secondRadian = Math.toRadians((360 - ((currentSecond * 6) - 90)) % 360); double minuteRadian = Math.toRadians((360 - ((currentMinute * 6) - 90)) % 360); double hourRadian = Math.toRadians((360 - ((currentHour * 30) - 90))% 360 - (30 * currentMinute / 60)); // 设置实针为6个象素粗 paint.setStrokeWidth(6); // 在表盘上画时针 mCenterX = 0; mHourLength = 100; canvas.drawLine(mCenterX, mCenterX, (int) (mCenterX + mHourLength * Math.cos(hourRadian)), (int) (mCenterX - mHourLength * Math.sin(hourRadian)), paint); // 设置分针为4个象素粗 paint.setStrokeWidth(4); mMinuteLength = 120; // 在表盘上画分针 canvas.drawLine(mCenterX, mCenterX, (int) (mCenterX + mMinuteLength* Math.cos(minuteRadian)), (int) (mCenterX - mMinuteLength* Math.sin(minuteRadian)), paint); // 设置分针为2个象素粗 paint.setStrokeWidth(2); // 在表盘上画秒针 mSecondLength = 145; int centerY = 30; canvas.drawLine((int) (mCenterX - centerY* Math.cos(secondRadian)),(int) (mCenterX + centerY* Math.sin(secondRadian)), (int) (mCenterX + mSecondLength* Math.cos(secondRadian)), (int) (mCenterX - mSecondLength* Math.sin(secondRadian)), paint); paint.setStyle(Paint.Style.FILL); canvas.drawCircle(0, 0, 5, paint); } @Override public void run() { // 重新绘制View this.invalidate(); // 重新设置定时器,在60秒后调用run方法 handler.postDelayed(this, 1000); } }}
通过效果图和代码我们可以知道,我们设置的坐标点其实就是我们所要展示的图片的左上角的顶点。
如果你觉得这篇博客对你有帮助请给予好评,如有疑问请留言。
- Android Canvas、Paint、Path、drawBitmap
- Android Canvas Path Paint
- android: Canvas,Paint,Path
- android canvas void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)
- canvas.drawBitmap(bitmap, src, dst, paint)
- Android Path, Region, Paint, Canvas API篇
- Canvas、path、paint讲解
- Canvas、Paint、Path
- android Canvas中的clipRect、drawBitmap
- android Canvas中的clipRect、drawBitmap
- android Canvas中的clipRect、drawBitmap
- android canvas.drawBitmap的理解
- android Canvas中的clipRect、drawBitmap
- android canvas drawBitmap方法详解
- android Canvas中的clipRect、drawBitmap
- canvas.drawBitmap(bitmap, src, dst, paint) 方法,个人理解,
- Canvas的drawBitmap以及Paint的PorterDuffXfermode使用心得
- 【Android】 Canvas、Path 和 Paint 实例 (游戏开发必备)
- Logistic回归
- 监控安防平台-国标GB28181协议
- 【SQL Server 2008】评估期已过的解决方法
- FileChannel
- LeetCode No.447 Number of Boomerangs
- Android Canvas、Paint、Path、drawBitmap
- ---JavaWeb文件下载
- 转自BYVoid大神----编码的经验
- 文件锁
- 数据结构实验之图论六:村村通公路
- 内存映射文件
- 期刊/会议/学报
- Socket通道
- 一种相对完善的聊天机器人框架