利用SurfaceView显示正弦曲线,仿造示波器
众所周知,view是通过刷新来重绘视图的,Android系统通过发出VSYNC信号来进行屏幕重绘,刷新的时间间隔为16ms,如果在16ms内view完成你所需要的所有操作,那么用户在视觉上就不会产生卡顿的感觉;而如果执行的操作逻辑太多,特别是需要频繁刷新的界面,就会不断阻塞主线程,从而导致画面卡顿。
因此Android提供了surfaceView。
1.View主要适用于主动更新的情况,surfaceView主要适用于被动更新,例如频繁的刷新。
2.View在主线程 中对View进行刷新,surfaceView通常会用一个子线程来进行页面的刷新。
3.View在绘图时没有双缓冲机制,而surfaceView在底层就已经实现了双缓冲机制。
因此如果自定义view需要频繁刷新或者刷新时候的数据处理量比较大,那么就可以考虑使用surfaceView来代替View
使用SurfaceeView有一套模板,以下用一个例子说明:用surfaceView做出示波器的效果,画出正弦波。
package com.example.tangzh.MyView; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.util.AttributeSet; import android.view.SurfaceHolder; import android.view.SurfaceView; import com.example.tangzh.mylearn.R; /** * Created by TangZH on 2017/4/30. */ public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable //继承并实现两个接口 { private SurfaceHolder mHolder; //用于绘图的Canvas private Canvas mCanvas; //子线程标志位 private boolean mIsDrawing; //画笔 private Paint mPaint; private Path mPath; //x坐标 private int x=0; //y坐标 private int y=400; public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(); } public MySurfaceView(Context context) { super(context); initView(); } public MySurfaceView(Context context, AttributeSet attrs) { super(context, attrs); initView(); } private void initView() { mHolder=getHolder(); mHolder.addCallback(this); setFocusable(true); setFocusableInTouchMode(true); this.setKeepScreenOn(true); } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { mIsDrawing=true; mPath=new Path(); mPath.moveTo(0,400); mPaint=new Paint(); mPaint.setColor(getResources().getColor(R.color.colorTheme)); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); new Thread(this).start(); } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { mIsDrawing=false; } @Override public void run() { while (mIsDrawing) { draw(); x+=5; y=(int)(100* Math.sin(x*2*Math.PI/180)+400); mPath.lineTo(x,y); } } private void draw() { try { mCanvas=mHolder.lockCanvas(); //SurfaceView背景 mCanvas.drawColor(Color.WHITE); mCanvas.drawPath(mPath,mPaint); }catch (Exception e) { e.printStackTrace(); }finally { if(mCanvas!=null) mHolder.unlockCanvasAndPost(mCanvas); //对画布内容进行提交 } } }
要注意,通过SurfaceView对象的lockCanvas()方法,就可以获取当前的Canvas绘图对象,这个对象跟上次的Canvas对象是同一个,因此之前的绘图操作都会被保留,如果需要擦出,则可以在绘制前,通过drawColor()方法来进行清屏操作。