I am using chrisbanes PhotoView to implement pinch zoom..Image zooms on pinching and double tapping but i can\'t see that my image streched to full screen on zooming..on zooming
I created a fully functional project on github. link in the end of the answer.
Problem elements:
1. Getting touch events and use it's variables to set image zoom level and window. (left, top, right, bottom).
Sample Code: only part of image will be showing at a time. therefore setting android:scaleType="fitCenter"
will achieve the zooming.
Touch Listener (you can modify this to add your 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. Since zooming required. I assume that we are using high quality images.
Therefore, loading the full sized quality image when zoomed out won't benefit, since the user won't recognise the small details. But it will increase memory usage and could crash for very large images.
Solution Trick: On zooming out load larger window with lower quality. On zoom in load smaller window with higher quality.
The proposed solution checks the current zoom level and image window required and based on that gets only part of the image with specific quality using BitmapRegionDecoder and BitmapFactory.
Sample Code:
Initialise image decoder that is going to be used later to ask for a 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();
}
Ask for 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) // you can map scale with quality better than this.
inSampleSize = 2;
bounds.inSampleSize = inSampleSize; // set image quality. takes binary steps only. 1, 2, 4, 8 . .
bm = bitmapRegionDecoder.decodeRegion(pRect, bounds);
imageView.setImageBitmap(bm);
project on github.