Let's call this question an image viewer, its main functions are:
1. Double-click to zoom the picture.
2. Scale the picture with both fingers.
3. Drag and drop the picture with one finger.
For this purpose, this image viewer needs to consider the following technical points:
1. Double-click to zoom in the picture:
1. If the image height is much smaller than the screen height, then enlarge the image to the same height as the screen height, otherwise enlarge a specific multiple.
2. How to determine whether this multiple reaches to stop scaling.
3. After judging and stopping enlarging, the picture may have exceeded the size required by this multiple. How to return to our target size.
4. After the judgment is completed and the reduction is stopped, the image width may be smaller than the screen width, leaving blank space on both sides. How to reset it to its original size.
2. Scaling the picture with two fingers:
1. Scale with both fingers and zoom in to a specific multiple to stop.
2. How to determine whether this multiple has reached.
3. After the enlargement stops, the picture may have exceeded the required size of this multiple. How to return to our target size.
4. After the shrinking stops, the image width may be smaller than the screen width, leaving blank space on both sides. How to reset it to its original size.
3. Drag and drop with one finger:
1. When the image width is less than or equal to the screen width, movement left and right is prohibited. When the image height is less than the screen height, movement up and down is prohibited.
2. When moving the picture, if one side of the picture has become blank with the screen, let go and restore it, so that this side of the picture coincides with the screen boundary.
Four,
How to determine whether it is a double-click, multi-finger touch, or single-finger.
five,
How to resolve the sliding conflict with viewPager. When the image has been slided to the end and cannot slide, the viewPager should intercept the event.
Let's solve it one by one:
public class MyImageView extends ImageView implements , { public MyImageView(Context context, AttributeSet attrs) { super(context, attrs); (); setOnTouchListener(this); /** * Double-click to enlarge the picture */ mGestureDetector = new GestureDetector(context, new () { @Override public boolean onDoubleTap(MotionEvent e) { changeViewSize(e); return true; } }); }
Here, the zoom image is using matrix, so first you need to set the scaleType to matrix.
Use gestures to judge the behavior of double-clicking. Don't forget to add it in onTouch
if ((event)) return true;
To determine whether single fingers and multi finger touching is done, judged in onTouch, use () & MotionEvent.ACTION_MASK to judge.
//Multi-finger touch mode, single-finger, double-fingerprivate int mode; private final static int SINGLE_TOUCH = 1; //Single fingerprivate final static int DOUBLE_TOUCH = 2; //Two fingers@Override public boolean onTouch(View view, MotionEvent event) { rectF = getMatrixRectF(); if ((event)) return true; switch (() & ()) { case MotionEvent.ACTION_DOWN: mode = SINGLE_TOUCH; break; case MotionEvent.ACTION_MOVE: if (mode >= DOUBLE_TOUCH) //Two-finger zoom { } if (mode == SINGLE_TOUCH) //Drag and drag with one finger { } break; case MotionEvent.ACTION_POINTER_DOWN: mode += 1;break; case MotionEvent.ACTION_POINTER_UP: mode -= 1; break; case MotionEvent.ACTION_UP: mode = 0; break; //In ACTION_MOVE, after the event is intercepted, sometimes ACTION_UP cannot be triggered, so ACTION_CANCEL is added case MotionEvent.ACTION_CANCEL: mode = 0; break; default: break; } return true; }
There are the following events that we want to use:
MotionEvent.ACTION_DOWN: Triggered when the first point is pressed
MotionEvent.ACTION_UP: Triggered when the unique point on the screen is released
MotionEvent.ACTION_POINTER_DOWN: Triggered when a point on the screen is already pressed and then pressed another point.
MotionEvent.ACTION_POINTER_UP: Triggered when multiple points are held on the screen and one of them is released (i.e. when the non-last point is released).
MotionEvent.ACTION_MOVE: Triggered when a bit moves on the screen. It is worth noting that because it has high sensitivity and our fingers cannot be completely still (even if we can't feel the movement, our fingers are actually shaking constantly), the reality is that basically as long as it is on the screen, this event will be triggered constantly.
In ACTION_MOVE, it is determined whether it is a single finger or a double finger by the size of the mode.
But there is one sad thing, Android itself has a bug. After testing, it was found that when the two fingers exchange touched the picture, the program would crash and an exception occurred: pointIndex out of range. This is Android's own bug. I personally think the best solution is to customize a viewPager, then rewrite it in it: onTouchEvent, onInterceptTouchEvent, and then catch the exception.
@Override public boolean onTouchEvent(MotionEvent ev) { try { return (ev); } catch (IllegalArgumentException ex) { (); } return false; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { try { return (ev); } catch (IllegalArgumentException ex) { (); } return false; }
This way the program will not crash.
Let's take a look at the code that double-click to enlarge:
/** * Double-click to zoom in picture */ private void changeViewSize(MotionEvent e) { //Get the coordinates of the double-click final float x = (); final float y = (); //If it is still scaling at this time, then return directly if (animator != null && ()) return; //Judge whether it is in a state of zooming in or zooming out if (!isZoomChanged()) { animator = (1.0f, 2.0f); } else { animator = (1.0f, 0.0f); } (this); (500); (new DecelerateInterpolator()); (); (new () { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { Float value = (Float) (); (value, value, x, y); checkBorderAndCenterWhenScale(); //Center the picture after zooming setImageMatrix(matrix); /** * Control the narrowed range * If it is already smaller than the initial size, then return to the initial size and stop */ if (checkRestScale()) { (oldMatrix); //oldMatrix is the most primitive matrix setImageMatrix(matrix); return; } /** * Control the enlarged range * If the magnification is already greater than the target, then it is directly set to the target's magnification * Then stop */ if (getMatrixValueX() >= mDoubleClickScale) { (mDoubleClickScale/getMatrixValueX(), mDoubleClickScale/getMatrixValueX(), x, y); checkBorderAndCenterWhenScale(); setImageMatrix(matrix); return; } } }); }
Code to determine whether it is in the zoom-in or zoom-in state: (If it is not the initial value, it means it is in the zoom-in state)
/** * Determine whether the zoom level has changed * * @return true means non-initial value, false means initial value */ private boolean isZoomChanged() { float[] values = new float[9]; getImageMatrix().getValues(values); //Get the current X-axis zoom level float scale = values[Matrix.MSCALE_X]; //Get the initial X-axis zoom level and compare the two (values); return scale != values[Matrix.MSCALE_X]; }
The code of getMatrixValue() is as follows, in order to obtain the current magnification, relative to the initial picture
private float getMatrixValueX() { // TODO Auto-generated method stub float[] values = new float[9]; getImageMatrix().getValues(values); //Get the current X-axis zoom level float scale = values[Matrix.MSCALE_X]; //Get the X-axis zoom level of the original Matrix (values); //Return the enlarged multiple return scale / values[Matrix.MSCALE_X]; }
The code of checkRestScale() is as follows, mainly to determine whether the current zoom level is smaller than the initial zoom level.
/** * Determine whether reset is required * * @return Reset when the current zoom level is smaller than the original zoom level */ private boolean checkRestScale() { // TODO Auto-generated method stub float[] values = new float[9]; getImageMatrix().getValues(values); //Get the current X-axis zoom level float scale = values[Matrix.MSCALE_X]; //Get the original X-axis zoom level and compare the two (values); return scale < values[Matrix.MSCALE_X]; }
The code of checkBorderAndCenterWhenScale() is as follows, otherwise the position will change after the image is scaled.
/** * When zooming, control the image display range */ private void checkBorderAndCenterWhenScale() { RectF rect = getMatrixRectF(); float deltaX = 0; float deltaY = 0; int width = getWidth(); int height = getHeight(); // If the width or height is larger than the screen, the control range if (() >= width) { if ( > 0) { deltaX = -; } if ( < width) { deltaX = width - ; } } if (() >= height) { if ( > 0) { deltaY = -; } if ( < height) { deltaY = height - ; } } // If the width or height is smaller than the screen, center it if (() < width) { deltaX = width * 0.5f - + 0.5f * (); } if (() < height) { deltaY = height * 0.5f - + 0.5f * (); } (deltaX, deltaY); setImageMatrix(matrix); }
Next, take a look at the two-finger zoom and single-finger drag:
@Override public boolean onTouch(View view, MotionEvent event) { rectF = getMatrixRectF(); //Get the image boundary range if ((event)) return true; switch (() & ()) { case MotionEvent.ACTION_DOWN: //If the boundary of the image exceeds the screen after enlargement, then the event will be blocked and the viewPager will not be processed. if (() > getWidth() || () > getHeight()) { getParent().requestDisallowInterceptTouchEvent(true); } mode = SINGLE_TOUCH; x = (int) (); y = (int) (); break; case MotionEvent.ACTION_MOVE: if (mode >= DOUBLE_TOUCH) //Two-finger zoom { getParent().requestDisallowInterceptTouchEvent(true); newDist = calculateDist(event); // Calculate the distance Point point = getMiPoint(event); //Get the midpoint coordinates between the two fingers if (newDist > oldDist + 1) //Zoom in (add one to prevent jitter) { changeViewSize(oldDist, newDist, point); //Achieve zoom in and out according to distance oldDist = newDist; } if (oldDist > newDist + 1) //Shrink { changeViewSize(oldDist, newDist, point); oldDist = newDist; } } if (mode == SINGLE_TOUCH) //Drag and drag with one finger { float dx = () - x; float dy = () - y; //If the boundary of the picture exceeds the screen during the movement, then the event will be blocked and the viewPager will not be processed. if (() > getWidth() || () > getHeight()) { getParent().requestDisallowInterceptTouchEvent(true); } //If you move the picture to the right and reach the end, then don't intercept the event and let the viewPager handle it if ( >= 0 && dx > 0) getParent().requestDisallowInterceptTouchEvent(false); //If you move to the end to the left, then don't intercept the event and let the viewPager handle it if ( <= getWidth() && dx < 0) getParent().requestDisallowInterceptTouchEvent(false); if (getDrawable() != null) { //If the image width or height does not exceed the screen, then it is prohibited to slide left and right or up and down if (() <= getWidth()) dx = 0; if (() < getHeight()) dy = 0; //If the image moves down to the end, don't let it continue to move if ( >= 0 && dy > 0) dy = 0; //If the image moves up to the end, don't let it continue to move if ( <= getHeight() && dy < 0) dy = 0; //When the moving distance is greater than 1, because ACTION_MOVE is more sensitive, // Even if the finger is just placed on it, you can still detect the shaking of the finger and then move the picture. if ((dx) > 1 || (dy) > 1) (dx, dy); setImageMatrix(matrix); } } x = (int) (); y = (int) (); break; case MotionEvent.ACTION_POINTER_DOWN: mode += 1; oldDist = calculateDist(event); break; case MotionEvent.ACTION_POINTER_UP: mode -= 1; break; case MotionEvent.ACTION_UP: backToPosition(); mode = 0; break; //In ACTION_MOVE, after the event is intercepted, sometimes ACTION_UP cannot be triggered, so ACTION_CANCEL is added case MotionEvent.ACTION_CANCEL: backToPosition(); mode = 0; break; default: break; } return true; }
First, let’s take a look at a method. To obtain the boundary range of the image based on the matrix of the image, this range is mapped on rect. (This range detection is used on single finger dragging)
/** * Get the range of images based on Matrix of the current image * * @return */ private RectF getMatrixRectF() { RectF rect = new RectF(); Drawable d = getDrawable(); if (null != d) { (0, 0, (), ()); (rect); } ("aaaa",""++" "++" "++" "+); return rect; }
: The vertical coordinate of the boundary below the picture
: The horizontal axis of the left border of the picture
: The horizontal axis of the right border of the picture
: The vertical coordinate of the upper boundary of the picture
(): Image width
(): Image height
It should be noted that Matrix operates the bitmap in the ImageView. The ImageView has not changed. The screen boundary mentioned above is actually the boundary of the ImageView, getWidth() and getHeight() are the width and height of the ImageView.
Method backToPosition() mainly implements the technical point 2 of single-finger drag. When the finger quickly passes, the image boundary and the screen boundary have already appeared before detecting that it is impossible to continue sliding. Therefore, when you release your finger, you must reset it to make the image boundary and the screen boundary overlap.
/** * If the boundary of the image is separated from the screen boundary after moving, then let the image boundary overlap with the screen boundary. * If the finger moves quickly, the image will be blank from the screen after stopping, and then it will be judged that it cannot move any more. * But it appears before making the next judgment on whether you can continue to move. * So reset is required */ private void backToPosition() { if ( >= 0) { //The distance between the left border of the picture and the screen appears (-, 0); setImageMatrix(matrix); } if ( <= getWidth()) { //The distance between the right border of the picture and the screen appears (getWidth() - , 0); setImageMatrix(matrix); } if ( >= 0) { //The distance between the border on the picture and the screen appears (0, -); setImageMatrix(matrix); } if ( <= getHeight()) { //The distance between the bottom boundary of the picture and the screen appears (0, getHeight() - ); setImageMatrix(matrix); } }
Get the midpoint coordinates between two fingers
/** * Get the midpoint of zooming when two fingers are zoomed * * @return */ private Point getMiPoint(MotionEvent event) { float x = (0) + (1); float y = (0) + (1); ((int) x / 2, (int) y / 2); return mPoint; }
Calculate the distance between the touch points of two fingers
/** * Calculate the distance between the touch points of two fingers */ private float calculateDist(MotionEvent event) { float x = (0) - (1); float y = (0) - (1); return (float) (x * x + y * y); }
Scaling picture with two fingers
/** * Two-finger zoom picture */ private void changeViewSize(float oldDist, float newDist, Point mPoint) { float scale = newDist / oldDist; //Scaling (scale, scale, , ); checkBorderAndCenterWhenScale(); setImageMatrix(matrix); //Prevent it from being smaller than the initial image size when shrinking, and needs to be reset reSetMatrix(); //If the scaling is already greater than the target multiple, stop because it may have exceeded it, then directly scale to the target size if (getMatrixValueX() >= MAX_SCALE) { (MAX_SCALE/getMatrixValueX(), MAX_SCALE/getMatrixValueX(), x, y); checkBorderAndCenterWhenScale(); setImageMatrix(matrix); return; } }
The code of reSetMatrix() is as follows:
/** * Reset Matrix */ private void reSetMatrix() { if (checkRestScale()) { (oldMatrix); setImageMatrix(matrix); return; } }
The code of checkRestScale() has been given above. oldMatrix is the initial Matrix.
It's not over yet. Set the ScaleType of Imageview to Matrix, so the image will not be actively scaled to the adaptive screen, nor will it be in the middle of the screen. Therefore, our custom ImageView needs to be inherited.
@Override protected void onAttachedToWindow() { (); getViewTreeObserver().addOnGlobalLayoutListener(this); }
@Override public void onGlobalLayout() { if (once) { Drawable d = getDrawable(); if (d == null) return; ("TAG", () + " , " + ()); int width = getWidth(); int height = getHeight(); // Get the width and height of the picture int dw = (); int dh = (); float scale = 1.0f; // If the width or height of the picture is greater than the screen, zoom to the width or height of the screen if (dw > width && dh <= height) { scale = width * 1.0f / dw; } if (dh > height && dw <= width) { scale = height * 1.0f / dh; } // If both width and height are larger than the screen, make it fit the screen size in proportion if (dw > width && dh > height) { scale = (width * 1.0f / dw, height * 1.0f / dh); } initScale = scale; ("TAG", "initScale = " + initScale); ((width - dw) / 2, (height - dh) / 2); (scale, scale, getWidth() / 2, getHeight() / 2); // Move the picture to the center of the screen setImageMatrix(matrix); (getImageMatrix()); once = false; RectF rectF=getMatrixRectF(); setDoubleClickScale(rectF); } } // Get the width and height of the picture int dw = (); int dh = ();
The width and height of the picture obtained are the real height of the bitmap.
The initial oldMatrix is set here, and then used as the initial template, representing the Matrix whose image has not been changed manually. As for the method setDoubleClickScale(rectF); it is just to set the multiple of double-click to enlarge. If the image height is much smaller than the screen height, then enlarge the image to the height equal to the screen height, otherwise enlarge a specific multiple. It must be set here because the rectF obtained here can reflect the boundaries of the original image, because there has not been any hands-on change of the image at this time.
/** * Set the multiple of double-click to enlarge */ private void setDoubleClickScale(RectF rectF) { if(()<getHeight()-100) { mDoubleClickScale=getHeight()/(); } else mDoubleClickScale=2f; }
It's probably over here, and the complete code is posted below:
package ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; /** * Created by TangZH on 2017/5/3. */ public class MyImageView extends ImageView implements , { private final static int SINGLE_TOUCH = 1; //Single finger private final static int DOUBLE_TOUCH = 2; //Two fingers //Multi-finger touch mode, single-finger, double-finger private int mode; //The distance between the touch points of two fingers private float oldDist; private float newDist; /** * Maximum zoom level */ private static final float MAX_SCALE = 5f; /** * Zoom level when double-clicked */ private float mDoubleClickScale = 2; /** * Scaling ratio during initialization, if the image width or height is larger than the screen, this value will be less than 0 */ private float initScale = 1.0f; private boolean once = true; private RectF rectF; /** * Used for double-click detection */ private GestureDetector mGestureDetector; private int x = 0; private int y = 0; private Point mPoint = new Point(); private final Matrix matrix = new Matrix(); private Matrix oldMatrix = new Matrix(); private ValueAnimator animator; public MyImageView(Context context) { this(context, null); } public MyImageView(Context context, AttributeSet attrs) { super(context, attrs); (); setOnTouchListener(this); /** * Double-click to enlarge the picture */ mGestureDetector = new GestureDetector(context, new () { @Override public boolean onDoubleTap(MotionEvent e) { changeViewSize(e); return true; } }); } @Override public boolean onTouch(View view, MotionEvent event) { rectF = getMatrixRectF(); //Get the image boundary range if ((event)) return true; switch (() & ()) { case MotionEvent.ACTION_DOWN: //If the boundary of the image exceeds the screen after enlargement, then the event will be blocked and the viewPager will not be processed. if (() > getWidth() || () > getHeight()) { getParent().requestDisallowInterceptTouchEvent(true); } mode = SINGLE_TOUCH; x = (int) (); y = (int) (); break; case MotionEvent.ACTION_MOVE: if (mode >= DOUBLE_TOUCH) //Two-finger zoom { getParent().requestDisallowInterceptTouchEvent(true); newDist = calculateDist(event); // Calculate the distance Point point = getMiPoint(event); //Get the midpoint coordinates between the two fingers if (newDist > oldDist + 1) //Zoom in (add one to prevent jitter) { changeViewSize(oldDist, newDist, point); //Achieve zoom in and out according to distance oldDist = newDist; } if (oldDist > newDist + 1) //Shrink { changeViewSize(oldDist, newDist, point); oldDist = newDist; } } if (mode == SINGLE_TOUCH) //Drag and drag with one finger { float dx = () - x; float dy = () - y; //If the boundary of the picture exceeds the screen during the movement, then the event will be blocked and the viewPager will not be processed. if (() > getWidth() || () > getHeight()) { getParent().requestDisallowInterceptTouchEvent(true); } //If you move the picture to the right and reach the end, then don't intercept the event and let the viewPager handle it if ( >= 0 && dx > 0) getParent().requestDisallowInterceptTouchEvent(false); //If you move to the end to the left, then don't intercept the event and let the viewPager handle it if ( <= getWidth() && dx < 0) getParent().requestDisallowInterceptTouchEvent(false); if (getDrawable() != null) { //If the image width or height does not exceed the screen, then it is prohibited to slide left and right or up and down if (() <= getWidth()) dx = 0; if (() < getHeight()) dy = 0; //If the image moves down to the end, don't let it continue to move if ( >= 0 && dy > 0) dy = 0; //If the image moves up to the end, don't let it continue to move if ( <= getHeight() && dy < 0) dy = 0; //When the moving distance is greater than 1, because ACTION_MOVE is more sensitive, // Even if the finger is just placed on it, you can still detect the shaking of the finger and then move the picture. if ((dx) > 1 || (dy) > 1) (dx, dy); setImageMatrix(matrix); } } x = (int) (); y = (int) (); break; case MotionEvent.ACTION_POINTER_DOWN: mode += 1; oldDist = calculateDist(event); ("q", "" + "a"); (":::", "" + () + " " + () + " " + (0)); break; case MotionEvent.ACTION_POINTER_UP: mode -= 1; break; case MotionEvent.ACTION_UP: backToPosition(); mode = 0; break; //In ACTION_MOVE, after the event is intercepted, sometimes ACTION_UP cannot be triggered, so ACTION_CANCEL is added case MotionEvent.ACTION_CANCEL: backToPosition(); mode = 0; break; default: break; } return true; } /** * Calculate the distance between the touch points of two fingers */ private float calculateDist(MotionEvent event) { float x = (0) - (1); float y = (0) - (1); return (float) (x * x + y * y); } @Override protected void onAttachedToWindow() { (); getViewTreeObserver().addOnGlobalLayoutListener(this); } /** * If the boundary of the image is separated from the screen boundary after moving, then let the image boundary overlap with the screen boundary. * If the finger moves quickly, the image will be blank from the screen after stopping, and then it will be judged that it cannot move any more. * But it appears before making the next judgment on whether you can continue to move. * So reset is required */ private void backToPosition() { if ( >= 0) { //The distance between the left border of the picture and the screen appears (-, 0); setImageMatrix(matrix); } if ( <= getWidth()) { //The distance between the right border of the picture and the screen appears (getWidth() - , 0); setImageMatrix(matrix); } if ( >= 0) { //The distance between the border on the picture and the screen appears (0, -); setImageMatrix(matrix); } if ( <= getHeight()) { //The distance between the bottom boundary of the picture and the screen appears (0, getHeight() - ); setImageMatrix(matrix); } } /** * Get the midpoint of zooming when two fingers are zoomed * * @return */ private Point getMiPoint(MotionEvent event) { float x = (0) + (1); float y = (0) + (1); ((int) x / 2, (int) y / 2); return mPoint; } /** * Two-finger zoom picture */ private void changeViewSize(float oldDist, float newDist, Point mPoint) { float scale = newDist / oldDist; //Scaling (scale, scale, , ); checkBorderAndCenterWhenScale(); setImageMatrix(matrix); //Prevent it from being smaller than the initial image size when shrinking, and needs to be reset reSetMatrix(); //If the scaling is already greater than the target multiple, stop because it may have exceeded it, then directly scale to the target size if (getMatrixValueX() >= MAX_SCALE) { (MAX_SCALE/getMatrixValueX(), MAX_SCALE/getMatrixValueX(), x, y); checkBorderAndCenterWhenScale(); setImageMatrix(matrix); return; } } /** * Double-click to zoom in picture */ private void changeViewSize(MotionEvent e) { //Get the coordinates of the double-click final float x = (); final float y = (); //If it is still scaling at this time, then return directly if (animator != null && ()) return; //Judge whether it is in a state of zooming in or zooming out if (!isZoomChanged()) { animator = (1.0f, 2.0f); } else { animator = (1.0f, 0.0f); } (this); (500); (new DecelerateInterpolator()); (); (new () { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { Float value = (Float) (); (value, value, x, y); checkBorderAndCenterWhenScale(); setImageMatrix(matrix); /** * Control the narrowed range * If it is already smaller than the initial size, then return to the initial size and stop */ if (checkRestScale()) { (oldMatrix); setImageMatrix(matrix); return; } /** * Control the enlarged range * If the magnification is already greater than the target, then it is directly set to the target's magnification * Then stop */ if (getMatrixValueX() >= mDoubleClickScale) { (mDoubleClickScale/getMatrixValueX(), mDoubleClickScale/getMatrixValueX(), x, y); checkBorderAndCenterWhenScale(); setImageMatrix(matrix); return; } } }); } /** * Determine whether the zoom level has changed * * @return true means non-initial value, false means initial value */ private boolean isZoomChanged() { float[] values = new float[9]; getImageMatrix().getValues(values); //Get the current X-axis zoom level float scale = values[Matrix.MSCALE_X]; //Get the X-axis zoom level of the template and compare the two (values); return scale != values[Matrix.MSCALE_X]; } /** * Reset Matrix */ private void reSetMatrix() { if (checkRestScale()) { (oldMatrix); setImageMatrix(matrix); return; } } /** * Set the multiple of double-click to enlarge */ private void setDoubleClickScale(RectF rectF) { if(()<getHeight()-100) { mDoubleClickScale=getHeight()/(); } else mDoubleClickScale=2f; } /** * Determine whether reset is required * * @return When the current zoom level is smaller than the template zoom level, reset */ private boolean checkRestScale() { // TODO Auto-generated method stub float[] values = new float[9]; getImageMatrix().getValues(values); //Get the current X-axis zoom level float scale = values[Matrix.MSCALE_X]; //Get the X-axis zoom level of the template and compare the two (values); return scale < values[Matrix.MSCALE_X]; } private float getMatrixValueX() { // TODO Auto-generated method stub float[] values = new float[9]; getImageMatrix().getValues(values); //Get the current X-axis zoom level float scale = values[Matrix.MSCALE_X]; //Get the X-axis zoom level of the template and compare the two (values); return scale / values[Matrix.MSCALE_X]; } /** * When zooming, control the image display range */ private void checkBorderAndCenterWhenScale() { RectF rect = getMatrixRectF(); float deltaX = 0; float deltaY = 0; int width = getWidth(); int height = getHeight(); // If the width or height is larger than the screen, the control range if (() >= width) { if ( > 0) { deltaX = -; } if ( < width) { deltaX = width - ; } } if (() >= height) { if ( > 0) { deltaY = -; } if ( < height) { deltaY = height - ; } } // If the width or height is smaller than the screen, center it if (() < width) { deltaX = width * 0.5f - + 0.5f * (); } if (() < height) { deltaY = height * 0.5f - + 0.5f * (); } ("TAG", "deltaX = " + deltaX + " , deltaY = " + deltaY); (deltaX, deltaY); setImageMatrix(matrix); } /** * Get the range of images based on Matrix of the current image * * @return */ private RectF getMatrixRectF() { RectF rect = new RectF(); Drawable d = getDrawable(); if (null != d) { (0, 0, (), ()); (rect); //If there is no this, the output of the following Log will be the same as in the previous sentence. } ("aaaa",""++" "++" "++" "+); return rect; } @Override public void onGlobalLayout() { if (once) { Drawable d = getDrawable(); if (d == null) return; ("TAG", () + " , " + ()); int width = getWidth(); int height = getHeight(); // Get the width and height of the picture int dw = (); int dh = (); float scale = 1.0f; // If the width or height of the picture is greater than the screen, zoom to the width or height of the screen if (dw > width && dh <= height) { scale = width * 1.0f / dw; } if (dh > height && dw <= width) { scale = height * 1.0f / dh; } // If both width and height are larger than the screen, make it fit the screen size in proportion if (dw > width && dh > height) { scale = (width * 1.0f / dw, height * 1.0f / dh); } initScale = scale; ("TAG", "initScale = " + initScale); ((width - dw) / 2, (height - dh) / 2); (scale, scale, getWidth() / 2, getHeight() / 2); // Move the picture to the center of the screen setImageMatrix(matrix); (getImageMatrix()); once = false; RectF rectF=getMatrixRectF(); setDoubleClickScale(rectF); } } }
Alas, although I have finished writing, there is still another problem that has not been solved, that is, move the picture to the end. Don’t let go at this time. Move in the opposite direction, and there will be a problem. The opposite part of the picture is blocked and cannot be seen. Then when moving, you directly switch the picture instead of continuing to move the picture. The reason for this problem is: when you move the picture to the end, you hand over the event to the viewpager for processing. Even if you move the picture to the opposite direction, the viewPager will continue to intercept the event. No solution yet.
The above is the implementation idea of double-finger zooming pictures in viewPager, double-clicking to zoom pictures, single-finger dragging pictures, I hope it will be helpful to everyone. If you have any questions, please leave me a message and the editor will reply to everyone in time. Thank you very much for your support for my website!