public class EatrthWorkSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder mHolder;
private Canvas mCanvas;
private boolean mIsDrawing; // 子線程標(biāo)志位
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();
}
/**
* 初始化數(shù)據(jù)
*/
private void init() {
mHolder = getHolder();
mHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
setKeepScreenOn(true);
}
/**
* 創(chuàng)建啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
* @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();
// 繪制的內(nèi)容
}catch (Exception e){
}finally {
if (mCanvas!=null){
// 提交繪畫內(nèi)容
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
}
手勢縮放平移
這是繪制兩個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; // 子線程標(biāo)志位
private Paint mPaint; // 畫筆對象
private TextPaint mTextPaint; // 畫筆對象
//----------------------------------------------------
// 手勢的狀態(tài)
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;
// 當(dāng)前正在發(fā)生修改的矩陣
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 創(chuàng)建時初始化畫布并開始繪制
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);
}
/**
* 繪畫數(shù)據(jù)
*/
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) {
// 提交繪畫內(nèi)容
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
/**
* 設(shè)置數(shù)據(jù)
*/
public void setData(Bounds bounds, int surfaceWidth, int surfaceHeight) {
// 已知View的高寬塘砸,求圖的高寬來計算縮放比
double scalew, scaleh;
scalew = surfaceWidth / bounds.getWidth();
scaleh = surfaceHeight / bounds.getHeight();
// 取最小倍數(shù)作為縮放
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); // 保存矩陣狀態(tài)
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);//根據(jù)中心進行縮放
}
} else {
// 判斷拖拽的距離
mDistance = getSingeDistance(event);
Logg.v("SONGSONG", "DRAG_FLAG");
if (mDistance > 10) {
// 恢復(fù)原來的矩陣
mCurrentMatrix.set(mSavedMatrix);
// 計算出移動的距離
float tempX = event.getX();
float tempY = event.getY();
float dx = tempX - mStartX;
float dy = tempY - mStartY;
// 給矩陣設(shè)置平移
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];
}
/**
* 去兩指的中心點坐標(biāo)
*
* @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);
}
/**
* 計算縮放倍數(shù)
* 由于x方向縮放和y方向縮放目前是一樣的,所以只返回x方向縮放
*
* @param matrix 矩陣
* @return 縮放倍數(shù)
*/
protected static float calScale(Matrix matrix) {
float data[] = new float[9];
matrix.getValues(data);
return data[Matrix.MSCALE_X];
}
/**
* 在繪制過程凸郑,將x點轉(zhuǎn)換屏幕坐標(biāo)
*
* @param num
* @return
*/
private float transectX(float num) {
return -(num) * (float) scaleY * calScale(mCurrentMatrix);
}
/**
* 在繪制過程,將x點轉(zhuǎn)換屏幕坐標(biāo)
*
* @param num
* @return
*/
private float transectY(float num) {
return num * (float) scaleX * calScale(mCurrentMatrix);
}
}
為了加載業(yè)務(wù)代碼,繼續(xù)調(diào)整繪制位置:
public class GridPreviewSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private Context mContext;
private ScheduledFuture mFuture;
private ScheduledExecutorService mExecutorService;
private SurfaceHolder mHolder; // SurfaceHolder對象
private boolean mIsDrawing; // 子線程標(biāo)志位
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;
//----------------------------------------------------
// 手勢的狀態(tài)
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;
// 當(dāng)前正在發(fā)生修改的矩陣
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 創(chuàng)建時初始化畫布并開始繪制
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);
}
/**
* 繪畫數(shù)據(jù)
*/
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) {
// 提交繪畫內(nèi)容
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);
}
}
}
/**
* 設(shè)置數(shù)據(jù)
*/
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();
// 取最小倍數(shù)作為縮放
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); // 保存矩陣狀態(tài)
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);//根據(jù)中心進行縮放
}
} else {
// 判斷拖拽的距離
mDistance = getSingeDistance(event);
Logg.v("SONGSONG", "DRAG_FLAG");
if (mDistance > 10) {
// 恢復(fù)原來的矩陣
mCurrentMatrix.set(mSavedMatrix);
// 計算出移動的距離
float tempX = event.getX();
float tempY = event.getY();
float dx = tempX - mStartX;
float dy = tempY - mStartY;
// 給矩陣設(shè)置平移
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];
}
/**
* 去兩指的中心點坐標(biāo)
*
* @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);
}
/**
* 計算縮放倍數(shù)
* 由于x方向縮放和y方向縮放目前是一樣的才沧,所以只返回x方向縮放
*
* @param matrix 矩陣
* @return 縮放倍數(shù)
*/
protected static float calScale(Matrix matrix) {
float data[] = new float[9];
matrix.getValues(data);
return data[Matrix.MSCALE_X];
}
/**
* 在繪制過程,將x點轉(zhuǎn)換屏幕坐標(biāo)
*
* @param num
* @return
*/
private float transectX(float num) {
return -(num) * (float) scaleY * calScale(mCurrentMatrix);
}
/**
* 在繪制過程集歇,將x點轉(zhuǎn)換屏幕坐標(biāo)
*
* @param num
* @return
*/
private float transectY(float num) {
return num * (float) scaleX * calScale(mCurrentMatrix);
}
}