Android Development Viewpager Picture preview picture zooming in zoom, move, toggle Tutorial

Source: Internet
Author: User
Tags constructor stub touch

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 () &gt;= width) {


if (Rect.left &gt; 0) {//processing left blank


DeltaX =-rect.left;


}


if (Rect.right &lt; width) {//Processing right blank


DeltaX = (int) (width-rect.right);


}


}


if (rect.height () &gt;= height) {


if (Rect.top &gt; 0) {


DeltaY =-rect.top;


}


if (Rect.bottom &lt; 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 () &lt; width) {


DeltaX = Width/2f-rect.right + rect.width ()/2f;


}


if (Rect.height () &lt; 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 () &gt;= width) {


if (Rect.left &gt; 0) {//processing left blank


DeltaX =-rect.left;


}


if (Rect.right &lt; width) {//Processing right blank


DeltaX = (int) (width-rect.right);


}


}


if (rect.height () &gt;= height) {


if (Rect.top &gt; 0) {


DeltaY =-rect.top;


}


if (Rect.bottom &lt; 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 () &lt; width) {


DeltaX = Width/2f-rect.right + rect.width ()/2f;


}


if (Rect.height () &lt; 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
}
}

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.