美文网首页
SurfaceView的简单实用

SurfaceView的简单实用

作者: sssssss_ | 来源:发表于2023-03-07 09:53 被阅读0次
    public class EatrthWorkSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
        private SurfaceHolder mHolder;
        private Canvas mCanvas;
        private boolean mIsDrawing; // 子线程标志位
        public EatrthWorkSurfaceView(Context context) {
            super(context);
            init();
        }
        public EatrthWorkSurfaceView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
        public EatrthWorkSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        /**
         * 初始化数据
         */
        private void init() {
            mHolder = getHolder();
            mHolder.addCallback(this);
            setFocusable(true);
            setFocusableInTouchMode(true);
            setKeepScreenOn(true);
        }
    
        /**
         * 创建啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
         * @param holder
         */
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            mIsDrawing = true;
            new Thread(this).start();
        }
    
        /**
         * 视图方向改变啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
         * @param holder
         * @param format
         * @param width
         * @param height
         */
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        }
    
        /**
         * 销毁啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
         * @param holder
         */
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            mIsDrawing = false;
        }
    
        @Override
        public void run() {
            while (mIsDrawing){
                draw();
            }
        }
    
        private void draw(){
            try {
                mCanvas = mHolder.lockCanvas();
                // 绘制的内容
            }catch (Exception e){
            }finally {
                if (mCanvas!=null){
                    // 提交绘画内容
                    mHolder.unlockCanvasAndPost(mCanvas);
                }
            }
        }
    }
    
    

    手势缩放平移

    image.png

    这是绘制两个TEXT的代码:

    public class DemoSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
        private Context mContext;
        private List<NEZ> mNEZList;
        private ScheduledFuture mFuture;
        private ScheduledExecutorService mExecutorService;
        private SurfaceHolder mHolder; // SurfaceHolder对象
        private Canvas mCanvas;
        private boolean mIsDrawing; // 子线程标志位
        private Paint mPaint; // 画笔对象
        private TextPaint mTextPaint; // 画笔对象
    
        //----------------------------------------------------
    
        // 手势的状态
        private static final int NONE_FLAG = 0;
        private static final int DRAG_FLAG = 1;
        private static final int ZOOM_FLAG = 2;
        private int mTouchMode = NONE_FLAG;
        // 记录距离
        private float mDistance;
        // 双指滑动的距离
        private float mPreDistance;
        // 两指中点
        private PointF mid = new PointF();
        // 手指点下去的开始点
        private float mStartX, mStartY;
        // 缩放比例
        private double scaleX = 1.0f;
        private double scaleY = 1.0f;
        // 当前正在发生修改的矩阵
        private Matrix mCurrentMatrix = new Matrix();
        // 保存上一次修改后的矩阵
        private Matrix mSavedMatrix = new Matrix();
    
        //----------------------------------------------------
    
        public DemoSurfaceView(Context context) {
            super(context);
            this.mContext = context;
            init();
        }
        public DemoSurfaceView(Context context, AttributeSet attrs) {
            super(context, attrs);
            this.mContext = context;
            init();
        }
        public DemoSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            this.mContext = context;
            init();
        }
        private void init() {
            mPaint = new Paint();
            mPaint.setColor(Color.RED);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(10);
            mTextPaint = new TextPaint();
            mTextPaint.setTextSize(12);
            mTextPaint.setColor(Color.GREEN);
            mTextPaint.setAntiAlias(true);
            mTextPaint.setStrokeWidth(1);
            mHolder = getHolder();
            mHolder.addCallback(this);
        }
        @Override
        public void surfaceCreated(SurfaceHolder surfaceHolder) {
            // 在 surface 创建时初始化画布并开始绘制
            mIsDrawing = true;
            mExecutorService = Executors.newScheduledThreadPool(1);
            mFuture = mExecutorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    drawData();
                }
            }, 0, 16, TimeUnit.MILLISECONDS);
        }
        @Override
        public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
            // 在 surface 尺寸改变时重新绘制
        }
        @Override
        public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
            mIsDrawing = false;
            // 释放画布资源
            mFuture.cancel(true);
        }
        /**
         * 绘画数据
         */
        private void drawData() {
            try {
                mCanvas = mHolder.lockCanvas();
                mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
                mCanvas.save();
                Matrix drawMatrix = new Matrix();
                float dx = calTransX(mCurrentMatrix);
                float dy = calTransY(mCurrentMatrix);
                drawMatrix.postTranslate(dx, dy);
                mCanvas.setMatrix(drawMatrix);
                mCanvas.drawText("100", transectY(10), transectX(20), mTextPaint);
                mCanvas.drawText("100", transectY(20), transectX(30), mTextPaint);
                mCanvas.restore();
            } catch (Exception e) {
            } finally {
                if (mCanvas != null) {
                    // 提交绘画内容
                    mHolder.unlockCanvasAndPost(mCanvas);
                }
            }
        }
        /**
         * 设置数据
         */
        public void setData(Bounds bounds, int surfaceWidth, int surfaceHeight) {
            // 已知View的高宽,求图的高宽来计算缩放比
            double scalew, scaleh;
            scalew = surfaceWidth / bounds.getWidth();
            scaleh = surfaceHeight / bounds.getHeight();
            // 取最小倍数作为缩放
            scaleX = scaleY = Math.min(scalew, scaleh);
        }
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN: // 按下
                    mTouchMode = DRAG_FLAG;
                    mStartX = event.getX();
                    mStartY = event.getY();
                    mSavedMatrix.set(mCurrentMatrix); // 保存矩阵状态
                    break;
                case MotionEvent.ACTION_POINTER_DOWN: // 多指按下
                    mPreDistance = getDoubleDistance(event);
                    if (mPreDistance > 10f) {
                        Logg.v("SONGSONG", "ACTION_POINTER_DOWN");
                        mid = getMid(event);
                        mSavedMatrix.set(mCurrentMatrix);
                        mTouchMode = ZOOM_FLAG;
                    }
                    break;
                case MotionEvent.ACTION_MOVE: // 移动or缩放
                    if (mTouchMode == ZOOM_FLAG) {
                        Logg.v("SONGSONG", "ZOOM_FLAG");
                        mDistance = getDoubleDistance(event);
                        if (mDistance > 10) {
                            mCurrentMatrix.set(mSavedMatrix);
                            float scale = mDistance / mPreDistance;
                            mCurrentMatrix.postScale(scale, scale, mid.x, mid.y);//根据中心进行缩放
                        }
                    } else {
                        // 判断拖拽的距离
                        mDistance = getSingeDistance(event);
                        Logg.v("SONGSONG", "DRAG_FLAG");
                        if (mDistance > 10) {
                            // 恢复原来的矩阵
                            mCurrentMatrix.set(mSavedMatrix);
                            // 计算出移动的距离
                            float tempX = event.getX();
                            float tempY = event.getY();
                            float dx = tempX - mStartX;
                            float dy = tempY - mStartY;
                            // 给矩阵设置平移
                            mCurrentMatrix.postTranslate(dx, dy);
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP: // 松开
                    mTouchMode = NONE_FLAG;
                    break;
                case MotionEvent.ACTION_POINTER_UP: // 多指放开
                    mSavedMatrix.set(mCurrentMatrix);
                    if (event.getActionIndex() == 0) {
                        mStartX = event.getX(1);
                        mStartY = event.getY(1);
                    }
                    if (event.getActionIndex() == 1) {
                        mStartX = event.getX(0);
                        mStartY = event.getY(0);
                    }
                    mTouchMode = DRAG_FLAG;
                    break;
            }
            return true;
        }
    
        /**
         * 计算单指滑动的距离
         *
         * @param event
         * @return
         */
        private float getSingeDistance(MotionEvent event) {
            float x = mStartX - event.getX(0);
            float y = mStartY - event.getY(0);
            return (float) Math.sqrt(x * x + y * y);//两点之间的距离
        }
        /**
         * 计算双指滑动距离
         *
         * @param event
         */
        private float getDoubleDistance(MotionEvent event) {
            float x = event.getX(1) - event.getX(0);
            float y = event.getY(1) - event.getY(0);
            return (float) Math.sqrt(x * x + y * y);//两点之间的距离
        }
        /**
         * 计算X方向平移
         *
         * @param matrix 矩阵
         * @return X方向平移
         */
        protected static float calTransX(Matrix matrix) {
            float data[] = new float[9];
            matrix.getValues(data);
            return data[Matrix.MTRANS_X];
        }
    
        /**
         * 计算Y方向平移
         *
         * @param matrix 矩阵
         * @return Y方向平移
         */
        protected static float calTransY(Matrix matrix) {
            float data[] = new float[9];
            matrix.getValues(data);
            return data[Matrix.MTRANS_Y];
        }
    
        /**
         * 去两指的中心点坐标
         *
         * @param event
         * @return
         */
        private PointF getMid(MotionEvent event) {
            float midX = (event.getX(1) + event.getX(0)) / 2;
            float midY = (event.getY(1) - event.getY(0)) / 2;
            return new PointF(midX, midY);
        }
    
        /**
         * 计算缩放倍数
         * 由于x方向缩放和y方向缩放目前是一样的,所以只返回x方向缩放
         *
         * @param matrix 矩阵
         * @return 缩放倍数
         */
        protected static float calScale(Matrix matrix) {
            float data[] = new float[9];
            matrix.getValues(data);
            return data[Matrix.MSCALE_X];
        }
    
        /**
         * 在绘制过程,将x点转换屏幕坐标
         *
         * @param num
         * @return
         */
        private float transectX(float num) {
            return -(num) * (float) scaleY * calScale(mCurrentMatrix);
        }
    
        /**
         * 在绘制过程,将x点转换屏幕坐标
         *
         * @param num
         * @return
         */
        private float transectY(float num) {
            return num * (float) scaleX * calScale(mCurrentMatrix);
        }
    }
    
    

    为了加载业务代码,继续调整绘制位置:


    image.png
    public class GridPreviewSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
    
        private Context mContext;
    
        private ScheduledFuture mFuture;
        private ScheduledExecutorService mExecutorService;
        private SurfaceHolder mHolder; // SurfaceHolder对象
        private boolean mIsDrawing; // 子线程标志位
    
        private Canvas mCanvas;
        private Paint mPaint; // 画笔对象
        private TextPaint mTextPaint; // 画笔对象
        private Path mBoundsPath;
    
        //----------------------------------------------------
        private List<NEZ> mNEZList;
        private Bounds mBoundsData;
        private float mMidpointX;
        private float mMidpointY;
        private float mOffsetX;
        private float mOffsetY;
    
        //----------------------------------------------------
    
        // 手势的状态
        private static final int NONE_FLAG = 0;
        private static final int DRAG_FLAG = 1;
        private static final int ZOOM_FLAG = 2;
        private int mTouchMode = NONE_FLAG;
    
        // 记录距离
        private float mDistance;
        // 双指滑动的距离
        private float mPreDistance;
        // 两指中点
        private PointF mid = new PointF();
        // 手指点下去的开始点
        private float mStartX, mStartY;
        // 缩放比例
        private double scaleX = 1.0f;
        private double scaleY = 1.0f;
        // 当前正在发生修改的矩阵
        private Matrix mCurrentMatrix = new Matrix();
        // 保存上一次修改后的矩阵
        private Matrix mSavedMatrix = new Matrix();
    
        //----------------------------------------------------
    
        public GridPreviewSurfaceView(Context context) {
            super(context);
            this.mContext = context;
            init();
        }
    
        public GridPreviewSurfaceView(Context context, AttributeSet attrs) {
            super(context, attrs);
            this.mContext = context;
            init();
        }
    
        public GridPreviewSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            this.mContext = context;
            init();
        }
    
        private void init() {
    
            mPaint = new Paint();
            mPaint.setColor(Color.RED);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(3);
    
            mTextPaint = new TextPaint();
            mTextPaint.setTextSize(30);
            mTextPaint.setColor(Color.GREEN);
            mTextPaint.setAntiAlias(true);
            mTextPaint.setStrokeWidth(1);
    
            mHolder = getHolder();
            mHolder.addCallback(this);
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder surfaceHolder) {
            // 在 surface 创建时初始化画布并开始绘制
            mIsDrawing = true;
            mExecutorService = Executors.newScheduledThreadPool(1);
            mFuture = mExecutorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    drawData();
                }
            }, 0, 16, TimeUnit.MILLISECONDS);
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
            // 在 surface 尺寸改变时重新绘制
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
            mIsDrawing = false;
            // 释放画布资源
            mFuture.cancel(true);
        }
    
        /**
         * 绘画数据
         */
        private void drawData() {
            try {
                mCanvas = mHolder.lockCanvas();
                mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
    
                mCanvas.save();
                Matrix drawMatrix = new Matrix();
                float dx = calTransX(mCurrentMatrix);
                float dy = calTransY(mCurrentMatrix);
                drawMatrix.postTranslate(dx, dy);
                mCanvas.setMatrix(drawMatrix);
    
                drawBoundsLine();
                drawDataText();
    
                mCanvas.restore();
            } catch (Exception e) {
    
            } finally {
                if (mCanvas != null) {
                    // 提交绘画内容
                    mHolder.unlockCanvasAndPost(mCanvas);
                }
            }
        }
    
        private void drawBoundsLine() {
    
            mBoundsPath = new Path();
            mBoundsPath.moveTo(transectY((float) mBoundsData.getMinX() - mOffsetX), transectX((float) mBoundsData.getMinY() - mOffsetY));
            mBoundsPath.lineTo(transectY((float) mBoundsData.getMinX() - mOffsetX), transectX((float) mBoundsData.getMaxY() - mOffsetY));
            mBoundsPath.lineTo(transectY((float) mBoundsData.getMaxX() - mOffsetX), transectX((float) mBoundsData.getMaxY() - mOffsetY));
            mBoundsPath.lineTo(transectY((float) mBoundsData.getMaxX() - mOffsetX), transectX((float) mBoundsData.getMinY() - mOffsetY));
            mBoundsPath.close();
            mCanvas.drawPath(mBoundsPath, mPaint);
        }
    
        private void drawDataText() {
    
            if (mNEZList != null && mNEZList.size() > 0) {
                for (int i = 0; i < mNEZList.size(); i++) {
                    NEZ nez = mNEZList.get(i);
                    mCanvas.drawText(String.valueOf(nez.Z), transectY((float) nez.E - mOffsetX), transectX((float) nez.N - mOffsetY), mTextPaint);
                }
            }
        }
    
        /**
         * 设置数据
         */
        public void setData(List<NEZ> nezList, GridAltitudeMissionBean missionBean, int surfaceWidth, int surfaceHeight) {
    
            mNEZList = nezList;
    
            mBoundsData = new Bounds(missionBean.getMinX(), missionBean.getMinY(),
                    missionBean.getMaxX(), missionBean.getMaxY());
    
            // 偏移量
            mOffsetX = missionBean.getMinX() - surfaceWidth / 2;
            mOffsetY = missionBean.getMinY() + surfaceHeight;
    
            // 偏移量和屏幕大小计算出的中点
            mMidpointX = (float) ((mBoundsData.getWidth() + surfaceWidth) / 2);
            mMidpointY = (float) ((mBoundsData.getHeight() + surfaceHeight) / 2);
    
            // 已知View的高宽,求图的高宽来计算缩放比
            double scalew, scaleh;
            scalew = surfaceWidth / missionBean.getWidth();
            scaleh = surfaceHeight / missionBean.getHeight();
            // 取最小倍数作为缩放
            scaleX = scaleY = Math.min(scalew, scaleh);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN: // 按下
                    mTouchMode = DRAG_FLAG;
                    mStartX = event.getX();
                    mStartY = event.getY();
                    mSavedMatrix.set(mCurrentMatrix); // 保存矩阵状态
                    break;
                case MotionEvent.ACTION_POINTER_DOWN: // 多指按下
                    mPreDistance = getDoubleDistance(event);
                    if (mPreDistance > 10f) {
                        Logg.v("SONGSONG", "ACTION_POINTER_DOWN");
                        mid = getMid(event);
                        mSavedMatrix.set(mCurrentMatrix);
                        mTouchMode = ZOOM_FLAG;
                    }
                    break;
                case MotionEvent.ACTION_MOVE: // 移动or缩放
                    if (mTouchMode == ZOOM_FLAG) {
                        Logg.v("SONGSONG", "ZOOM_FLAG");
    
                        mDistance = getDoubleDistance(event);
                        if (mDistance > 10) {
                            mCurrentMatrix.set(mSavedMatrix);
                            float scale = mDistance / mPreDistance;
                            mCurrentMatrix.postScale(scale, scale, mid.x, mid.y);//根据中心进行缩放
                        }
                    } else {
                        // 判断拖拽的距离
                        mDistance = getSingeDistance(event);
                        Logg.v("SONGSONG", "DRAG_FLAG");
                        if (mDistance > 10) {
                            // 恢复原来的矩阵
                            mCurrentMatrix.set(mSavedMatrix);
                            // 计算出移动的距离
                            float tempX = event.getX();
                            float tempY = event.getY();
                            float dx = tempX - mStartX;
                            float dy = tempY - mStartY;
                            // 给矩阵设置平移
                            mCurrentMatrix.postTranslate(dx, dy);
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP: // 松开
                    mTouchMode = NONE_FLAG;
                    break;
                case MotionEvent.ACTION_POINTER_UP: // 多指放开
                    mSavedMatrix.set(mCurrentMatrix);
                    if (event.getActionIndex() == 0) {
                        mStartX = event.getX(1);
                        mStartY = event.getY(1);
                    }
                    if (event.getActionIndex() == 1) {
                        mStartX = event.getX(0);
                        mStartY = event.getY(0);
                    }
                    mTouchMode = DRAG_FLAG;
                    break;
            }
            return true;
        }
    
        /**
         * 计算单指滑动的距离
         *
         * @param event
         * @return
         */
        private float getSingeDistance(MotionEvent event) {
            float x = mStartX - event.getX(0);
            float y = mStartY - event.getY(0);
            return (float) Math.sqrt(x * x + y * y);//两点之间的距离
        }
    
        /**
         * 计算双指滑动距离
         *
         * @param event
         */
        private float getDoubleDistance(MotionEvent event) {
            float x = event.getX(1) - event.getX(0);
            float y = event.getY(1) - event.getY(0);
            return (float) Math.sqrt(x * x + y * y);//两点之间的距离
        }
    
        /**
         * 计算X方向平移
         *
         * @param matrix 矩阵
         * @return X方向平移
         */
        protected static float calTransX(Matrix matrix) {
            float data[] = new float[9];
            matrix.getValues(data);
            return data[Matrix.MTRANS_X];
        }
    
        /**
         * 计算Y方向平移
         *
         * @param matrix 矩阵
         * @return Y方向平移
         */
        protected static float calTransY(Matrix matrix) {
            float data[] = new float[9];
            matrix.getValues(data);
            return data[Matrix.MTRANS_Y];
        }
    
        /**
         * 去两指的中心点坐标
         *
         * @param event
         * @return
         */
        private PointF getMid(MotionEvent event) {
            float midX = (event.getX(1) + event.getX(0)) / 2;
            float midY = (event.getY(1) - event.getY(0)) / 2;
            return new PointF(midX, midY);
        }
    
        /**
         * 计算缩放倍数
         * 由于x方向缩放和y方向缩放目前是一样的,所以只返回x方向缩放
         *
         * @param matrix 矩阵
         * @return 缩放倍数
         */
        protected static float calScale(Matrix matrix) {
            float data[] = new float[9];
            matrix.getValues(data);
            return data[Matrix.MSCALE_X];
        }
    
        /**
         * 在绘制过程,将x点转换屏幕坐标
         *
         * @param num
         * @return
         */
        private float transectX(float num) {
            return -(num) * (float) scaleY * calScale(mCurrentMatrix);
        }
    
        /**
         * 在绘制过程,将x点转换屏幕坐标
         *
         * @param num
         * @return
         */
        private float transectY(float num) {
            return num * (float) scaleX * calScale(mCurrentMatrix);
        }
    }
    

    相关文章

      网友评论

          本文标题:SurfaceView的简单实用

          本文链接:https://www.haomeiwen.com/subject/hlgeultx.html