Android 自定义View实现贴图效果,可以按住贴图拖拽,缩放,移动位置,旋转等

思路:

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();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金戈鐡馬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值