Drawing and scaling ImageView and canvas in Android

I want to be able to draw and scale ImageView and Canvas .

I can already do this, but when I draw something and then enlarge the image, the drawing remains in its place, as you see below:

originalimage

zoomedimage

and here is my code:

activity_main.xml

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <Button android:id="@+id/enable_zoom" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="disable zoom"/> <com.zoomtrial2.CustomImageView android:id="@+id/zoom_iv" android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/image" android:layout_below="@+id/enable_zoom" /> <com.zoomtrial2.DrawableView android:id="@+id/drawble_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignBottom="@+id/zoom_iv" android:layout_alignTop="@+id/zoom_iv" /> 

MainActivity.java

 public class MainActivity extends Activity implements View.OnClickListener { private Button enableZoomBtn; private DrawableView drawbleView; private CustomImageView touchImageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); drawbleView = (DrawableView) findViewById(R.id.drawble_view); enableZoomBtn = (Button) findViewById(R.id.enable_zoom); touchImageView = (CustomImageView) findViewById(R.id.zoom_iv); enableZoomBtn.setOnClickListener(this); drawbleView.setDrawingEnabled(false); } @Override public void onClick(View v) { int id = v.getId(); switch (id) { case R.id.enable_zoom: if(enableZoomBtn.getText().equals("disable zoom")){ touchImageView.setZoomEnable(false); drawbleView.setDrawingEnabled(true); enableZoomBtn.setText("enable zoom"); } else{ touchImageView.setZoomEnable(true); drawbleView.setDrawingEnabled(false); enableZoomBtn.setText("disable zoom"); } break; default: break; } } } 

DrawableView.java

 public class DrawableView extends View { public int width; public int height; private boolean isEditable; private Path drawPath; private Paint drawPaint; private Paint canvasPaint; private Canvas drawCanvas; private Bitmap canvasBitmap; private int paintColor = Color.RED; public DrawableView(Context context) { super(context); } public DrawableView(Context context, AttributeSet attrs) { super(context, attrs); this.canvasPaint = new Paint(Paint.DITHER_FLAG); setupDrawing(); } public DrawableView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); this.height = h; this.width = w; canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); drawCanvas = new Canvas(canvasBitmap); } private void setupDrawing() { drawPath = new Path(); drawPaint = new Paint(); drawPaint.setColor(paintColor); drawPaint.setAntiAlias(true); drawPaint.setDither(true); drawPaint.setStyle(Paint.Style.STROKE); drawPaint.setStrokeJoin(Paint.Join.ROUND); drawPaint.setStrokeCap(Paint.Cap.ROUND); drawPaint.setStrokeWidth(10); } public void setDrawingEnabled(boolean isEditable){ this.isEditable = isEditable; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); canvas.drawPath(drawPath, drawPaint); } @Override public boolean onTouchEvent(MotionEvent event) { if(isEditable){ float touchX = event.getX(); float touchY = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: drawPath.moveTo(touchX, touchY); break; case MotionEvent.ACTION_MOVE: drawPath.lineTo(touchX, touchY); break; case MotionEvent.ACTION_UP: drawPath.lineTo(touchX, touchY); drawCanvas.drawPath(drawPath, drawPaint); drawPath = new Path(); break; default: return false; } } else{ return false; } invalidate(); return true; } } 

CustomImageView.java

 public class CustomImageView extends ImageView { Matrix matrix; // We can be in one of these 3 states static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; int mode = NONE; private boolean zoomEnable= true; // Remember some things for zooming PointF last = new PointF(); PointF start = new PointF(); float minScale = 1f; float maxScale = 5f; float[] m; int viewWidth, viewHeight; static final int CLICK = 3; float saveScale = 1f; protected float origWidth, origHeight; int oldMeasuredWidth, oldMeasuredHeight; ScaleGestureDetector mScaleDetector; Context context; public CustomImageView(Context context) { super(context); sharedConstructing(context); } public void setZoomEnable(boolean status){ zoomEnable = status; } public CustomImageView(Context context, AttributeSet attrs) { super(context, attrs); sharedConstructing(context); } private void sharedConstructing(Context context) { super.setClickable(true); this.context = context; mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); matrix = new Matrix(); m = new float[9]; setImageMatrix(matrix); setScaleType(ScaleType.MATRIX); setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if(zoomEnable){ mScaleDetector.onTouchEvent(event); PointF curr = new PointF(event.getX(), event.getY()); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: last.set(curr); start.set(last); mode = DRAG; break; case MotionEvent.ACTION_MOVE: if (mode == DRAG) { float deltaX = curr.x - last.x; float deltaY = curr.y - last.y; float fixTransX = getFixDragTrans(deltaX, viewWidth, origWidth * saveScale); float fixTransY = getFixDragTrans(deltaY, viewHeight, origHeight * saveScale); matrix.postTranslate(fixTransX, fixTransY); fixTrans(); last.set(curr.x, curr.y); } break; case MotionEvent.ACTION_UP: mode = NONE; int xDiff = (int) Math.abs(curr.x - start.x); int yDiff = (int) Math.abs(curr.y - start.y); if (xDiff < CLICK && yDiff < CLICK) performClick(); break; case MotionEvent.ACTION_POINTER_UP: mode = NONE; break; } setImageMatrix(matrix); invalidate(); return true; // indicate event was handled } else{ return false; } } }); } public void setMaxZoom(float x) { maxScale = x; } private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScaleBegin(ScaleGestureDetector detector) { mode = ZOOM; return true; } @Override public boolean onScale(ScaleGestureDetector detector) { float mScaleFactor = detector.getScaleFactor(); float origScale = saveScale; saveScale *= mScaleFactor; if (saveScale > maxScale) { saveScale = maxScale; mScaleFactor = maxScale / origScale; } else if (saveScale < minScale) { saveScale = minScale; mScaleFactor = minScale / origScale; } if (origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight) matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2, viewHeight / 2); else matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY()); fixTrans(); return true; } } void fixTrans() { matrix.getValues(m); float transX = m[Matrix.MTRANS_X]; float transY = m[Matrix.MTRANS_Y]; float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale); float fixTransY = getFixTrans(transY, viewHeight, origHeight * saveScale); if (fixTransX != 0 || fixTransY != 0) matrix.postTranslate(fixTransX, fixTransY); } float getFixTrans(float trans, float viewSize, float contentSize) { float minTrans, maxTrans; if (contentSize <= viewSize) { minTrans = 0; maxTrans = viewSize - contentSize; } else { minTrans = viewSize - contentSize; maxTrans = 0; } if (trans < minTrans) return -trans + minTrans; if (trans > maxTrans) return -trans + maxTrans; return 0; } float getFixDragTrans(float delta, float viewSize, float contentSize) { if (contentSize <= viewSize) { return 0; } return delta; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); viewWidth = MeasureSpec.getSize(widthMeasureSpec); viewHeight = MeasureSpec.getSize(heightMeasureSpec); // // Rescales image on rotation // if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight || viewWidth == 0 || viewHeight == 0) return; oldMeasuredHeight = viewHeight; oldMeasuredWidth = viewWidth; if (saveScale == 1) { // Fit to screen. float scale; Drawable drawable = getDrawable(); if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) return; int bmWidth = drawable.getIntrinsicWidth(); int bmHeight = drawable.getIntrinsicHeight(); Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight); float scaleX = (float) viewWidth / (float) bmWidth; float scaleY = (float) viewHeight / (float) bmHeight; scale = Math.min(scaleX, scaleY); matrix.setScale(scale, scale); // Center the image float redundantYSpace = (float) viewHeight - (scale * (float) bmHeight); float redundantXSpace = (float) viewWidth - (scale * (float) bmWidth); redundantYSpace /= (float) 2; redundantXSpace /= (float) 2; matrix.postTranslate(redundantXSpace, redundantYSpace); origWidth = viewWidth - 2 * redundantXSpace; origHeight = viewHeight - 2 * redundantYSpace; setImageMatrix(matrix); } fixTrans(); } } 
+8
source share
1 answer

When you zoom in, you only call setImageMatrix (matrix). This set the matrix to the image, which was then applied. The problem is that it will not apply to the extra path that you created. What you need to do is apply the matrix to the canvas, draw various elements. You do not apply the matrix to the path so that they are out of sync. Your drawableview onDraw () routine is perfect for this code. You can also just draw the bitmap yourself and get rid of the look of the image. In the end, what you do is more complicated than just presenting with some image hooks.

0
source

All Articles