1、在绘制正弦曲线之前,先简单讲解一下SurfaceView的基本用法:
我们在使用SurfaceView的时候,主要用到三个类,SurfaceView, SurfaceHolder, SurfaceHolder.Callback。SurfaceView是视图控件,其包含了一块叫做Surface的内存区域,我们通过SurfaceHolder提供的API方法操作这块内存区域实现绘图,SurfaceHolder.Callback是在Surface创建,销毁,状态改变时回调。
2、下面讲解绘制正弦曲线,通过绘制正弦曲线,讲解SurfaceView的用法
1)、在XML布局文件中引用SurfaceView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/action_container" />
<LinearLayout
android:id="@+id/action_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentBottom="true" >
<Button
android:id="@+id/btnPlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Play" />
</LinearLayout>
</RelativeLayout>
ps:SurfaceView的使用和其他空间并无特殊之处,直接在XML中引用便可
public class MainActivity extends Activity implements SurfaceHolder.Callback{
public static final String TAG = "camera";
//x方向的单位长度,即20像素代表一个单位长度
private static final double UNIT_X = 20;
//y方向的单位长度,即20像素代表一个单位长度
private static final double UNIT_Y = 50;
private int centerX, centerY;
private SurfaceView surfaceView;
//该类提供了操作SurfaceView的API
private SurfaceHolder holder;
//计时器,用于绘制正弦曲线。SurfaceView与普通View的区别就是SurfaceView可以在子线程中更新UI,这样在UI更新频繁的场景下(比如游戏中精灵的移动)可以避免阻塞主线程
private Timer timer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
//通过SurfaceView.getHolder()方法获得SurfaceHolder
holder = surfaceView.getHolder();
//设置SurfaceView的回调
holder.addCallback(this);
paint = new Paint();
paint.setColor(Color.WHITE);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
//数学坐标到像素点的转换
private int coordinate2Pix(double coordinate, double unit){
return (int)(coordinate * unit);
}
//像素点到数学坐标的转换
private double pix2Coordinate(int pix, double unit){
return pix / unit;
}
private Paint paint;
class MyTimerTask extends TimerTask{
private int px, py;
public MyTimerTask(){
}
@Override
public void run() {
/**
*基本绘制思路是,从x方向像素为0的点算起,计算出像素点的数学坐
*标,通过正弦函数sin(x)计算出y的数学坐标,再将数学坐标转换
*成像素点,绘制计算出来的像素点,然后x++,重复上述过程。。。
*
*/
double cx = pix2Coordinate(px, UNIT_X);
double cy = Math.sin(cx);
py = coordinate2Pix(cy, UNIT_Y) + surfaceView.getHeight() / 2;
Rect dirty = new Rect(px - 1, py - 1, px + 1, py+1);
Canvas canvas = holder.lockCanvas(dirty);
canvas.drawLine(0, centerY, surfaceView.getWidth(), centerY, paint);
canvas.drawCircle(px, py, 2, paint);
holder.unlockCanvasAndPost(canvas);
px++;
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
//Surface创建成功之后回调
Log.i(TAG, "surfaceCreated");
if(timer == null){
timer = new Timer();
}
centerX = 0;
centerY = surfaceView.getHeight() / 2;
timer.schedule(new MyTimerTask(), 0, 100);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i(TAG, "surfaceChanged");
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//SurfaceView销毁后回调
Log.i(TAG, "surfaceDestroyed");
if(timer != null){
timer.cancel();
timer = null;
}
}
}