SurfaceView之绘制sin曲线

package com.loaderman.customviewdemo;


import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * SurfaceView类的成员函数draw和dispatchDraw的参数canvas所描述的都是建立在宿主窗口的绘图表面上的画布,
 * 因此,在这块画布上绘制的任何UI都是出现在宿主窗口的绘图表面上的。
 * <p/>
 * 本来SurfaceView类的成员函数draw是用来将自己的UI绘制在宿主窗口的绘图表面上的,
 * 但是这里我们可以看到,如果当前正在处理的SurfaceView不是用作宿主窗口面板的时候,
 * 即其成员变量mWindowType的值不等于WindowManager.LayoutParams.TYPE_APPLICATION_PANEL的时候,
 * SurfaceView类的成员函数draw只是简单地将它所占据的区域绘制为黑色。
 */
public class SinSurfaceView extends SurfaceView implements Runnable {
    private SurfaceHolder mSurfaceHolder;
    /**
     * 用于保存正弦路径坐标
     */
    private Path mPath;
    private Paint mPaint;

    public SinSurfaceView(Context context) {
        super(context);
        init();
    }

    public SinSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public SinSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(5);
        mPaint.setColor(Color.GREEN);
        //连接处更加平滑
        mPaint.setStrokeJoin(Paint.Join.ROUND);

        mPath = new Path();

        /**通过holder去申请绘图表面的画布,surfaceview其实draw()或dispathDraw()都只是一块默认的黑色区域,并不是用作宿主
         * 真正要做的事情由开发者自行绘制,绘制之前就是通过holder获取一块内存区域的画布,
         * 然后可在UI线程或工作线程在这个画布上进行绘制所需要的视图,最后还是通过holder提交这个画布就可以显示
         * */
        mSurfaceHolder = getHolder();
        //回调
        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
            /***
             * surfaceview的绘图表面(就是activity宿主创建一个透明的表面用于surfaceView绘制)被创建时执行
             * 在updateWindow()创建宿主(activity的窗口)的绘图表面时会回调,虽然surfaceView是独立于一个线程但还是离不开宿主窗口,
             * 最后还是要粘贴到window中
             *
             * surfaceCreated方法,是当SurfaceView被显示时会调用的方法,所以你需要再这边开启绘制的线 程
             *
             * @param holder
             */
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                new Thread(SinSurfaceView.this).start();

                //Animator是在主线程中执行的
                ValueAnimator animator = ValueAnimator.ofFloat(0,100.0f);
                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float value = (Float) animation.getAnimatedValue();
                        if (Looper.myLooper() != Looper.getMainLooper()  ){
                            Log.d("loaderman","不在主线程哦");
                        }else {
                            Log.d("loaderman","啊哈,在主线程哦");
                        }
                    }
                });
                animator.start();

            }

            /**
             * 创建、更新会认为发生变化也会回调这个方法
             * @param holder
             * @param format
             * @param width
             * @param height
             */
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }

            /***
             *surfaceDestroyed方法是当SurfaceView被隐藏会销毁时调用的方法,在这里你可以关闭绘制的线程
             * @param holder
             */
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                isDrawing = false;
            }
        });
    }

    /***
     * 是否在绘制:用于关闭子线程:true则表示一直循环
     */
    private boolean isDrawing = true;
    private int drawX;
    private int drawY;

    /***
     * 注意这个是在子线程中绘制的
     */
    @Override
    public void run() {
        while (isDrawing) {
            drawX++;
            drawY = (int) (100 * Math.sin(drawX * 2 * Math.PI / 180) + 400);
            mPath.lineTo(drawX, drawY);
            draw(mPath);
        }

    }

    /***
     * 注意这个是在子线程中绘制的,surface支持子线程更新ui,所以
     */
    private void draw(Path path) {
        Canvas canvas = null;
        //给画布加锁,防止线程安全,防止该内存区域被其他线程公用
        canvas = mSurfaceHolder.lockCanvas();
        if (null != canvas) {
            //清屏操作或者设置背景
            canvas.drawColor(Color.WHITE);
            canvas.drawPath(mPath, mPaint);
            //提交显示视图并解锁,防止长期占用此内存
            mSurfaceHolder.unlockCanvasAndPost(canvas);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    }


}

效果:

原文地址:https://www.cnblogs.com/loaderman/p/10232294.html