SurfaceView的简单实用
2023-03-07 本文已影响0人
sssssss_
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);
}
}