1, enlarge and shrink freely
2. Double click Zoom in and Zoom out
3. Can be free to move after amplification
4. Handling of conflict of events with Viewpager
The points of knowledge that need to be used
1.Matrix (Image zoom in, zoom out to use matrix)
2.ScaleGestureDetector (to detect the zoom gesture when the user refers to the touch control)
3.GestureDetector: Detects some of the processing that users need to do when they double-click
4. Event distribution mechanism (when we enlarge the picture, our pictures can be moved around, viewpager around the picture, the two will have a conflict).
----------------------------------------------------Code Design
First lesson
The first step: custom ImageView to implement the picture Adaptive Control Size: (Effect: When the picture is smaller than the control size, zoom to the control size, the picture is larger than the control size, automatically shrink to the control size)
Package com.example.viewpagerimage;
Import Android.content.Context;
Import Android.graphics.Matrix;
Import android.graphics.drawable.Drawable;
Import Android.util.AttributeSet;
Import Android.view.ViewTreeObserver.OnGlobalLayoutListener;
Import Android.widget.ImageView;
Implements the listener Ongloballayoutlistener, listens for the picture to be loaded completes
public class Myimageview extends ImageView implements ongloballayoutlistener{
Private Boolean monce;//to determine whether to initialize
Private float minitscale;//The value that is scaled when initialized
Private float mmidscale;//Double click to enlarge the reached value
Private float mmaxscale;//maximum magnification
Private Matrix Mscalematrix;
Public Myimageview (context context, AttributeSet attrs, int defstyleattr) {
Super (context, attrs, defstyleattr);
Init
Mscalematrix = new Matrix ();
Setscaletype (Scaletype.matrix);
When the picture is loaded, the picture may be large, or it may be small, you need to adapt the picture to the screen size, when the picture is too large to automatically shrink to the screen size, when the picture is magnified to the screen size.
}
Public Myimageview (context context, AttributeSet Attrs) {
This is (context, attrs,0);
TODO auto-generated Constructor stub
}
Public Myimageview {
This (context,null);
TODO auto-generated Constructor stub
}
@Override
protected void Onattachedtowindow () {
TODO auto-generated Method Stub
Super.onattachedtowindow ()////When view is displayed on the screen
Getviewtreeobserver (). Addongloballayoutlistener (this);//Register interface
}
@SuppressWarnings ("deprecation")
@Override
protected void Ondetachedfromwindow () {
TODO auto-generated Method Stub
Super.ondetachedfromwindow ()///When view is removed from the screen
Getviewtreeobserver (). Removeglobalonlayoutlistener (this);//Remove interface
}
/**
* Get ImageView load complete picture
*/
@Override
public void Ongloballayout () {
Called after the global layout completes
if (!monce) {
Gets the width and height of the control
int width = getwidth ();
int height = getheight ();
Get our picture as well as the width and height
drawable d = getdrawable ();
if (d = = null)
Return
int DW = D.getintrinsicwidth ();
int dh = d.getintrinsicheight ();
Float scale = 1.0f;//scaling value
If the picture is wider than the height of the control, but the width is less than the width of the control, it shrinks
if (DW > width && dh < height) {
scale = WIDTH*1.0F/DW;
}
else if (dh > Height && DW < width) {
scale = HEIGHT*1.0F/DH;
}
else if (DW > Width && dh > height) {
Scale = Math.min (WIDTH*1.0F/DW, HEIGHT*1.0F/DH);
}
else if (DW < width && DH < height) {
Scale = math.min (width *1.0f/dw, HEIGHT*1.0F/DH);
}
/*
* ratio of scaling when initialized
* */
Minitscale = scale;
Mmaxscale = Minitscale * 4;
Mmidscale = Minitscale * 2;
Move a picture to the center of the current control
int dx = getwidth ()/2-dw/2;
int dy = getheight ()/2-dh/2;
Mscalematrix.posttranslate (dx, dy);/translate
Mscalematrix.postscale (Minitscale, MINITSCALE,WIDTH/2,HEIGHT/2);//zoom, the following two parameters are the center point of the zoom
Setimagematrix (Mscalematrix);
Monce = true;
}
}
}
Layout file Use:
<linearlayout 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= "Com.example.viewpagerimage.MainActivity" >
<com.example.viewpagerimage.myimageview
Android:layout_width= "Match_parent"
android:layout_height= "Match_parent"
Android:scaletype= "Matrix"
android:src= "@drawable/viewpatherimage"/>
</LinearLayout>
Step Two: Add the ability to support finger touch scaling for custom controls: (Support for finger touch amplification)
Because it involves gestures to touch events, we want to implement the onscalegesturelistener,ontouchlistener of these two interfaces.
Declaring a member variable: Private Scalegesturedetector mscalegesturedetector;//captures the proportion of user-controlled touch scaling
To initialize in a constructor:
Mscalegesturedetector = new Scalegesturedetector (context, this);
Setontouchlistener (this);
Add Method:
/**\
* Gets the zoom value of the current picture
* @return
*/
public float Getscale () {
Float[] values = new float[9];
Mscalematrix.getvalues (values);
return values[matrix.mscale_x];
}
Implement the methods in the interface:
//Zoom interval, Initscale maxscale
@Override
public boolean onscale (Scalegesturedetector detector) {
//TODO auto-generated method stub
float scale = Getscale ();
float Scale Factor = Detector.getscalefactor ();//The Scaled value
if (getdrawable () = null) {
return true;
// Control of the Zoom range
if (Scale < Mmaxscale && scalefactor > 1.0f) | | (Scale > Minitscale && scalefactor < 1.0f)) {
if (scale * Scalefactor < Minitscale) {
scalefactor = MInitScale/ scale;//when the finger is scaled smaller than the minimum, the default display of the minimum scale
}
if (scale * scalefactor > Mmaxscale) {/ /When the thumb is enlarged to the maximum, the default display is the maximum scale
scale = Mmaxscale/scale;
}
//scaling
mscalematrix.postscale (scalefactor, Scalefactor, GetWidth ()/2, getHeight ()/ 2);
setimagematrix (Mscalematrix);
}
return true;//Setting returns true to ensure that events can be performed
@Override
public boolean Onscalebegin (Scalegesturedetector detector) {
TODO auto-generated Method Stub
Returns true;//must return True
}
@Override
public void Onscaleend (Scalegesturedetector detector) {
TODO auto-generated Method Stub
}
@Override
public boolean Ontouch (View V, motionevent event) {
TODO auto-generated Method Stub
Mscalegesturedetector.ontouchevent (Event)//Pass the event to mscalegesturedetector for processing
Return true;//must be true
}
All the code is as follows:
Package com.example.viewpagerimage;
Import Android.content.Context;
Import Android.graphics.Matrix;
Import android.graphics.drawable.Drawable;
Import Android.util.AttributeSet;
Import android.view.MotionEvent;
Import Android.view.ScaleGestureDetector;
Import Android.view.ScaleGestureDetector.OnScaleGestureListener;
Import Android.view.View;
Import Android.view.ViewTreeObserver.OnGlobalLayoutListener;
Import Android.widget.ImageView;
Import Android.view.View.OnTouchListener;
Implements the listener Ongloballayoutlistener, listens for the picture to be loaded completes
public class Myimageview extends ImageView implements Ongloballayoutlistener, onscalegesturelistener,ontouchlistener{
Private Boolean monce;//to determine whether to initialize
Private float minitscale;//The value that is scaled when initialized
Private float mmidscale;//Double click to enlarge the reached value
Private float mmaxscale;//maximum magnification
Private Scalegesturedetector mscalegesturedetector;//captures the proportion of user-controlled touch scaling
Private Matrix Mscalematrix;
Public Myimageview (context context, AttributeSet attrs, int defstyleattr) {
Super (context, attrs, defstyleattr);
Init
Mscalematrix = new Matrix ();
Setscaletype (Scaletype.matrix);
Mscalegesturedetector = new Scalegesturedetector (context, this);
Setontouchlistener (this);
When the picture is loaded, the picture may be large, or it may be small, you need to adapt the picture to the screen size, when the picture is too large to automatically shrink to the screen size, when the picture is magnified to the screen size.
}
Public Myimageview (context context, AttributeSet Attrs) {
This is (context, attrs,0);
TODO auto-generated Constructor stub
}
Public Myimageview {
This (context,null);
TODO auto-generated Constructor stub
}
@Override
protected void Onattachedtowindow () {
TODO auto-generated Method Stub
Super.onattachedtowindow ()////When view is displayed on the screen
Getviewtreeobserver (). Addongloballayoutlistener (this);//Register interface
}
@SuppressWarnings ("deprecation")
@Override
protected void Ondetachedfromwindow () {
TODO auto-generated Method Stub
Super.ondetachedfromwindow ()///When view is removed from the screen
Getviewtreeobserver (). Removeglobalonlayoutlistener (this);//Remove interface
}
/**
* Get ImageView load complete picture
*/
@Override
public void Ongloballayout () {
Called after the global layout completes
if (!monce) {
Gets the width and height of the control
int width = getwidth ();
int height = getheight ();
Get our picture as well as the width and height
drawable d = getdrawable ();
if (d = = null)
Return
int DW = D.getintrinsicwidth ();
int dh = d.getintrinsicheight ();
Float scale = 1.0f;//scaling value
If the picture is wider than the height of the control, but the width is less than the width of the control, it shrinks
if (DW > width && dh < height) {
scale = WIDTH*1.0F/DW;
}
else if (dh > Height && DW < width) {
scale = HEIGHT*1.0F/DH;
}
else if (DW > Width && dh > height) {
Scale = Math.min (WIDTH*1.0F/DW, HEIGHT*1.0F/DH);
}
else if (DW < width && DH < height) {
Scale = math.min (width *1.0f/dw, HEIGHT*1.0F/DH);
}
/*
* ratio of scaling when initialized
* */
Minitscale = scale;
Mmaxscale = Minitscale * 4;
Mmidscale = Minitscale * 2;
Move a picture to the center of the current control
int dx = getwidth ()/2-dw/2;
int dy = getheight ()/2-dh/2;
Mscalematrix.posttranslate (dx, dy);/translate
Mscalematrix.postscale (Minitscale, MINITSCALE,WIDTH/2,HEIGHT/2);//zoom, the following two parameters are the center point of the zoom
Setimagematrix (Mscalematrix);
Monce = true;
}
}
/**\
* Gets the zoom value of the current picture
* @return
*/
public float Getscale () {
Float[] values = new float[9];
Mscalematrix.getvalues (values);
return values[matrix.mscale_x];
}
//Scale range, Initscale maxscale
@Override
public boolean Onscale (scalegesturedetector Detector) {
//TODO auto-generated method stub
float scale = Getscale ();
float scalefactor = Detector.getscalefactor ()//The Scaled value
if (getdrawable () = null) {
return true;
// Control of the Zoom range
if (Scale < Mmaxscale && scalefactor > 1.0f) | | (Scale > Minitscale && scalefactor < 1.0f)) {
if (scale * Scalefactor < Minitscale) {
scalefactor = MInitScale/ scale;//when the finger is scaled smaller than the minimum, the default display of the minimum scale
}
if (scale * scalefactor > Mmaxscale) {/ /When the thumb is enlarged to the maximum, the default display is the maximum scale
scale = Mmaxscale/scale;
}
//scaling
mscalematrix.postscale (scalefactor, Scalefactor, GetWidth ()/2, getHeight ()/ 2);
setimagematrix (Mscalematrix);
}
return true;//Setting returns true to ensure that events can be performed
@Override
public boolean Onscalebegin (Scalegesturedetector detector) {
TODO auto-generated Method Stub
Returns true;//must return True
}
@Override
public void Onscaleend (Scalegesturedetector detector) {
TODO auto-generated Method Stub
}
@Override
public boolean Ontouch (View V, motionevent event) {
TODO auto-generated Method Stub
Mscalegesturedetector.ontouchevent (Event)//Pass the event to mscalegesturedetector for processing
Return true;//must be true
}
}
The effect of the current implementation: No matter where the touch of the finger is the center of the center point to start scaling.
The effect below is to start scaling at any point that touches the finger
Lesson three (step three): support to start scaling with any point at finger touch
The key part of the scaling is the continuous boundary detection, to prevent magnification after the white edge:
/**
* Boundary Control range position control when scaling
*/
private void Checkborderandcenterwhenscale () {
TODO auto-generated Method Stub
RECTF rect = GETMATRIXRECTF ();
float deltax = 0;
float DeltaY = 0;
Float width = getwidth ();
float height = getheight ();
Border detection when zooming, on white edges
if (Rect.width () >= width) {
if (Rect.left > 0) {//processing left blank
DeltaX =-rect.left;
}
if (Rect.right < width) {//Processing right blank
DeltaX = (int) (width-rect.right);
}
}
if (rect.height () >= height) {
if (Rect.top > 0) {
DeltaY =-rect.top;
}
if (Rect.bottom < height) {
DeltaY = Height-rect.bottom;
}
}
If the width or height is less than the control's width or high, let it be centered
if (Rect.width () < width) {
DeltaX = Width/2f-rect.right + rect.width ()/2f;
}
if (Rect.height () < height) {
DeltaY = Height/2f-rect.bottom + rect.height ()/2f;
}
Mscalematrix.posttranslate (DeltaX, DeltaY);
}
All code:
Package com.example.viewpagerimage;
Import Android.content.Context;
Import Android.graphics.Matrix;
Import Android.graphics.RectF;
Import android.graphics.drawable.Drawable;
Import Android.util.AttributeSet;
Import android.view.MotionEvent;
Import Android.view.ScaleGestureDetector;
Import Android.view.ScaleGestureDetector.OnScaleGestureListener;
Import Android.view.View;
Import Android.view.View.OnTouchListener;
Import Android.view.ViewTreeObserver.OnGlobalLayoutListener;
Import Android.widget.ImageView;
Implements the listener Ongloballayoutlistener, listens for the picture to be loaded completes
public class Myimageview extends ImageView implements Ongloballayoutlistener, onscalegesturelistener,ontouchlistener{
Private Boolean monce;//to determine whether to initialize
Private float minitscale;//The value that is scaled when initialized
Private float mmidscale;//Double click to enlarge the reached value
Private float mmaxscale;//maximum magnification
Private Scalegesturedetector mscalegesturedetector;//captures the proportion of user-controlled touch scaling
Private Matrix Mscalematrix;
Public Myimageview (context context, AttributeSet attrs, int defstyleattr) {
Super (context, attrs, defstyleattr);
Init
Mscalematrix = new Matrix ();
Setscaletype (Scaletype.matrix);
Mscalegesturedetector = new Scalegesturedetector (context, this);
Setontouchlistener (this);
When the picture is loaded, the picture may be large, or it may be small, you need to adapt the picture to the screen size, when the picture is too large to automatically shrink to the screen size, when the picture is magnified to the screen size.
}
Public Myimageview (context context, AttributeSet Attrs) {
This is (context, attrs,0);
TODO auto-generated Constructor stub
}
Public Myimageview {
This (context,null);
TODO auto-generated Constructor stub
}
@Override
protected void Onattachedtowindow () {
TODO auto-generated Method Stub
Super.onattachedtowindow ()////When view is displayed on the screen
Getviewtreeobserver (). Addongloballayoutlistener (this);//Register interface
}
@SuppressWarnings ("deprecation")
@Override
protected void Ondetachedfromwindow () {
TODO auto-generated Method Stub
Super.ondetachedfromwindow ()///When view is removed from the screen
Getviewtreeobserver (). Removeglobalonlayoutlistener (this);//Remove interface
}
/**
* Get ImageView load complete picture
*/
@Override
public void Ongloballayout () {
Called after the global layout completes
if (!monce) {
Gets the width and height of the control
int width = getwidth ();
int height = getheight ();
Get our picture as well as the width and height
drawable d = getdrawable ();
if (d = = null)
Return
int DW = D.getintrinsicwidth ();
int dh = d.getintrinsicheight ();
Float scale = 1.0f;//scaling value
If the picture is wider than the height of the control, but the width is less than the width of the control, it shrinks
if (DW > width && dh < height) {
scale = WIDTH*1.0F/DW;
}
else if (dh > Height && DW < width) {
scale = HEIGHT*1.0F/DH;
}
else if (DW > Width && dh > height) {
Scale = Math.min (WIDTH*1.0F/DW, HEIGHT*1.0F/DH);
}
else if (DW < width && DH < height) {
Scale = math.min (width *1.0f/dw, HEIGHT*1.0F/DH);
}
/*
* ratio of scaling when initialized
* */
Minitscale = scale;
Mmaxscale = Minitscale * 4;
Mmidscale = Minitscale * 2;
Move a picture to the center of the current control
int dx = getwidth ()/2-dw/2;
int dy = getheight ()/2-dh/2;
Mscalematrix.posttranslate (dx, dy);/translate
Mscalematrix.postscale (Minitscale, MINITSCALE,WIDTH/2,HEIGHT/2);//zoom, the following two parameters are the center point of the zoom
Setimagematrix (Mscalematrix);
Monce = true;
}
}
/**
* Gets the zoom value of the current picture
* @return
*/
public float Getscale () {
Float[] values = new float[9];
Mscalematrix.getvalues (values);
return values[matrix.mscale_x];
}
Zoom interval, Initscale Maxscale
@Override
public boolean Onscale (Scalegesturedetector detector) {
TODO auto-generated Method Stub
Float scale = Getscale ();
float scalefactor = Detector.getscalefactor ()//The Scaled value
if (getdrawable () = null) {
return true;
}
Control of Zoom Range
if ((Scale < Mmaxscale && scalefactor > 1.0f) | | (Scale > Minitscale && scalefactor < 1.0f)) {
if (Scale * Scalefactor < Minitscale) {
Scalefactor = minitscale/scale;//The smallest proportion is displayed by default when the finger is scaled less than the minimum value
}
if (scale * scalefactor > Mmaxscale) {////When the thumb is scaled to the maximum, the default display is the maximum proportion
scale = Mmaxscale/scale;
}
Zoom, zoom Center is where the finger touches.
Mscalematrix.postscale (Scalefactor, Scalefactor, Detector.getfocusx (), detector.getfocusy ());
Checkborderandcenterwhenscale ();
Setimagematrix (Mscalematrix);
}
Return true;//set Complete returns True guarantee event can be performed
}
/**
* Get the picture zoom in and out after the width and height and l R T b
* @return
*/
Private RECTF GETMATRIXRECTF () {
Matrix matrix = Mscalematrix;
RECTF RECF = new RECTF ();
drawable d = getdrawable ();
if (d!= null) {
Recf.set (0, 0, d.getintrinsicwidth (), D.getintrinsicheight ());
Matrix.maprect (RECF);
}
return RECF;
}
/**
* Boundary Control range position control when scaling
*/
private void Checkborderandcenterwhenscale () {
TODO auto-generated Method Stub
RECTF rect = GETMATRIXRECTF ();
float deltax = 0;
float DeltaY = 0;
Float width = getwidth ();
float height = getheight ();
Border detection when zooming, on white edges
if (Rect.width () >= width) {
if (Rect.left > 0) {//processing left blank
DeltaX =-rect.left;
}
if (Rect.right < width) {//Processing right blank
DeltaX = (int) (width-rect.right);
}
}
if (rect.height () >= height) {
if (Rect.top > 0) {
DeltaY =-rect.top;
}
if (Rect.bottom < height) {
DeltaY = Height-rect.bottom;
}
}
If the width or height is less than the control's width or high, let it be centered
if (Rect.width () < width) {
DeltaX = Width/2f-rect.right + rect.width ()/2f;
}
if (Rect.height () < height) {
DeltaY = Height/2f-rect.bottom + rect.height ()/2f;
}
Mscalematrix.posttranslate (DeltaX, DeltaY);
}
@Override
public boolean Onscalebegin (Scalegesturedetector detector) {
TODO auto-generated Method Stub
Returns true;//must return True
}
@Override
public void Onscaleend (Scalegesturedetector detector) {
TODO auto-generated Method Stub
}
@Override
public boolean Ontouch (View V, motionevent event) {
TODO auto-generated Method Stub
Mscalegesturedetector.ontouchevent (Event)//Pass the event to mscalegesturedetector for processing
Return true;//must be true
}
}