Android 利用Canvas实现双指拖动和双指缩放图片
2016-12-07 21:00
501 查看
背景
关于Android中使用Canvas绘制图片对于大家来说已经很熟悉了.关于图片的缩放和拖动,一般使用到的技能是:单指拖动图片和双指缩放图片.最近由于工作的要求,需要实现:1.双指拖动和在拖动过程中控制图片缩放.
2.绘制的线条与背景图片实现正片叠底的混合效果.
先上效果图:
原理:
使用的原理:1.我采用的是自定义View的方式来控制图片的缩放,坐标系起始点(0,0)在整个自定义View的左上角;
2.使用Canvas.scale(float sx, float sy)来实现画布的缩放进而实画布上现图片的缩放;
3.以两个手指触点的中心点作为整张图片缩放的中心点;通过函数canvas.drawBitmap(mSrcBitmap,x,y,mPdxPaint)中的参数x,y的指来实现图片位置的放置;
4.通过自定义View中onTouchEvent 函数来实现画笔线条的绘制;
5.把画笔绘制的线条单独绘制在一张空白的Bitmap图片上,底色必须为白色(正片叠底时使用),采用Paint中的混合模式 PorterDuff.Mode.MULTIPLY 来实现当前画笔绘制的Bitmap和背景Bitmap的混合;
6.由于在绘制过程中采用的两张图片的混合模式,所以在整个图片的移动过程中,整个画面会很卡,用户体验不好.为了提高拖动的效率,提高用户体验,我采用的方式:当双指同时触屏时,把当前背景图和绘制图直接混合成一张图片,在拖动过程中实际拖动的是混合后的一张图片.当拖动结束后,释放这张图片.
7.为了实现绘制过程中,可以让客户实时的看到绘制的效果,又重新定义了一张图片,这张图片就是指显示正在绘制的这条线,当绘制完成后,触电抬起ACTION_UP时,把这条线绘制到画笔的Bitmap上,在和背景图片实现正片叠底的混合.
主要代码:
MainActivity.javapackage com.test.wb.doublemoveview3; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import java.util.Arrays; import java.util.concurrent.CopyOnWriteArrayList; /** * Author: aaa * Date: 2016/12/5 17:31. */ public class DoubleMoveView3 extends View { private Context mContext; private Bitmap mSrcBitmap; private Bitmap mMultiplyBitmap = null;//混合之后的图片,双指缩放移动的时候,单独移动这张混合后图片,提高用户体验 public boolean mIsMove;//是否双指拖动图片中ing private int mBitmapWidth, mBitmapHeight;//图片的长度和高度 private float mCenterLeft, mCenterTop;//图片居中时左上角的坐标 private int mCenterHeight, mCenterWidth; // 图片适应屏幕时的大小 private float mCenterScale;//画布居中时的比例 private int mViewWidth, mViewHeight;//当前View的长度和宽度 private float mTransX = 0, mTransY = 0; // 偏移量,图片真实偏移量为 mCentreTranX + mTransX private float mScale = 1.0f; // 缩放倍数, 图片真实的缩放倍数为 mPrivateScale * mScale private boolean mIsSaveArg = false;//保存参数使用 private Paint mPaint; private Bitmap mGraffitiBitmap; // 用绘制涂鸦的图片 private Canvas mBitmapCanvas; // 用于绘制涂鸦的画布 private Bitmap mCurrentBitmap; // 绘制当前线时用到的图片 private Canvas mCurrentCanvas; // 当前绘制线的画布 private int[] mWhiteBuffer;//保存白色图片内存,刷新时重新刷新图片 // 保存涂鸦操作,便于撤销 private CopyOnWriteArrayList<MyDrawSinglePath> mPathStack = new CopyOnWriteArrayList<MyDrawSinglePath>(); private CopyOnWriteArrayList<MyDrawSinglePath> pathStackBackup = new CopyOnWriteArrayList<MyDrawSinglePath>(); private int mTouchMode; // 触摸模式,触点数量 private float mTouchDownX, mTouchDownY, mLastTouchX, mLastTouchY, mTouchX, mTouchY; private MyDrawSinglePath mCurrPath; // 当前手写的路径 private PorterDuffXfermode mPdXfermode; // 定义PorterDuffXfermode变量 private Paint mPdXfPaint;// 绘图的混合模式 private Paint mCurrentPaint; private Path mCanvasPath; //仅用于当前Path的绘制 public DoubleMoveView3(Context context, Bitmap bitmap) { super(context); mContext = context; init(bitmap); } public DoubleMoveView3(Context context, AttributeSet attrs) { super(context, attrs); } private void init(Bitmap bitmap) { mSrcBitmap = bitmap; mBitmapWidth = mSrcBitmap.getWidth(); mBitmapHeight = mSrcBitmap.getHeight(); mMultiplyBitmap = Bitmap.createBitmap(mBitmapWidth, mBitmapHeight, Bitmap.Config.ARGB_8888); mPaint = new Paint(); mPaint.setColor(Color.RED); mPaint.setStrokeWidth(20); mGraffitiBitmap = getTransparentBitmap(mSrcBitmap); mCurrentPaint = new Paint(); mCurrentPaint.setStyle(Paint.Style.STROKE); mCurrentPaint.setStrokeWidth(50); mCurrentPaint.setColor(Color.RED); mCurrentPaint.setAlpha(100); mCurrentPaint.setAntiAlias(true); mCurrentPaint.setStrokeJoin(Paint.Join.ROUND); mCurrentPaint.setStrokeCap(Paint.Cap.ROUND); mCurrentPaint.setXfermode(null); mCanvasPath = new Path(); mCurrentBitmap = getTransparentBitmap(mSrcBitmap); //设置混合模式 (正片叠底) mPdXfermode = new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY); mPdXfPaint = new Paint(); mPdXfPaint.setAntiAlias(true); mPdXfPaint.setFilterBitmap(true); mIsMove = false; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mViewWidth = w; mViewHeight = h; float nw = mBitmapWidth * 1f / mViewWidth; float nh = mBitmapHeight * 1f / mViewHeight; if (nw > nh) { mCenterScale = 1 / nw; mCenterWidth = mViewWidth; mCenterHeight = (int) (mBitmapHeight * mCenterScale); } else { mCenterScale = 1 / nh; mCenterWidth = (int) (mBitmapWidth * mCenterScale); mCenterHeight = mViewHeight; } // 使图片居中 mCenterLeft = (mViewWidth - mCenterWidth) / 2f; mCenterTop = (mViewHeight - mCenterHeight) / 2f; initCanvas(); initCurrentCanvas(); mIsMove = false; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float scale = mCenterScale * mScale; float x = (mCenterLeft + mTransX) / scale; float y = (mCenterTop + mTransY) / scale; canvas.scale(scale, scale); if (!mIsMove) { //正片叠底混合模式 initCurrentCanvas(); mCurrentCanvas.drawPath(mCanvasPath, mCurrentPaint); canvas.drawBitmap(mSrcBitmap, x, y, mPdXfPaint); mPdXfPaint.setXfermode(mPdXfermode); canvas.drawBitmap(mCurrentBitmap, x, y, mPdXfPaint); // 绘制涂鸦图片 canvas.drawBitmap(mGraffitiBitmap, x, y, mPdXfPaint); mPdXfPaint.setXfermode(null); } else { //只显示原始图片 canvas.drawBitmap(mMultiplyBitmap, x, y, null); } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: Log.i("aaa", "ACTION_DOWN"); mTouchMode = 1; penTouchDown(event.getX(), event.getY()); return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: Log.i("aaa", "ACTION_UP"); mTouchMode = 0; mCanvasPath.reset(); initCanvas();//添上这句防止重复绘制 draw(mBitmapCanvas, mPathStack); // 保存到图片中 invalidate(); return true; case MotionEvent.ACTION_MOVE: Log.i("aaa", "ACTION_MOVE"); if (mTouchMode == 1 && !mIsMove) { mLastTouchX = mTouchX; mLastTouchY = mTouchY; mTouchX = event.getX(); mTouchY = event.getY(); mCurrPath.getPath().quadTo(screenToBitmapX(mLastTouchX), screenToBitmapY(mLastTouchY), screenToBitmapX((mTouchX + mLastTouchX) / 2), screenToBitmapY((mTouchY + mLastTouchY) / 2)); mCanvasPath.quadTo(screenToBitmapX(mLastTouchX), screenToBitmapY(mLastTouchY), screenToBitmapX((mTouchX + mLastTouchX) / 2), screenToBitmapY((mTouchY + mLastTouchY) / 2)); invalidate(); } return true; } return true; } public void setTransScale(float scale, float dx, float dy) { mScale = scale; mTransX = dx; mTransY = dy; if (!mIsSaveArg) { invalidate(); } mIsSaveArg = false; } public void saveCurrentScale() { mCenterScale = mCenterScale * mScale; mCenterLeft = (mCenterLeft + mTransX) / mCenterScale; mCenterTop = (mCenterTop + mTransY) / mCenterScale; mIsSaveArg = true; saveMultiplyBitmap(); } //双指移动的时候,生成混合之后的图片 private void saveMultiplyBitmap() { mIsMove = true; Canvas canvas = new Canvas(mMultiplyBitmap); canvas.drawBitmap(mSrcBitmap, 0, 0, mPdXfPaint); mPdXfPaint.setXfermode(mPdXfermode); // 绘制涂鸦图片 canvas.drawBitmap(mGraffitiBitmap, 0, 0, mPdXfPaint); mPdXfPaint.setXfermode(null); } /** * 在画笔的状态下第一个触点按下的情况 */ private void penTouchDown(float x, float y) { mIsMove = false; mTouchDownX = mTouchX = mLastTouchX = x; mTouchDownY = mTouchY = mLastTouchY = y; // 为了仅点击时也能出现绘图,模拟滑动一个像素点 mTouchX++; mTouchY++; mCurrPath = new MyDrawSinglePath(Color.RED, 50, 100, true); mCurrPath.getPath().moveTo(screenToBitmapX(mTouchDownX), screenToBitmapY(mTouchDownY)); mPathStack.add(mCurrPath); mCanvasPath.reset(); mCanvasPath.moveTo(screenToBitmapX(mTouchDownX), screenToBitmapY(mTouchDownY)); // 为了仅点击时也能出现绘图,必须移动path mCanvasPath.quadTo(screenToBitmapX(mLastTouchX), screenToBitmapY(mLastTouchY), screenToBitmapX((mTouchX + mLastTouchX) / 2), screenToBitmapY((mTouchY + mLastTouchY) / 2)); } /** * 初始化当前画线的绘图 */ private void initCurrentCanvas() { mCurrentBitmap.setPixels(mWhiteBuffer, 0, mSrcBitmap.getWidth(), 0, 0, mSrcBitmap.getWidth(), mSrcBitmap.getHeight()); mCurrentCanvas = new Canvas(mCurrentBitmap); } /** * 初始化涂鸦的绘图 */ private void initCanvas() { mGraffitiBitmap.setPixels(mWhiteBuffer, 0, mSrcBitmap.getWidth(), 0, 0, mSrcBitmap.getWidth(), mSrcBitmap.getHeight()); mBitmapCanvas = new Canvas(mGraffitiBitmap); } /** * 创建一个图片,透明度为255(不透明), 底色为白色 ,目的是为了使用正片叠底 * * @param sourceImg * @return */ public Bitmap getTransparentBitmap(Bitmap sourceImg) { mWhiteBuffer = new int[sourceImg.getWidth() * sourceImg.getHeight()]; Arrays.fill(mWhiteBuffer, 0xFFFFFFFF); sourceImg = Bitmap.createBitmap(mWhiteBuffer, sourceImg.getWidth(), sourceImg.getHeight(), Bitmap.Config.ARGB_8888).copy(Bitmap.Config.ARGB_8888, true); return sourceImg; } private void draw(Canvas canvas, CopyOnWriteArrayList<MyDrawSinglePath> pathStack) { // 还原堆栈中的记录的操作 for (MyDrawSinglePath path : pathStack) { canvas.drawPath(path.getPath(), path.getMyPen().getPenPaint()); } } //双指抬起时 public void PointertUp() { if (!mCanvasPath.isEmpty()) {//单指画线过程中,出现双触点则停止画线 mCanvasPath.reset(); if (!mPathStack.isEmpty()) { mPathStack.remove(mPathStack.size() - 1); } } } /** * 将触摸的屏幕坐标转换成实际图片中的坐标 */ public float screenToBitmapX(float touchX) { return (touchX - mCenterLeft - mTransX) / (mCenterScale * mScale); } public float screenToBitmapY(float touchY) { return (touchY - mCenterTop - mTransY) / (mCenterScale * mScale); } //通过触点的坐标和实际图片中的坐标,得到当前图片的起始点坐标 public final float toTransX(float touchX, float graffitiX) { return -graffitiX * (mCenterScale * mScale) + touchX - mCenterLeft; } public final float toTransY(float touchY, float graffitiY) { return -graffitiY * (mCenterScale * mScale) + touchY - mCenterTop; } }
自定义View DoubleMoveView3.java
package com.test.wb.doublemoveview3; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import java.util.Arrays; import java.util.concurrent.CopyOnWriteArrayList; /** * Author: aaa * Date: 2016/12/5 17:31. */ public class DoubleMoveView3 extends View { private Context mContext; private Bitmap mSrcBitmap; private Bitmap mMultiplyBitmap = null;//混合之后的图片,双指缩放移动的时候,单独移动这张混合后图片,提高用户体验 public boolean mIsMove;//是否双指拖动图片中ing private int mBitmapWidth, mBitmapHeight;//图片的长度和高度 private float mCenterLeft, mCenterTop;//图片居中时左上角的坐标 private int mCenterHeight, mCenterWidth; // 图片适应屏幕时的大小 private float mCenterScale;//画布居中时的比例 private int mViewWidth, mViewHeight;//当前View的长度和宽度 private float mTransX = 0, mTransY = 0; // 偏移量,图片真实偏移量为 mCentreTranX + mTransX private float mScale = 1.0f; // 缩放倍数, 图片真实的缩放倍数为 mPrivateScale * mScale private boolean mIsSaveArg = false;//保存参数使用 private Paint mPaint; private Bitmap mGraffitiBitmap; // 用绘制涂鸦的图片 private Canvas mBitmapCanvas; // 用于绘制涂鸦的画布 private Bitmap mCurrentBitmap; // 绘制当前线时用到的图片 private Canvas mCurrentCanvas; // 当前绘制线的画布 private int[] mWhiteBuffer;//保存白色图片内存,刷新时重新刷新图片 // 保存涂鸦操作,便于撤销 private CopyOnWriteArrayList<MyDrawSinglePath> mPathStack = new CopyOnWriteArrayList<MyDrawSinglePath>(); private CopyOnWriteArrayList<MyDrawSinglePath> pathStackBackup = new CopyOnWriteArrayList<MyDrawSinglePath>(); private int mTouchMode; // 触摸模式,触点数量 private float mTouchDownX, mTouchDownY, mLastTouchX, mLastTouchY, mTouchX, mTouchY; private MyDrawSinglePath mCurrPath; // 当前手写的路径 private PorterDuffXfermode mPdXfermode; // 定义PorterDuffXfermode变量 private Paint mPdXfPaint;// 绘图的混合模式 private Paint mCurrentPaint; private Path mCanvasPath; //仅用于当前Path的绘制 public DoubleMoveView3(Context context, Bitmap bitmap) { super(context); mContext = context; init(bitmap); } public DoubleMoveView3(Context context, AttributeSet attrs) { super(context, attrs); } private void init(Bitmap bitmap) { mSrcBitmap = bitmap; mBitmapWidth = mSrcBitmap.getWidth(); mBitmapHeight = mSrcBitmap.getHeight(); mMultiplyBitmap = Bitmap.createBitmap(mBitmapWidth, mBitmapHeight, Bitmap.Config.ARGB_8888); mPaint = new Paint(); mPaint.setColor(Color.RED); mPaint.setStrokeWidth(20); mGraffitiBitmap = getTransparentBitmap(mSrcBitmap); mCurrentPaint = new Paint(); mCurrentPaint.setStyle(Paint.Style.STROKE); mCurrentPaint.setStrokeWidth(50); mCurrentPaint.setColor(Color.RED); mCurrentPaint.setAlpha(100); mCurrentPaint.setAntiAlias(true); mCurrentPaint.setStrokeJoin(Paint.Join.ROUND); mCurrentPaint.setStrokeCap(Paint.Cap.ROUND); mCurrentPaint.setXfermode(null); mCanvasPath = new Path(); mCurrentBitmap = getTransparentBitmap(mSrcBitmap); //设置混合模式 (正片叠底) mPdXfermode = new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY); mPdXfPaint = new Paint(); mPdXfPaint.setAntiAlias(true); mPdXfPaint.setFilterBitmap(true); mIsMove = false; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mViewWidth = w; mViewHeight = h; float nw = mBitmapWidth * 1f / mViewWidth; float nh = mBitmapHeight * 1f / mViewHeight; if (nw > nh) { mCenterScale = 1 / nw; mCenterWidth = mViewWidth; mCenterHeight = (int) (mBitmapHeight * mCenterScale); } else { mCenterScale = 1 / nh; mCenterWidth = (int) (mBitmapWidth * mCenterScale); mCenterHeight = mViewHeight; } // 使图片居中 mCenterLeft = (mViewWidth - mCenterWidth) / 2f; mCenterTop = (mViewHeight - mCenterHeight) / 2f; initCanvas(); initCurrentCanvas(); mIsMove = false; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float scale = mCenterScale * mScale; float x = (mCenterLeft + mTransX) / scale; float y = (mCenterTop + mTransY) / scale; canvas.scale(scale, scale); if (!mIsMove) { //正片叠底混合模式 initCurrentCanvas(); mCurrentCanvas.drawPath(mCanvasPath, mCurrentPaint); canvas.drawBitmap(mSrcBitmap, x, y, mPdXfPaint); mPdXfPaint.setXfermode(mPdXfermode); canvas.drawBitmap(mCurrentBitmap, x, y, mPdXfPaint); // 绘制涂鸦图片 canvas.drawBitmap(mGraffitiBitmap, x, y, mPdXfPaint); mPdXfPaint.setXfermode(null); } else { //只显示原始图片 canvas.drawBitmap(mMultiplyBitmap, x, y, null); } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: mTouchMode = 1; penTouchDown(event.getX(), event.getY()); return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mTouchMode = 0; mCanvasPath.reset(); initCanvas();//添上这句防止重复绘制 draw(mBitmapCanvas, mPathStack); // 保存到图片中 invalidate(); return true; case MotionEvent.ACTION_MOVE: if (mTouchMode == 1 && !mIsMove) { mLastTouchX = mTouchX; mLastTouchY = mTouchY; mTouchX = event.getX(); mTouchY = event.getY(); mCurrPath.getPath().quadTo(screenToBitmapX(mLastTouchX), screenToBitmapY(mLastTouchY), screenToBitmapX((mTouchX + mLastTouchX) / 2), screenToBitmapY((mTouchY + mLastTouchY) / 2)); mCanvasPath.quadTo(screenToBitmapX(mLastTouchX), screenToBitmapY(mLastTouchY), screenToBitmapX((mTouchX + mLastTouchX) / 2), screenToBitmapY((mTouchY + mLastTouchY) / 2)); invalidate(); } return true; } return true; } public void setTransScale(float scale, float dx, float dy) { mScale = scale; mTransX = dx; mTransY = dy; if (!mIsSaveArg) { invalidate(); } mIsSaveArg = false; } public void saveCurrentScale() { mCenterScale = mCenterScale * mScale; mCenterLeft = (mCenterLeft + mTransX) / mCenterScale; mCenterTop = (mCenterTop + mTransY) / mCenterScale; mIsSaveArg = true; saveMultiplyBitmap(); } //双指移动的时候,生成混合之后的图片 private void saveMultiplyBitmap() { mIsMove = true; Canvas canvas = new Canvas(mMultiplyBitmap); canvas.drawBitmap(mSrcBitmap, 0, 0, mPdXfPaint); mPdXfPaint.setXfermode(mPdXfermode); // 绘制涂鸦图片 canvas.drawBitmap(mGraffitiBitmap, 0, 0, mPdXfPaint); mPdXfPaint.setXfermode(null); } /** * 在画笔的状态下第一个触点按下的情况 */ private void penTouchDown(float x, float y) { mIsMove = false; mTouchDownX = mTouchX = mLastTouchX = x; mTouchDownY = mTouchY = mLastTouchY = y; // 为了仅点击时也能出现绘图,模拟滑动一个像素点 mTouchX++; mTouchY++; mCurrPath = new MyDrawSinglePath(Color.RED, 50, 100, true); mCurrPath.getPath().moveTo(screenToBitmapX(mTouchDownX), screenToBitmapY(mTouchDownY)); mPathStack.add(mCurrPath); mCanvasPath.reset(); mCanvasPath.moveTo(screenToBitmapX(mTouchDownX), screenToBitmapY(mTouchDownY)); // 为了仅点击时也能出现绘图,必须移动path mCanvasPath.quadTo(screenToBitmapX(mLastTouchX), screenToBitmapY(mLastTouchY), screenToBitmapX((mTouchX + mLastTouchX) / 2), screenToBitmapY((mTouchY + mLastTouchY) / 2)); } /** * 初始化当前画线的绘图 */ private void initCurrentCanvas() { mCurrentBitmap.setPixels(mWhiteBuffer, 0, mSrcBitmap.getWidth(), 0, 0, mSrcBitmap.getWidth(), mSrcBitmap.getHeight()); mCurrentCanvas = new Canvas(mCurrentBitmap); } /** * 初始化涂鸦的绘图 */ private void initCanvas() { mGraffitiBitmap.setPixels(mWhiteBuffer, 0, mSrcBitmap.getWidth(), 0, 0, mSrcBitmap.getWidth(), mSrcBitmap.getHeight()); mBitmapCanvas = new Canvas(mGraffitiBitmap); } /** * 创建一个图片,透明度为255(不透明), 底色为白色 ,目的是为了使用正片叠底 * * @param sourceImg * @return */ public Bitmap getTransparentBitmap(Bitmap sourceImg) { mWhiteBuffer = new int[sourceImg.getWidth() * sourceImg.getHeight()]; Arrays.fill(mWhiteBuffer, 0xFFFFFFFF); sourceImg = Bitmap.createBitmap(mWhiteBuffer, sourceImg.getWidth(), sourceImg.getHeight(), Bitmap.Config.ARGB_8888).copy(Bitmap.Config.ARGB_8888, true); return sourceImg; } private void draw(Canvas canvas, CopyOnWriteArrayList<MyDrawSinglePath> pathStack) { // 还原堆栈中的记录的操作 for (MyDrawSinglePath path : pathStack) { canvas.drawPath(path.getPath(), path.getMyPen().getPenPaint()); } } //双指抬起时 public void PointertUp() { if (!mCanvasPath.isEmpty()) {//单指画线过程中,出现双触点则停止画线 mCanvasPath.reset(); if (!mPathStack.isEmpty()) { mPathStack.remove(mPathStack.size() - 1); } } } /** * 将触摸的屏幕坐标转换成实际图片中的坐标 */ public float screenToBitmapX(float touchX) { return (touchX - mCenterLeft - mTransX) / (mCenterScale * mScale); } public float screenToBitmapY(float touchY) { return (touchY - mCenterTop - mTransY) / (mCenterScale * mScale); } //通过触点的坐标和实际图片中的坐标,得到当前图片的起始点坐标 public final float toTransX(float touchX, float graffitiX) { return -graffitiX * (mCenterScale * mScale) + touchX - mCenterLeft; } public final float toTransY(float touchY, float graffitiY) { return -graffitiY * (mCenterScale * mScale) + touchY - mCenterTop; } }
使用到的另外的两个类:
MyPen.java
package com.test.wb.doublemoveview3; import android.graphics.Color; import android.graphics.Paint; /** * Author: aaa * Date: 2016/10/13 09:54. * 涂鸦时所用的画笔 */ public class MyPen { boolean mBooleanPen;//是否是画笔 true - 画笔 false - 橡皮差 private int mPenColor; private int mPenSize; private int mPenAlpha;//0 - 100 private Paint mPaint, mEraserPaint; public MyPen(int penColor, int penSize, int penAlpha, boolean bPen) { mPenAlpha = penAlpha; mPenColor = penColor; mPenSize = penSize; mBooleanPen = bPen; if (mBooleanPen){//画笔 mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(mPenSize); mPaint.setColor(mPenColor); mPaint.setAlpha(mPenAlpha); mPaint.setAntiAlias(true); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); }else {//橡皮擦 mEraserPaint = new Paint(); mEraserPaint.setStyle(Paint.Style.STROKE); mEraserPaint.setAlpha(255); mEraserPaint.setColor(Color.WHITE); mEraserPaint.setStrokeWidth(mPenSize); mEraserPaint.setAntiAlias(true); mEraserPaint.setStrokeJoin(Paint.Join.ROUND); mEraserPaint.setStrokeCap(Paint.Cap.ROUND); } } public int getPenAlpha() { return mPenAlpha; } public void setPenAlpha(int penAlpha) { mPenAlpha = penAlpha; } public int getPenColor() { return mPenColor; } public void setPenColor(int penColor) { mPenColor = penColor; } public int getPenSize() { return mPenSize; } public void setPenSize(int penSize) { mPenSize = penSize; } public boolean isBooleanPen() { return mBooleanPen; } public void setBooleanPen(boolean booleanBen) { mBooleanPen = booleanBen; } public Paint getPenPaint(){ if (mBooleanPen) { return mPaint; }else{ return mEraserPaint; } } }
MyDrawSinglePath.java
package com.test.wb.doublemoveview3; import android.graphics.Path; /** * Author: aaa * Date: 2016/10/15 11:24. * 当前涂鸦的路径 */ public class MyDrawSinglePath { private MyPen mMyPen; private Path mPath; public MyDrawSinglePath(int color, int size, int alpha, boolean b){ mMyPen = new MyPen(color, size, alpha, b); mPath = new Path(); } public MyPen getMyPen() { return mMyPen; } public Path getPath() { return mPath; } }
下载链接:Demo下载
相关文章推荐
- Android 利用Canvas实现双指拖动和双指缩放图片(二)-图片拖出边界检测
- Android开发:ImageView上绘制旋转圆环(透明度不同的旋转圆环,利用canvas.drawArc实现)
- android利用Paint在Canvas实现竖排文字
- Android开发:ImageView上绘制旋转圆环(透明度不同的旋转圆环,利用canvas.drawArc实现)
- Android利用Canvas和Paint实现画图和自定义布局组件
- 【Android】利用自定义View的重绘实现拖动移动,获取组件的尺寸
- 让Flex控件 Canvas实现弹出窗口并拖动
- Android中利用LinearLayout继承实现ImageButton
- 利用Jquery的cropper插件实现拖动层动态头剪切(裁剪头像)图片
- 利用SendMessage实现窗口拖动
- Android 中利用反射技术实现加减乘除
- android实现拖动效果
- android 实现拖动效果
- 利用magicAjax实现webParts无刷新拖动
- android中实现swipe的手势功能及页面拖动动画
- 【积累】利用WM_NCHITTEST消息实现无标题窗口的拖动
- Android实现拖动效果
- C#中利用"消息处理"实现在窗体中按下鼠标左键拖动窗体_L
- 利用majicAjax实现webParts无刷新拖动
- 利用SendMessage实现窗口拖动[转]