实例源码下载地址 :http://download.csdn.net/detail/xiaocaoxiekun/7809389
Android中使用图形处理引擎,2D部分是android SDK内部自己提供。使用该引擎中的API我们可以实现常用的2D图像的绘制,以及一些自定义UI组件的构造,比如自己定义指针式时钟。
1. 常用绘图API简介:
Android 2D 图形处理引擎常用到的API主要位于android.graphics.drawable包下面,下面就对一些常用的API进行介绍:
Canvas 是图形编程中一个很常用的概念,无论实在静态页面HTML中还是在动态网页,直到现在的移动开发中都可以看见Canvas的身影。Canvas 常被称为画布,它是图形绘制的执行者,它统帅着所有的机型图形绘制的API,其提供了draw*方法来实现位图的设计。
drawRect(RectF rect, Paint paint) //绘制区域,参数一为RectF一个区域
drawPath(Path path, Paint paint) //绘制一个路径,参数一为Path路径对象
drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) //贴图,参数一就是我们常规的Bitmap对象,参数二是源区域(这里是bitmap),参数三是目标区域(应该在canvas的位置和大小),参数四是Paint画刷对象,因为用到了缩放和拉伸的可能,当原始Rect不等于目标Rect时性能将会有大幅损失。
drawLine(float startX, float startY, float stopX, float stopY, Paintpaint) //画线,参数一起始点的x轴位置,参数二起始点的y轴位置,参数三终点的x轴水平位置,参数四y轴垂直位置,最后一个参数为Paint 画刷对象。
drawPoint(float x, float y, Paint paint) //画点,参数一水平x轴,参数二垂直y轴,第三个参数为Paint对象。
drawText(String text, float x, floaty, Paint paint) //渲染文本,Canvas类除了上面的还可以描绘文字,参数一是String类型的文本,参数二x轴,参数三y轴,参数四是Paint对象。
drawOval(RectF oval, Paint paint)//画椭圆,参数一是扫描区域,参数二为paint对象
drawCircle(float cx, float cy, float radius,Paint paint)// 绘制圆,参数一是中心点的x轴,参数二是中心点的y轴,参数三是半径,参数四是paint对象;
drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//画弧,
参数一是RectF对象,一个矩形区域椭圆形的界限用于定义在形状、大小、电弧,参数二是起始角(度)在电弧的开始,
参数三扫描角(度)开始顺时针测量的,参数四是如果这是真的话,包括椭圆中心的电弧,并关闭它,如果它是假这将是一个弧线,参数五是Paint对象;
drawText(String text, float x, float y, Paint paint) //渲染文本
由Canvas提供的方法可以看出,在绘图过程中都离不开Paint对象,那么Paint究竟代表着什么呢?下面就来介绍一下Paint:
Paint 被称为画笔,刷子等。主要是制定如何将基本图形绘制到位图上,相当于是规则制作者, 用来规定画布上的字体样式, 画布背景,对齐方式等,Paint 常用的API如下:
Shader setShader(Shader shader) //设置阴影,Shader类是一个矩阵对象,如果为NULL将清除阴影
setARGB(int a, int r, int g, int b) // 设置 Paint对象颜色,参数一为alpha透明值
setAlpha(int a) // 设置alpha不透明度,范围为0~255
setColor(int color) // 设置颜色
setTextSize(float textSize) // 设置字体大小
setUnderlineText(booleanunderlineText) // 设置下划线
setTextAlign(Align.CENTER) // 设置文本的对齐方式
注:如果设置了画笔Paint的对齐属性,那么在进行文本渲染的时候,drawText(String text, float x, float y, Paint paint) 中设置的X坐标可能不是我们想要的结果:在设置了setTextAlign(Align.CENTER)的时候,X坐标实际上是Text文本中间点的坐标,而不是文本起始位置的坐标。
2. 怎么样绘制一个图形:
android为我们提供了绘制图形的工具,那我们究竟需要将这些图形绘制在哪些地方呢?当画图形时,典型情况下,你将使用以下两方法之一:
-
A.把你的图形或动画绘制到你的Layout中的一个View上.你的图形的绘制被系统的标准绘制过程所处理—你只需定义进人View的图形即可.
-
B.在一个Canvas中直接绘制图形.用此方法,你需亲自调用恰当的类的onDraw()方法(把它传给你的Canvas),或Canvas的draw...()方法们中的一个(比如drawPicture()).在这样做时,你也可以任意控制动画
在这里我们主要学习的是利用Canvas直接进行图形的绘制,对于动作和视频类游戏,需要经常对图形进行重绘时,采用这种方法,这种绘制方法,Android也为开发人员提供了最终可供选择的开发方案:
在UIActivity线程(UI主线程)中,自定义View组件(只需要集成View即可),然后调用invalidate()然后处理onDraw()回调,在onDraw()中调用canvas的draw...()方法来绘制自己想要的图形。
在异步线程中,通过管理SurfaceView 快速的向主线程的Canvas中传递绘画的动作。
下面我们通过实例来讲解2中绘制方法的用法,顺便熟悉一下绘图API的使用:
(1):通过自定义View组件,将图形绘制在主线程中,我们只需要实现View的onDraw方法即可:
public DrawView(Context mContext) {
super(mContext);
setBackgroundColor(Color.BLACK);
//绘制画笔
mPaint=new Paint();
mPaint.setColor(Color.WHITE); //设置画笔的颜色,即图形的边框(包含字体)
mPaint.setStrokeWidth(5); //设置画笔的大小,相当于图形的边框宽度
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setAntiAlias(true);//不抗锯齿
mPaint.setTextAlign(Align.CENTER);
mPaint.setTextSize(24);
}
@Override
protected void onDraw(Canvas mCanvas){
super.onDraw(mCanvas);
mCanvas.drawRect(10, 30, 150,200, mPaint);
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(2);
mCanvas.drawText("draw Text", 150, 150, mPaint);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLUE);
mPaint.setAntiAlias(true);//抗锯齿
mCanvas.drawRect(150, 40, 290,200, mPaint);
}
(2) 通过surfaceView ,在非主线程中绘制图形,可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。在游戏开发中多用到SurfaceView,游戏中的背景、人物、动画等等尽量在画布canvas中画出。
SurfaceView是View的子类,它内嵌了一个专门用于绘制的Surface。如果我们需要创建一个SurfaceView对象,我们需要按照一下步骤进行:
SurfaceView的使用首先继承SurfaceView,并实现SurfaceHolder.Callback接口,实现它的三个方法:surfaceCreated,surfaceChanged,surfaceDestroyed。
surfaceCreated(SurfaceHolder holder):surface创建的时候调用,一般在该方法中启动绘图的线程。
surfaceChanged(SurfaceHolder holder, int format, int width,int height):surface尺寸发生改变的时候调用,如横竖屏切换。
surfaceDestroyed(SurfaceHolder holder) :surface被销毁的时候调用,如退出游戏画面,一般在该方法中停止绘图线程。
还需要获得SurfaceHolder,并添加回调函数,这样这三个方法才会执行。
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder mSurfaceHolder;
private SurfaceThread mSurfaceThread;
public MySurfaceView(Context context) {
super(context);
mSurfaceHolder=this.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceThread=new SurfaceThread(mSurfaceHolder);
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
//在surface的大小发生改变时激发
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
//在创建时激发,一般在这里调用画图的线程
@Override
public void surfaceCreated(SurfaceHolder holder) {
mSurfaceThread.isrun=true;
mSurfaceThread.start();
}
//销毁时激发,一般在这里将画图的线程停止、释放
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mSurfaceThread.isrun=false;
}
//创建一个线程,对surface 进行业务处理
class SurfaceThread extends Thread{
private SurfaceHolder mHolder;
public boolean isrun;
public SurfaceThread(SurfaceHolder mHolder){
this.mHolder=mHolder;
isrun=true;
}
@Override
public void run(){
int count = 0;
while(isrun){
Canvas c = null;
try {
synchronized (mHolder){
c = mHolder.lockCanvas();//锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
c.drawColor(Color.BLACK);//设置画布背景颜色
Paint p = new Paint(); //创建画笔
p.setColor(Color.WHITE);
Rect r = new Rect(100, 50, 300, 250);
c.drawRect(r, p);
c.drawText("这是第"+(count++)+"秒", 100, 310, p);
}
}
catch (Exception e) {
e.printStackTrace();
}
finally{
if(c!= null){
mHolder.unlockCanvasAndPost(c); //结束锁定画图,并提交改变。
}
}
}
}
}
}