I created a fully functional github project. link at the end of the answer.
Elements of the problem:
1. Getting touch events and using its variables to set the zoom level of the image and window. (left, top, right, bottom).
Code example: only part of the image is shown. therefore setting android:scaleType="fitCenter" will scale.
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/imageFrameLayout" android:background="@android:color/black"> <ImageView android:id="@+id/imageView" android:layout_width="0px" android:layout_height="0px" android:layout_gravity="center" android:scaleType="fitCenter" android:background="@android:color/transparent" /> </FrameLayout>
Touch Listener (you can change this to add a click event)
OnTouchListener MyOnTouchListener = new OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent event) { float distx, disty; switch(event.getAction() & MotionEvent.ACTION_MASK){ case MotionEvent.ACTION_DOWN: //A pressed gesture has started, the motion contains the initial starting location. touchState = TOUCH; currentX = (int) event.getRawX(); currentY = (int) event.getRawY(); break; case MotionEvent.ACTION_POINTER_DOWN: //A non-primary pointer has gone down. touchState = PINCH; //Get the distance when the second pointer touch distx = event.getX(0) - event.getX(1); disty = event.getY(0) - event.getY(1); dist0 = (float) Math.sqrt(distx * distx + disty * disty); distLast = dist0; break; case MotionEvent.ACTION_MOVE: //A change has happened during a press gesture (between ACTION_DOWN and ACTION_UP). if(touchState == PINCH){ // pinch started calculate scale step. //Get the current distance distx = event.getX(0) - event.getX(1); disty = event.getY(0) - event.getY(1); distCurrent = (float) Math.sqrt(distx * distx + disty * disty); if (Math.abs(distCurrent-distLast) >= 35) // check sensitivity { stepScale = distCurrent/dist0; distLast = distCurrent; drawMatrix(); // draw new image } } else { // move started. if (currentX==-1 && currentY==-1) { // first move after touch down currentX = (int) event.getRawX(); currentY = (int) event.getRawY(); } else { // calculate move window variable. int x2 = (int) event.getRawX(); int y2 = (int) event.getRawY(); int dx = (currentX - x2); int dy = (currentY - y2); left += dx; top += dy; currentX = x2; currentY = y2; drawMatrix(); // draw new image window } } break; case MotionEvent.ACTION_UP: //A pressed gesture has finished. touchState = IDLE; break; case MotionEvent.ACTION_POINTER_UP: //A non-primary pointer has gone up. if (touchState == PINCH) { // pinch ended. reset variable. } touchState = TOUCH; break; } return true; } };
2. Because scaling is required. I assume we use high quality images.
Therefore, when downloading full-sized image quality while zooming out, this will not be useful, since the user will not recognize small details. But this will increase memory usage and may crash for very large images.
Trick Solution: When zoomed in, a larger window is displayed with lower quality When zooming in on a smaller image with higher quality.
The proposed solution checks the current zoom level and the required image window and, on the basis of this, receives only part of the image with a certain quality using BitmapRegionDecoder and BitmapFactory .
Code example:
Initialize the image decoder, which will be used later to request part of the image:
InputStream is = null; bitmapRegionDecoder = null; try { is = getAssets().open(res_id); // get image stream from assets. only the stream, no mem usage bitmapRegionDecoder = BitmapRegionDecoder.newInstance(is, false); } catch (IOException e) { e.printStackTrace(); } bounds = new BitmapFactory.Options(); bounds.inJustDecodeBounds = true; // only specs needed. no image yet! BitmapFactory.decodeStream(is, null, bounds); // get image specs. try { is.close(); // close stream no longer needed. } catch (IOException e) { e.printStackTrace(); }
Request image with quality and window:
Rect pRect = new Rect(left, top, left + newWidth, top + newHeight); BitmapFactory.Options bounds = new BitmapFactory.Options(); int inSampleSize = 1; if (tempScale <= 2.75)
project on github .