您当前的位置: 首页 >  android
  • 0浏览

    0关注

    483博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Android之SurfaceView

高精度计算机视觉 发布时间:2018-07-19 09:43:25 ,浏览量:0

本来这个SurfaceView没什么好写的。仅仅是发现网络上很多SurfaceView的教程代码不全,入门者可能会感到困惑,因为不知道谁应该放在哪里。所以这里力求无论新手熟手,都能从源码中得到全部信息,权当是一个补充。

第一步

首先自己先建一个类,我这里叫MySurfaceView,完整的源码如下(参考了【1】,但修复了其中退出时会引发黑屏的一个小bug,另外多说一句,里面采用新建线程的方法不要学,线程能不建就尽量不要建;对于while循环,一般在有外来信息时加入判断条件,及时中止即可,不过这与本文主旨无关)。

package com.spacesoftwares.ssapplication;

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.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;


/**
 * Created by Administrator on 2018/7/19 0019.
 */

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
    // SurfaceHolder
    private SurfaceHolder mSurfaceHolder;
    // 画布
    private Canvas mCanvas;
    // 子线程标志位
    private boolean isDrawing;
    // 画笔
    Paint mPaint;
    // 路径
    Path mPath;
    private float mLastX, mLastY;//上次的坐标

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

    /**
     * 初始化
     */
    private void init() {
        //初始化 SurfaceHolder mSurfaceHolder
        mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);

        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setKeepScreenOn(true);
        //画笔
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        mPaint.setStrokeWidth(10f);
        mPaint.setColor(Color.parseColor("#FF4081"));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        //路径
        mPath = new Path();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {//创建
        isDrawing = true;
        Log.e("surfaceCreated","--"+isDrawing);
        //绘制线程
        new Thread(this).start();
    }


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

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {//销毁
        isDrawing = false;
        Log.e("surfaceDestroyed","--"+isDrawing);
    }

    @Override
    public void run() {
        while (isDrawing){
            drawing();
        }
    }

    /**
     * 绘制
     */
    private void drawing() {
        try {
            mCanvas = mSurfaceHolder.lockCanvas();
            if(null == mCanvas){
                return;
            }
            mCanvas.drawColor(Color.YELLOW);
            mCanvas.drawPath(mPath,mPaint);
        } finally {
            if (mCanvas != null) {
                mSurfaceHolder.unlockCanvasAndPost(mCanvas);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:

                mLastX = x;
                mLastY = y;
                mPath.moveTo(mLastX, mLastY);
                break;
            case MotionEvent.ACTION_MOVE:
                float dx = Math.abs(x - mLastX);
                float dy = Math.abs(y - mLastY);
                if (dx >= 3 || dy >= 3) {
                    mPath.quadTo(mLastX, mLastY, (mLastX + x) / 2, (mLastY + y) / 2);
                }
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }

    /**
     * 测量
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int wSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int wSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int hSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int hSpecSize = MeasureSpec.getSize(heightMeasureSpec);

        if (wSpecMode == MeasureSpec.AT_MOST && hSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(300, 300);
        } else if (wSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(300, hSpecSize);
        } else if (hSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(wSpecSize, 300);
        }
    }
}

其中drawing函数中 if(null == mCanvas){  return;  }这句是必须的,否则退出时程序可能会崩溃,因此此时从surfaceHolder中得到的canvas一定是空的。报错内容大概和这个差不多:

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawColor(int)' on a null object reference....bla bla bla...。

第二步 SurfaceViewActivity

SurfaceViewAcitivity源码如下

package com.spacesoftwares.ssapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.SurfaceView;

public class SurfaceViewActivity extends AppCompatActivity {

    private MySurfaceView surface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_surface_view);
        surface = findViewById(R.id.sv_main);
    }
}

对应的layout/activity_surface_view.xml如下




    

这里你可以看到,布局文件com.spacesoftwares.ssapplication.MySurfaceView就是我们自己定义的那个MySurfaceView。

当然,不要忘记检查AndroidManifest.xml中有这么一句(一般Android Studio会自动添加)

com.spacesoftwares.ssapplication.SurfaceViewActivity

 

【1】 https://www.jianshu.com/p/15060fc9ef18

关注
打赏
1661664439
查看更多评论
立即登录/注册

微信扫码登录

0.0358s