思路:
1、首先需要根据屏幕宽高计算出指定的贴图的位置,并计算出贴图的宽高;
2、利用Matrix把贴图放置到指定的位置上,并利用Matrix做旋转,缩放,移动等操作;
3、当用户按下贴图的时候,记录按下的x,y坐标,并记录贴图当前的Matrix;
4、当用户移动贴图的时候,根据移动的距离,计算出贴图新的Matrix,并重新绘制贴图;
5、当用户缩放贴图,计算缩放的比例,计算出贴图新的Matrix,并重新绘制贴图;
6、当用户旋转贴图时,计算旋转的角度,计算出新的Matrix,并重新绘制贴图;
代码实现:
public class StickerView extends View {
private Bitmap mBitmap;
private Matrix mCurrentMatrix;
private Paint mPaint;
private float mOriginalWidth, mOriginalHeight;
private float mRotateX, mRotateY;
private float mCurrentDegree;
private float mScale;
private float mTranslateX, mTranslateY;
private float mStartX, mStartY;
private float mCurrentX, mCurrentY;
private int mMode;
private static final int MODE_NONE = 0;
private static final int MODE_DRAG = 1;
private static final int MODE_ZOOM = 2;
private static final int MODE_ROTATE = 3;
public StickerView(Context context) {
this(context, null, 0);
}
public StickerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public StickerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mCurrentMatrix = new Matrix();
mMode = MODE_NONE;
}
public void setBitmap(Bitmap bitmap) {
mBitmap = bitmap;
mOriginalWidth = bitmap.getWidth();
mOriginalHeight = bitmap.getHeight();
mRotateX = mOriginalWidth / 2;
mRotateY = mOriginalHeight / 2;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBitmap != null) {
canvas.drawBitmap(mBitmap, mCurrentMatrix, mPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mMode = MODE_DRAG;
mStartX = event.getX();
mStartY = event.getY();
mCurrentMatrix.invert(mCurrentMatrix);
mCurrentMatrix.mapPoints(new float[]{mStartX, mStartY});
break;
case MotionEvent.ACTION_MOVE:
if (mMode == MODE_DRAG) {
mCurrentX = event.getX();
mCurrentY = event.getY();
mTranslateX = mCurrentX - mStartX;
mTranslateY = mCurrentY - mStartY;
mCurrentMatrix.postTranslate(mTranslateX, mTranslateY);
mStartX = mCurrentX;
mStartY = mCurrentY;
} else if (mMode == MODE_ZOOM) {
float endX = event.getX();
float endY = event.getY();
float scaleX = endX - mStartX;
float scaleY = endY - mStartY;
mScale = (float) Math.sqrt(scaleX * scaleX + scaleY * scaleY);
mCurrentMatrix.postScale(mScale, mScale, mRotateX, mRotateY);
} else if (mMode == MODE_ROTATE) {
float endX = event.getX();
float endY = event.getY();
float centerX = (mStartX + endX) / 2;
float centerY = (mStartY + endY) / 2;
float startX = mRotateX + mOriginalWidth / 2;
float startY = mRotateY + mOriginalHeight / 2;
float currentDegree = getDegree(centerX, centerY, startX, startY, endX, endY);
mCurrentMatrix.postRotate(currentDegree - mCurrentDegree, mRotateX, mRotateY);
mCurrentDegree = currentDegree;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
mMode = MODE_ZOOM;
mStartX = event.getX(0);
mStartY = event.getY(0);
break;
case MotionEvent.ACTION_POINTER_UP:
mMode = MODE_ROTATE;
mStartX = event.getX(0);
mStartY = event.getY(0);
break;
case MotionEvent.ACTION_UP:
mMode = MODE_NONE;
break;
}
invalidate();
return true;
}
private float getDegree(float centerX, float centerY, float startX, float startY, float endX, float endY) {
float degree = 0;
float a = (float) Math.sqrt(Math.pow(endX - centerX, 2) + Math.pow(endY - centerY, 2));
float b = (float) Math.sqrt(Math.pow(startX - centerX, 2) + Math.pow(startY - centerY, 2));
float c = (float) Math.sqrt(Math.pow(startX - endX, 2) + Math.pow(startY - endY, 2));
if (b != 0 && c != 0) {
float cosA = (float) ((Math.pow(b, 2) + Math.pow(c, 2) - Math.pow(a, 2)) / (2 * b * c));
if (cosA >= 1) {
cosA = 1f;
} else if (cosA <= -1) {
cosA = -1f;
}
degree = (float) Math.toDegrees(Math.acos(cosA));
float cal = startX * endY - endX * startY;
if (cal > 0) {
degree = -degree;
}
}
return degree;
}
public void reset() {
mCurrentMatrix.reset();
invalidate();
}
}