引用:http://www.oschina.net/code/snippet_54100_1423
SurfaceView 由于可以直接从内存或者DMA等硬件接口取得图像数据,因此是个非常重要的绘图容器,网上介绍 SurfaceView的用法有很多,写法也层出不同,例如继承SurfaceView类,或者继承SurfaceHolder.Callback类等,这个可以根据功能实际需要自己选择,我这里就直接在普通的用户界面调用SurfaceHolder的lockCanvas和 unlockCanvasAndPost。
对比下面的第二、三两图,三图用.lockCanvas(null),而二图用.lockCanvas(new Rect(oldX, 0, oldX + length, getWindowManager().getDefaultDisplay().getHeight())),对比一下两个效果,由于二图是按指定Rect绘画,所以效率会比三图的全控件绘画高些,并且在清屏之后 (canvas.drawColor(Color.BLACK))不会留有上次绘画的残留。
对比下面的第二、三两图,三图用.lockCanvas(null),而二图用.lockCanvas(new Rect(oldX, 0, oldX + length, getWindowManager().getDefaultDisplay().getHeight())),对比一下两个效果,由于二图是按指定Rect绘画,所以效率会比三图的全控件绘画高些,并且在清屏之后 (canvas.drawColor(Color.BLACK))不会留有上次绘画的残留。
代码片段(5)
[图片] 程序运行的截图
[图片] 1.gif
[图片] 2.gif
[代码] main.xml
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
02 |
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" |
03 |
android:layout_width = "fill_parent" android:layout_height = "fill_parent" |
04 |
android:orientation = "vertical" > |
05 |
06 |
< LinearLayout android:id = "@+id/LinearLayout01" |
07 |
android:layout_width = "wrap_content" android:layout_height = "wrap_content" > |
08 |
< Button android:id = "@+id/Button01" android:layout_width = "wrap_content" |
09 |
android:layout_height = "wrap_content" android:text = "简单绘画" ></ Button > |
10 |
< Button android:id = "@+id/Button02" android:layout_width = "wrap_content" |
11 |
android:layout_height = "wrap_content" android:text = "定时器绘画" ></ Button > |
12 |
</ LinearLayout > |
13 |
< SurfaceView android:id = "@+id/SurfaceView01" |
14 |
android:layout_width = "fill_parent" android:layout_height = "fill_parent" ></ SurfaceView > |
15 |
</ LinearLayout > |
[代码] TestSurfaceView.java
001 |
package com.testSurfaceView; |
002 |
003 |
import java.util.Timer; |
004 |
import java.util.TimerTask; |
005 |
006 |
import android.app.Activity; |
007 |
import android.graphics.Canvas; |
008 |
import android.graphics.Color; |
009 |
import android.graphics.Paint; |
010 |
import android.graphics.Rect; |
011 |
import android.os.Bundle; |
012 |
import android.util.Log; |
013 |
import android.view.SurfaceHolder; |
014 |
import android.view.SurfaceView; |
015 |
import android.view.View; |
016 |
import android.widget.Button; |
017 |
018 |
public class TestSurfaceView extends Activity { |
019 |
/** Called when the activity is first created. */ |
020 |
Button btnSimpleDraw, btnTimerDraw; |
021 |
SurfaceView sfv; |
022 |
SurfaceHolder sfh; |
023 |
024 |
private Timer mTimer; |
025 |
private MyTimerTask mTimerTask; |
026 |
int Y_axis[], //保存正弦波的Y轴上的点 |
027 |
centerY, //中心线 |
028 |
oldX,oldY, //上一个XY点 |
029 |
currentX; //当前绘制到的X轴上的点 |
030 |
031 |
@Override |
032 |
public void onCreate(Bundle savedInstanceState) { |
033 |
super .onCreate(savedInstanceState); |
034 |
setContentView(R.layout.main); |
035 |
036 |
btnSimpleDraw = (Button) this .findViewById(R.id.Button01); |
037 |
btnTimerDraw = (Button) this .findViewById(R.id.Button02); |
038 |
btnSimpleDraw.setOnClickListener( new ClickEvent()); |
039 |
btnTimerDraw.setOnClickListener( new ClickEvent()); |
040 |
sfv = (SurfaceView) this .findViewById(R.id.SurfaceView01); |
041 |
sfh = sfv.getHolder(); |
042 |
043 |
//动态绘制正弦波的定时器 |
044 |
mTimer = new Timer(); |
045 |
mTimerTask = new MyTimerTask(); |
046 |
047 |
// 初始化y轴数据 |
048 |
centerY = (getWindowManager().getDefaultDisplay().getHeight() - sfv |
049 |
.getTop()) / 2 ; |
050 |
Y_axis = new int [getWindowManager().getDefaultDisplay().getWidth()]; |
051 |
for ( int i = 1 ; i < Y_axis.length; i++) { // 计算正弦波 |
052 |
Y_axis[i - 1 ] = centerY |
053 |
- ( int ) ( 100 * Math.sin(i * 2 * Math.PI / 180 )); |
054 |
} |
055 |
} |
056 |
057 |
class ClickEvent implements View.OnClickListener { |
058 |
059 |
@Override |
060 |
public void onClick(View v) { |
061 |
062 |
if (v == btnSimpleDraw) { |
063 |
SimpleDraw(Y_axis.length- 1 ); //直接绘制正弦波 |
064 |
|
065 |
} else if (v == btnTimerDraw) { |
066 |
oldY = centerY; |
067 |
mTimer.schedule(mTimerTask, 0 , 5 ); //动态绘制正弦波 |
068 |
} |
069 |
070 |
} |
071 |
072 |
} |
073 |
074 |
class MyTimerTask extends TimerTask { |
075 |
@Override |
076 |
public void run() { |
077 |
078 |
SimpleDraw(currentX); |
079 |
currentX++; //往前进 |
080 |
if (currentX == Y_axis.length - 1 ) { //如果到了终点,则清屏重来 |
081 |
ClearDraw(); |
082 |
currentX = 0 ; |
083 |
oldY = centerY; |
084 |
} |
085 |
} |
086 |
087 |
} |
088 |
|
089 |
/** |
090 |
* 绘制指定区域 |
091 |
*/ |
092 |
void SimpleDraw( int length) { |
093 |
if (length == 0 ) |
094 |
oldX = 0 ; |
095 |
Canvas canvas = sfh.lockCanvas( new Rect(oldX, 0 , oldX + length, |
096 |
getWindowManager().getDefaultDisplay().getHeight())); // 关键:获取画布 |
097 |
Log.i( "Canvas:" , |
098 |
String.valueOf(oldX) + "," + String.valueOf(oldX + length)); |
099 |
100 |
Paint mPaint = new Paint(); |
101 |
mPaint.setColor(Color.GREEN); // 画笔为绿色 |
102 |
mPaint.setStrokeWidth( 2 ); // 设置画笔粗细 |
103 |
104 |
int y; |
105 |
for ( int i = oldX + 1 ; i < length; i++) { // 绘画正弦波 |
106 |
y = Y_axis[i - 1 ]; |
107 |
canvas.drawLine(oldX, oldY, i, y, mPaint); |
108 |
oldX = i; |
109 |
oldY = y; |
110 |
} |
111 |
sfh.unlockCanvasAndPost(canvas); // 解锁画布,提交画好的图像 |
112 |
} |
113 |
114 |
void ClearDraw() { |
115 |
Canvas canvas = sfh.lockCanvas( null ); |
116 |
canvas.drawColor(Color.BLACK); // 清除画布 |
117 |
sfh.unlockCanvasAndPost(canvas); |
118 |
119 |
} |
120 |
} |