欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android实现简易示波器

程序员文章站 2022-03-30 13:47:43
...

用SurfaceView简易的实现一个示波器,这需求估计玩电子的比较需要吧。

这里学到一个接口蛮有意思的,简单的说一下。

holder.lockCanvas(null),就是锁住整张画布,绘画完成后也更新整张画布的内容到屏幕上,这个没有什么疑惑。而 lockCanvas(Rect dirty)就是锁住画布中的某个区域,绘画完成后也只更新这个区域的内容到屏幕。使用后一接口的初衷是只更新必要的画面内容以节省时间,提高程序运行的效率,适用于大动态画面的场景。

示波器的实现也非常简单,在显示曲线之前要布置黑色背景、白色网格和坐标轴:

private void drawBackGround(SurfaceHolder holder) {
        Canvas canvas = holder.lockCanvas();
        // 绘制黑色背景
        canvas.drawColor(Color.BLACK);
        Paint p = new Paint();
        p.setColor(Color.WHITE);
        p.setStrokeWidth(2);

        // 画网格8*8
        Paint mPaint = new Paint();
        mPaint.setColor(Color.GRAY);// 网格为黄色
        mPaint.setStrokeWidth(1);// 设置画笔粗细
        int oldY = 0;
        for (int i = 0; i <= 8; i++) {// 绘画横线
            canvas.drawLine(0, oldY, WIDTH, oldY, mPaint);
            oldY = oldY + WIDTH/8;
        }
        int oldX = 0;
        for (int i = 0; i <= 8; i++) {// 绘画纵线
            canvas.drawLine(oldX, 0, oldX, HEIGHT, mPaint);
            oldX = oldX + HEIGHT/8;
        }

        // 绘制坐标轴
        canvas.drawLine(X_OFFSET, centerY, WIDTH, centerY, p);
        canvas.drawLine(X_OFFSET, 40, X_OFFSET, HEIGHT, p);
        holder.unlockCanvasAndPost(canvas);
        holder.lockCanvas(new Rect(0, 0, 0, 0));
        holder.unlockCanvasAndPost(canvas);
    }

首先是正余弦线的画法:

    /**
     * 正余弦曲线函数
     */
    private void showSineCord(final View view){
        drawBackGround(holder);
        cx = X_OFFSET;
        if (task != null) {
            task.cancel();
        }
        task = new TimerTask() {

            @Override
            public void run() {
                // 根据是正玄还是余玄和X坐标确定Y坐标
                int cy = view.getId()==R.id.btnShowSin?
                        centerY- (int) (100 * Math.sin((cx - 5) * 2 * Math.PI/ 150))
                        :centerY- (int) (100 * Math.cos((cx - 5) * 2 * Math.PI/ 150));

                Canvas canvas = holder.lockCanvas(new Rect(cx, cy - 2,
                        cx + 2, cy + 2));
                // 根据X,Y坐标画点
                canvas.drawPoint(cx, cy, paint);
                cx++;
                // 超过指定宽度,线程取消,停止画曲线
                if (cx > WIDTH) {
                    task.cancel();
                    task = null;
                }
                // 提交修改
                holder.unlockCanvasAndPost(canvas);
            }
        };
        timer.schedule(task, 0, 30);
    }

最后是折线曲线的实现:

/**
     * 折线曲线
     */
    private void showBrokenLine(){

        drawBackGround(holder);
        cx = X_OFFSET;
        if (task != null) {
            task.cancel();
        }
        task = new TimerTask() {
            int startX = 0;
            int startY = 200;
            Random random = new Random();
            @Override
            public void run() {

                int cy = random.nextInt(100)+200;

                Canvas canvas = holder.lockCanvas(new Rect(cx-10, cy - 900,
                        cx + 10, cy + 900));

                // 根据X,Y坐标画线
                canvas.drawLine(startX, startY ,cx, cy, paint);

                //结束点作为下一次折线的起始点
                startX = cx;
                startY = cy;

                cx+=10;
                // 超过指定宽度,线程取消,停止画曲线
                if (cx > WIDTH) {
                    task.cancel();
                    task = null;
                }
                // 提交修改
                holder.unlockCanvasAndPost(canvas);
            }
        };
        timer.schedule(task, 0, 300);
    }

就这么简单,运行结果演示:
Android实现简易示波器

代码也不多,所以就全部贴出来,懒得打包了,MainActivity的代码:

public class MainActivity extends ActionBarActivity implements OnClickListener {
    private SurfaceHolder holder;
    private SurfaceView showSurfaceView;

    private Button btnShowSin;
    private Button btnShowCos;
    private Button btnShowBrokenLine;

    private Paint paint;

    private int HEIGHT;
    // 要绘制的曲线的水平宽度
    private int WIDTH;
    // 离屏幕左边界的起始距离
    private final int X_OFFSET = 5;
    // 初始化X坐标
    private int cx = X_OFFSET;
    // 实际的Y轴的位置
    private int centerY ;
    private Timer timer = new Timer();
    private TimerTask task = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 获得SurfaceView对象
        showSurfaceView = (SurfaceView) findViewById(R.id.showSurfaceView);
        btnShowSin = (Button) findViewById(R.id.btnShowSin);
        btnShowCos = (Button) findViewById(R.id.btnShowCos);
        btnShowBrokenLine = (Button) findViewById(R.id.btnShowBrokenLine);

        btnShowSin.setOnClickListener(this);
        btnShowCos.setOnClickListener(this);
        btnShowBrokenLine.setOnClickListener(this);

        InitData();

        // 初始化SurfaceHolder对象
        holder = showSurfaceView.getHolder();
        paint = new Paint();
        paint.setColor(Color.GREEN);
        paint.setStrokeWidth(3);
    }

    private void InitData() {
        Resources resources = this.getResources();
        DisplayMetrics dm = resources.getDisplayMetrics();
        //获取屏幕的宽度作为示波器的边长
        HEIGHT = dm.widthPixels;
        WIDTH = dm.widthPixels;
        //Y轴的中心就是高的一半
        centerY = HEIGHT / 2;

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
        case R.id.btnShowSin:
            showSineCord(view);
            break;
        case R.id.btnShowCos:
            showSineCord(view);
            break;
        case R.id.btnShowBrokenLine:
            showBrokenLine();
            break;
        }

    }

    /**
     * 折线曲线
     */
    private void showBrokenLine(){

        drawBackGround(holder);
        cx = X_OFFSET;
        if (task != null) {
            task.cancel();
        }
        task = new TimerTask() {
            int startX = 0;
            int startY = 200;
            Random random = new Random();
            @Override
            public void run() {

                int cy = random.nextInt(100)+200;

                Canvas canvas = holder.lockCanvas(new Rect(cx-10, cy - 900,
                        cx + 10, cy + 900));

                // 根据X,Y坐标画线
                canvas.drawLine(startX, startY ,cx, cy, paint);

                //结束点作为下一次折线的起始点
                startX = cx;
                startY = cy;

                cx+=10;
                // 超过指定宽度,线程取消,停止画曲线
                if (cx > WIDTH) {
                    task.cancel();
                    task = null;
                }
                // 提交修改
                holder.unlockCanvasAndPost(canvas);
            }
        };
        timer.schedule(task, 0, 300);
    }

    /**
     * 正余弦曲线函数
     */
    private void showSineCord(final View view){
        drawBackGround(holder);
        cx = X_OFFSET;
        if (task != null) {
            task.cancel();
        }
        task = new TimerTask() {

            @Override
            public void run() {
                // 根据是正玄还是余玄和X坐标确定Y坐标
                int cy = view.getId()==R.id.btnShowSin?
                        centerY- (int) (100 * Math.sin((cx - 5) * 2 * Math.PI/ 150))
                        :centerY- (int) (100 * Math.cos((cx - 5) * 2 * Math.PI/ 150));

                Canvas canvas = holder.lockCanvas(new Rect(cx, cy - 2,
                        cx + 2, cy + 2));
                // 根据X,Y坐标画点
                canvas.drawPoint(cx, cy, paint);
                cx++;
                // 超过指定宽度,线程取消,停止画曲线
                if (cx > WIDTH) {
                    task.cancel();
                    task = null;
                }
                // 提交修改
                holder.unlockCanvasAndPost(canvas);
            }
        };
        timer.schedule(task, 0, 30);
    }

    private void drawBackGround(SurfaceHolder holder) {
        Canvas canvas = holder.lockCanvas();
        // 绘制黑色背景
        canvas.drawColor(Color.BLACK);
        Paint p = new Paint();
        p.setColor(Color.WHITE);
        p.setStrokeWidth(2);

        // 画网格8*8
        Paint mPaint = new Paint();
        mPaint.setColor(Color.GRAY);// 网格为黄色
        mPaint.setStrokeWidth(1);// 设置画笔粗细
        int oldY = 0;
        for (int i = 0; i <= 8; i++) {// 绘画横线
            canvas.drawLine(0, oldY, WIDTH, oldY, mPaint);
            oldY = oldY + WIDTH/8;
        }
        int oldX = 0;
        for (int i = 0; i <= 8; i++) {// 绘画纵线
            canvas.drawLine(oldX, 0, oldX, HEIGHT, mPaint);
            oldX = oldX + HEIGHT/8;
        }

        // 绘制坐标轴
        canvas.drawLine(X_OFFSET, centerY, WIDTH, centerY, p);
        canvas.drawLine(X_OFFSET, 40, X_OFFSET, HEIGHT, p);
        holder.unlockCanvasAndPost(canvas);
        holder.lockCanvas(new Rect(0, 0, 0, 0));
        holder.unlockCanvasAndPost(canvas);
    }

}

其布局文件的代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/btnShowSin"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="click"
            android:text="正玄曲线" />

        <Button
            android:id="@+id/btnShowCos"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="click"
            android:text="余玄曲线" />

        <Button
            android:id="@+id/btnShowBrokenLine"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="click"
            android:text="折线曲线" />
    </LinearLayout>

    <SurfaceView
        android:id="@+id/showSurfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
相关标签: SurfaceView