Android实现简易示波器

用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);
    }

就这么简单,运行结果演示:
这里写图片描述

代码也不多,所以就全部贴出来,懒得打包了,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>
阅读更多

扫码向博主提问

LayneYao

一个技术人
  • 擅长领域:
  • Android开发
  • 偏物联网方向
去开通我的Chat快问
版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明作者和出处。 https://blog.csdn.net/Jsagacity/article/details/80373847
文章标签: SurfaceView
个人分类: Android
上一篇使用DrawerLayout和SlidingMenu分别实现侧滑菜单、以及AS使用SlidingMenu第三方库的步骤
下一篇service两种启动方式的区别
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭