Android 自定义View 开发 入门与实践6 SurfaceView

10.3 SurfaceView

public class SurfaceGesturePath extends SurfaceView {

    private Path mPath;
    private Paint mPaint;

    public SurfaceGesturePath(Context context) {
        this(context, null);
    }

    public SurfaceGesturePath(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SurfaceGesturePath(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(5);
        mPaint.setColor(Color.RED);

        mPath = new Path();


        //默认为黑色背景 修改为透明 
        this.setZOrderOnTop(true);
        this.getHolder().setFormat(PixelFormat.TRANSLUCENT);

    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            mPath.moveTo(x, y);
            return true;
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            mPath.lineTo(x, y);
        }
        drwacanvas();

        return super.onTouchEvent(event);
    }


    //由于机制不同 建议这么来绘制
    private void drwacanvas() {
        new Thread(){
            @Override
            public void run() {

                SurfaceHolder holder = getHolder();
                Canvas canvas = holder.lockCanvas();
                canvas.drawPath(mPath, mPaint);
                holder.unlockCanvasAndPost(canvas);

            }
        }.start();

    }


}

Android 自定义View 开发 入门与实践6 SurfaceView_第1张图片

 


可以通过以上代码大致 了解 了SurfaceView 虽然派生自View ,但是他自带画布,具有双缓冲技术,所以绘制的时候使用缓冲画布.

注意我使用drawColor 和  xml 设置背景色 都无效,默认是黑色背景,可以设置成白色透明,其他颜色如何设置暂时不知晓


为什么要加锁

特性:SurfaceView 中的缓冲画布 在线程中是可以更新的.

如果同时存在诸多线程去更新,那么绘制的就会很乱,所以需要加锁.

...................而加锁就会造成一个问题,当画布被占用或者缓存canvas没有被创建的时候,surfaceHolder.lockCanvas函数会返回null,这样一来,如果存在多个线程同时操作缓冲画布的情况,则不仅需要对画布做判空处理,也需要在画布为空的时候添加重试策略,


仿墨迹天气背景

/**
 * -----------------------------
 * Created by zqf on 2020/8/3.
 * 仿墨迹天气背景
 * ---------------------------
 */
public class MojiTianqiView extends SurfaceView {

    private SurfaceHolder surfaceHolder;
    /**
     * 线程标识
     */
    private boolean flag = false;
    private Bitmap bitmap_bg;
    private Canvas mCanvas;

    /**
     * 开始绘制的图片的X坐标
     */
    private int mBitposX;
    private int mSurfaceWidth;

    //背景 移动状态
    private enum State {
        LEFT, RIGHT
    }

    //默认为向左
    private State state = State.LEFT;

    //背景画布移动步伐
    private final int BITMAP_STEP = 1;


    public MojiTianqiView(Context context) {
        this(context, null);
    }

    public MojiTianqiView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MojiTianqiView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        surfaceHolder = getHolder();
        surfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                flag = true;
                startAnimation();
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                flag = false;
            }
        });

    }


    private void startAnimation() {
        mSurfaceWidth = getWidth();
        int mSurfaceHeight = getHeight();
        int mWidth = mSurfaceWidth * 3 / 2;
        /**
         * 将图片宽度缩放带屏幕的3/2倍,高度充满屏幕
         */
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
        bitmap_bg = Bitmap.createScaledBitmap(bitmap, mWidth, mSurfaceHeight, true);

        //开始绘图
        Thread thread = new Thread() {
            @Override
            public void run() {
                while (flag) {
                    mCanvas = surfaceHolder.lockCanvas();
                    DrawView();
                    surfaceHolder.unlockCanvasAndPost(mCanvas);
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread.start();

    }

    /**
     * 进行绘制
     */
    private void DrawView() {
        //绘制背景
        mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        mCanvas.drawBitmap(bitmap_bg, mBitposX, 0, null);

        /** 图片滚动效果 **/
        switch (state) {
            case LEFT:
                mBitposX -= BITMAP_STEP;
                break;
            case RIGHT:
                mBitposX += BITMAP_STEP;
                break;
            default:
                break;
        }


        if (mBitposX <= -mSurfaceWidth / 2) {
            state = State.RIGHT;
        }
        if (mBitposX >= 0) {
            state = State.LEFT;
        }

    }


}

数字闪烁类似

Android 自定义View 开发 入门与实践6 SurfaceView_第2张图片

public class NumberView extends SurfaceView {

    private Paint mPaint;
    private int height;

    public NumberView(Context context) {
        this(context, null);
    }

    public NumberView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public NumberView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setTextSize(ConvertUtils.sp2px(30));


        //默认为黑色背景 修改为透明
        this.setZOrderOnTop(true);
        this.getHolder().setFormat(PixelFormat.TRANSLUCENT);

        height = ConvertUtils.dp2px(100);

        getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                drawText(holder);
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {

            }
        });
    }


    /**
     * 开始绘制
     */
    private void drawText(SurfaceHolder holder) {


        Thread thread = new Thread() {
            @Override
            public void run() {


                while (true) {

                    for (int i = 0; i < 10; i++) {

                        Canvas mCanvas = holder.lockCanvas();
                        //俩种效果
//                        mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

                        if (mCanvas != null) {
                            mCanvas.drawText(i + "", i * 30, height / 2, mPaint);
                        }
                        holder.unlockCanvasAndPost(mCanvas);

                        try {
                            Thread.sleep(800);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                }

            }
        };
        thread.start();


    }

}

一次性绘制所有数字


        Thread thread = new Thread() {
            @Override
            public void run() {

                Canvas mCanvas = holder.lockCanvas();
                for (int i = 0; i < 10; i++) {

                    if (mCanvas != null) {
                        mCanvas.drawText(i + "", i * 60, height / 2, mPaint);
                    }
                }
                holder.unlockCanvasAndPost(mCanvas);

            }
        };
        thread.start();

 Android 自定义View 开发 入门与实践6 SurfaceView_第3张图片

public class NumberView extends SurfaceView {

    private Paint mPaint;
    private int height;

    private boolean flag = true;

    public NumberView(Context context) {
        this(context, null);
    }

    public NumberView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public NumberView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setTextSize(ConvertUtils.sp2px(30));


        //默认为黑色背景 修改为透明
        this.setZOrderOnTop(true);
        this.getHolder().setFormat(PixelFormat.TRANSLUCENT);

        height = ConvertUtils.dp2px(100);

        getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                drawText(holder);
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {

            }
        });
    }


    private List mInts = new ArrayList<>();

    /**
     * 开始绘制
     */
    private void drawText(SurfaceHolder holder) {

        Thread thread = new Thread() {
            @Override
            public void run() {

                for (int i = 0; i < 10; i++) {
                    Canvas mCanvas = holder.lockCanvas();
                    mInts.add(i);
                    if (mCanvas != null) {

                        for (int j = 0; j < mInts.size(); j++) {
                            mCanvas.drawText(mInts.get(j) + "", j * 60, height / 2, mPaint);
                        }

                        try {
                            Thread.sleep(800);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        holder.unlockCanvasAndPost(mCanvas);

                    }
                }

            }
        };
        thread.start();


    }

}

带背景

public class NumberView extends SurfaceView {

    private Paint mPaint;
    private int height;

    private boolean flag = true;

    public NumberView(Context context) {
        this(context, null);
    }

    public NumberView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public NumberView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);


        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setTextSize(ConvertUtils.sp2px(30));


        //默认为黑色背景 修改为透明
        this.setZOrderOnTop(true);
        this.getHolder().setFormat(PixelFormat.TRANSLUCENT);

        height = ConvertUtils.dp2px(100);

        getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                drawText(holder);
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {

            }
        });
    }


    private List mInts = new ArrayList<>();

    /**
     * 开始绘制
     */
    private void drawText(SurfaceHolder holder) {

        Thread thread = new Thread() {
            @Override
            public void run() {

                //先进行清屏操作
                while (true) {
                    Rect dirtyRect = new Rect(0, 0, 1, 1);
                    Canvas canvas = holder.lockCanvas(dirtyRect);
                    Rect canvasRect = canvas.getClipBounds();
                    if (getWidth() == canvasRect.width() && getHeight() == canvasRect.height()) {
                        canvas.drawColor(Color.WHITE);
                        holder.unlockCanvasAndPost(canvas);
                    } else {
                        holder.unlockCanvasAndPost(canvas);
                        break;
                    }

                }

                //画图
                for (int i = 0; i < 10; i++) {

                    //间隔
                    int itemWidth = 80;

                    //行高
                    int itemHeight = height;

                    Rect rect = new Rect(i * itemWidth, 0, (i + 1) * itemWidth - 10, itemHeight);
                    Canvas canvas = holder.lockCanvas(rect);
                    if (canvas != null) {
                        canvas.drawColor(Color.GREEN);
                        canvas.drawText(i+"",i*itemWidth+10, itemHeight/2, mPaint);
                    }
                    holder.unlockCanvasAndPost(canvas);

                    try {
                        Thread.sleep(800);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }


                }

            }
        };

        thread.start();

    }


}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Android 自定义View 开发 入门与实践6 SurfaceView)