Http://www.havenliu.com/android/668.html
A company project needs to develop a software for Android cartoon reading. After reading the results, you need to slide pages, zoom in multiple points, drag and so on. However, it is not difficult to see how each effect is implemented on Android, but it is difficult to combine all the effects. After two days of research, I wrote a few results comparison, in the end, gallery was selected. However, the system's own gallery component does not support point scaling and dragging. [its default drag is paging, and I need to move the positioning image.] And when moving fast, the gallery is multiple consecutive pages, I only need to flip one page at a time. I checked some Android source code. Feel like performing the gallery and imageview again. The results are satisfactory. The performance is still good, whether it is drag, flip or point scaling is very smooth. Let's share the general idea and discuss it together if you have better improvement methods. There is a complete demo source code at the end of the article. After reading the code carefully, do not leave me a message or send an email asking me for the source code, but it is estimated that many people did not have the patience to complete the reading, and sent an email to ask me for the source code. I had to wash my ass, prepare to go to bed, and open the computer to email back ].
The following is the rewritten gallery code. The comments are basically written.
Mygallery. Java:
/*** Mygallery. Java * @ version 1.0 * @ author haven http://www.havenliu.com * @ createtime 2011-12-9 03:42:53 * sub-function of Android. widget. Gallery. This is important. We recommend that you carefully read */package COM. havenliu. demo; import android. content. context; import android. graphics. matrix; import android. graphics. rect; import android. util. attributeset; import android. util. log; import android. view. gesturedetector; import android. view. motionevent; import android. view. view; import android. view. gesturedetector. simpleongesturelistener; import android. widget. gallery; public class mygallery extends gal Lery {private gesturedetector gesturetries; private myimageview imageview; Public mygallery (context) {super (context);} public mygallery (context, attributeset attrs, int defstyle) {super (context, attrs, defstyle);} public mygallery (context, attributeset attrs) {super (context, attrs); gesturetor = new gesturedetector (New mysimplegesture (); this. setontouchlistener (New on Touchlistener () {float basevalue; float originalscale; @ overridepublic Boolean ontouch (view V, motionevent event) {view = mygallery. this. getselectedview (); If (view instanceof myimageview) {imageview = (myimageview) view; If (event. getaction () = motionevent. action_down) {basevalue = 0; originalscale = imageview. getscale ();} If (event. getaction () = motionevent. action_move) {If (event. getpointer Count () = 2) {float x = event. getx (0)-event. getx (1); float y = event. gety (0)-event. gety (1); float value = (float) math. SQRT (x * x + y * Y); // calculates the distance between two points. // system. out. println ("value:" + value); If (basevalue = 0) {basevalue = value;} else {float scale = value/basevalue; // The distance between the current two points divided by the distance between the two points when the finger falls is the proportion to be scaled. // Scale the imageimageview. zoomto (originalscale * scale, x + event. getx (1), Y + event. gety (1) ;}}}return false ;}}) ;}@ overridepublic Boolean onscroll (motionevent E1, motionevent E2, float distancex, float distancey) {view = mygallery. this. getselectedview (); If (view instanceof myimageview) {imageview = (myimageview) view; float V [] = new float [9]; matrix m = imageview. getimagematrix (); M. getva Lues (V); // the upper and lower coordinates float left and right of the image in real time; // The Real-time width, high float width, height; width = imageview of the image. getscale () * imageview. getimagewidth (); Height = imageview. getscale () * imageview. getimageheight (); // The following logic is the logic for switching between moving images and sliding gallery screens. If you do not have a clear understanding of the entire framework, think twice before modifying the following code !!!!!! If (INT) width <= Main. screenwidth & (INT) height <= Main. screenheight) // if the current image size <screen size, directly process the sliding screen event {super. onscroll (E1, E2, distancex, distancey);} else {left = V [matrix. mtrans_x]; Right = left + width; rect r = new rect (); imageview. getglobalvisiblerect (r); If (distancex> 0) // slide to the left {If (R. left> 0) {// determines whether the current imageview is completely super. onscroll (E1, E2, distancex, distancey);} else if (right <main. screenwidth) {super. onscroll (E1, E2, distancex, distancey);} else {imageview. posttranslate (-distancex,-distancey) ;}} else if (distancex <0) // slide to the right {If (R. right <main. screenwidth) {super. onscroll (E1, E2, distancex, distancey);} else if (left> 0) {super. onscroll (E1, E2, distancex, distancey);} else {imageview. posttranslate (-distancex,-distancey) ;}}} else {super. onscroll (E1, E2, distancex, distancey);} return false;} @ overridepublic Boolean onfling (motionevent E1, motionevent E2, float velocityx, float velocityy) {return false ;} @ overridepublic Boolean ontouchevent (motionevent event) {gesturetries. ontouchevent (event); Switch (event. getaction () {Case motionevent. action_up: // determine whether the upper and lower boundary is out of bounds. view = mygallery. this. getselectedview (); If (view instanceof myimageview) {imageview = (myimageview) view; float width = imageview. getscale () * imageview. getimagewidth (); float Height = imageview. getscale () * imageview. getimageheight (); If (INT) width <= Main. screenwidth & (INT) height <= Main. screenheight) // if the current image size <screen size, determine the boundary {break;} float V [] = new float [9]; matrix m = imageview. getimagematrix (); M. getvalues (V); float top = V [matrix. mtrans_y]; float Bottom = Top + height; If (top> 0) {imageview. posttranslatedur (-top, 200f);} log. I ("manga", "bottom:" + bottom); If (bottom <main. screenheight) {imageview. posttranslatedur (main. screenheight-bottom, 200f) ;}} break;} return Super. ontouchevent (event);} private class mysimplegesture extends simpleongesturelistener {// trigger public Boolean ondoubletap (motionevent e) {view = mygallery. this. getselectedview (); If (view instanceof myimageview) {imageview = (myimageview) view; If (imageview. getscale ()> imageview. getscalerate () {imageview. zoomto (imageview. getscalerate (), Main. screenwidth/2, Main. screenheight/2, 200f); // imageview. layouttocenter ();} else {imageview. zoomto (1.0f, Main. screenwidth/2, Main. screenheight/2, 200f) ;}} else {}// return Super. ondoubletap (E); Return true ;}}}
Myimageview. Java:
/*** Myimageview. java * @ version 1.0 * @ author haven http://www.havenliu.com * @ createtime 2011-12-9 03:12:30 * this class of Code is based on the Android system's built-in imageviewtouchbase code modification */package COM. havenliu. demo; import android. content. context; import android. graphics. bitmap; import android. graphics. matrix; import android. graphics. rectf; import android. OS. handler; import android. util. attributeset; import android. view. keyevent; impo RT android. widget. imageview; public class myimageview extends imageview {@ suppresswarnings ("UNUSED") Private Static final string tag = "imageviewtouchbase "; // This is the base transformation which is used to show the image // initially. the current computation for this shows the image in // It's entirety, letterboxing as needed. one cocould choose to // show the image as cropped instead. /// this matri X is recomputed when we go from the thumbnail image to // The full size image. protected matrix mbasematrix = new matrix (); // This is the supplementary transformation which reflects what // The user has done in terms of zooming and panning. /// this Matrix remains the same when we go from the thumbnail image // to the full size image. protected matrix msuppmatrix = new matrix (); // This is the final m Atrix which is computed as the concatentation // of the base matrix and the supplementary matrix. private Final matrix mdisplaymatrix = new matrix (); // temporary buffer used for getting the values out of a matrix. private Final float [] mmatrixvalues = new float [9]; // The current bitmap being displayed. // protected final rotatebitmap mbitmapdisplayed = new rotatebitmap (null); protected bitmap image = NULL; int mthiswidth =-1, mthisheight =-1; float mmaxzoom = 2.0f; // maximum zoom ratio float mminzoom; // minimum zoom ratio private int imagewidth; // The original width of the image is private int imageheight; // The original height of the image is private float scalerate; // The image scales according to the screen's scaling ratio public myimageview (context, int imagewidth, int imageheight) {super (context); this. imageheight = imageheight; this. imagewidth = imagewidth; Init ();} public myimageview (context, Attributeset attrs, int imagewidth, int imageheight) {super (context, attrs); this. imageheight = imageheight; this. imagewidth = imagewidth; Init () ;}/ *** calculate the ratio of the image to be scaled according to the screen size */private void arithscalerate () {float scalewidth = Main. screenwidth/(float) imagewidth; float scaleheight = Main. screenheight/(float) imageheight; scalerate = math. min (scalewidth, scaleheight);} public float getscalerate () {retur N scalerate;} public int getimagewidth () {return imagewidth;} public void setimagewidth (INT imagewidth) {This. imagewidth = imagewidth;} public int getimageheight () {return imageheight;} public void setimageheight (INT imageheight) {This. imageheight = imageheight;} @ overridepublic Boolean onkeydown (INT keycode, keyevent event) {If (keycode = keyevent. keycode_back & event. getrepeatcount () = 0) {EV Ent. starttracking (); Return true;} return Super. onkeydown (keycode, event) ;}@ overridepublic Boolean onkeyup (INT keycode, keyevent event) {If (keycode = keyevent. keycode_back & event. istracking ()&&! Event. iscanceled () {If (getscale ()> 1.0f) {// If We're re zoomed in, pressing back jumps out to show the // entire image, otherwise back returns the user to the gallery. zoomto (1.0f); Return true ;}} return Super. onkeyup (keycode, event);} protected handler mhandler = new handler (); @ overridepublic void setimagebitmap (Bitmap bitmap) {super. setimagebitmap (Bitmap); image = bitmap; // calculate the ratio of arithscalerate () to adapt to the screen; // zoomto (scalerate, Main. screenwidth/2f, Main. screenheight/2f); // center layouttocenter (); // imageview. zoomto (scalerate, Main. screenwidth/2, Main. screenheight/2 // center (True, true);} // center as much as possible in one or both axis. centering is // defined as follows: if the image is scaled down below the // view's dimensions then center it (literally ). if the image // is scaled larger than the view and is translated out of view // then translate it back into view (I. e. eliminate black bars ). protected void Center (Boolean horizontal, Boolean vertical) {// If (mbitmapdisplayed. getbitmap () = NULL) {// return; //} If (image = NULL) {return;} matrix m = getimageviewmatrix (); rectf rect = new rectf (0, 0, image. getwidth (), image. getheight (); // rectf rect = new rectf (0, 0, imagewidth * getscale (), imageheight * getscale (); M. maprect (rect); float Height = rect. height (); float width = rect. width (); float deltax = 0, deltay = 0; If (vertical) {int viewheight = getheight (); If (height <viewheight) {deltay = (viewheight-height) /2-rect. top;} else if (rect. top> 0) {deltay =-rect. top;} else if (rect. bottom <viewheight) {deltay = getheight ()-rect. bottom ;}}if (horizontal) {int viewwidth = getwidth (); If (width <viewwidth) {deltax = (viewwidth-width)/2-rect. left;} else if (rect. left> 0) {deltax =-rect. left;} else if (rect. right <viewwidth) {deltax = viewwidth-rect. right ;}} posttranslate (deltax, deltay); setimagematrix (getimageviewmatrix ();} private void Init () {setscaletype (imageview. scaletype. matrix);}/*** set the image center display */Public void layouttocenter () {// The actual width and height of the image being displayed float width = imagewidth * getscale (); float Height = imageheight * getscale (); // the width and height of the blank area float fill_width = Main. screenwidth-width; float fill_height = Main. screenheight-height; // float tran_width = 0f; float tran_height = 0f; If (fill_width> 0) tran_width = fill_width/2; If (fill_height> 0) tran_height = fill_height/2; posttranslate (tran_width, tran_height); setimagematrix (getimageviewmatrix ();} protected float getvalue (matrix, int whichvalue) {matrix. getvalues (mmatrixvalues); mminzoom = (main. screenwidth/2f)/imagewidth; return mmatrixvalues [whichvalue];} // get the scale factor out of the matrix. protected float getscale (matrix) {return getvalue (matrix, matrix. mscale_x);} protected float getscale () {return getscale (msuppmatrix);} // combine the base matrix and the supp matrix to make the final matrix. protected matrix getimageviewmatrix () {// The final matrix is computed as the concatentation of the base matrix // and the supplementary matrix. mdisplaymatrix. set (mbasematrix); mdisplaymatrix. postconcat (msuppmatrix); Return mdisplaymatrix;} static final float scale_rate = 1.25f; // sets the maximum zoom, which is a scale relative to the base matrix. it // is calculated to show the image at 400% zoom regardless of screen or // image orientation. if in the future we decode the full 3 megapixel image, // rather than the current 1024x768, this shoshould be changed down to 200%. protected float maxzoom () {If (image = NULL) {return 1f;} float fw = (float) image. getwidth ()/(float) mthiswidth; float FH = (float) image. getheight ()/(float) mthisheight; float max = math. max (FW, FH) * 4; return Max;} protected void zoomto (float scale, float centerx, float centery) {If (scale> mmaxzoom) {scale = mmaxzoom ;} else if (scale <mminzoom) {scale = mminzoom;} float oldscale = getscale (); float deltascale = scale/oldscale; msuppmatrix. postscale (deltascale, deltascale, centerx, centery); hour (getimageviewmatrix (); Center (True, true);} protected void zoomto (final float scale, final float centerx, final float centery, final float durationms) {final float incrementperms = (scale-getscale ()/durationms; Final float oldscale = getscale (); Final long starttime = system. currenttimemillis (); mhandler. post (New runnable () {public void run () {long now = system. currenttimemillis (); float currentms = math. min (durationms, now-starttime); float target = oldscale + (incrementperms * currentms); zoomto (target, centerx, centery); If (currentms <durationms) {mhandler. post (this) ;}}) ;}protected void zoomto (float scale) {float Cx = getwidth ()/2f; float Cy = getheight ()/2f; zoomto (scale, CX, CY);} protected void zoomtopoint (float scale, float pointx, float pointy) {float Cx = getwidth ()/2f; float Cy = getheight () /2f; panby (CX-pointx, cy-Pointy); zoomto (scale, CX, CY);} protected void zoomin () {zoomin (scale_rate );} protected void zoomout () {zoomout (scale_rate);} protected void zoomin (float rate) {If (getscale ()> = mmaxzoom) {return; // don't let the user zoom into the molecular level .} else if (getscale () <= mminzoom) {return;} If (image = NULL) {return;} float Cx = getwidth ()/2f; float Cy = getheight () /2f; msuppmatrix. postscale (rate, rate, CX, CY); setimagematrix (getimageviewmatrix ();} protected void zoomout (float rate) {If (image = NULL) {return ;} float Cx = getwidth ()/2f; float Cy = getheight ()/2f; // zoom out to at most 1x. matrix TMP = new matrix (msuppmatrix); TMP. postscale (1f/rate, 1f/rate, CX, CY); If (getscale (TMP) <1f) {msuppmatrix. setscale (1f, 1f, CX, CY);} else {msuppmatrix. postscale (1f/rate, 1f/rate, CX, CY);} setimagematrix (getimageviewmatrix (); Center (True, true);} public void posttranslate (float dx, float Dy) {msuppmatrix. posttranslate (dx, Dy); setimagematrix (getimageviewmatrix ();} float _ DY = 0.0f; protected void posttranslatedur (final float dy, final float durationms) {_ DY = 0.0f; final float incrementperms = Dy/durationms; Final long starttime = system. currenttimemillis (); mhandler. post (New runnable () {public void run () {long now = system. currenttimemillis (); float currentms = math. min (durationms, now-starttime); posttranslate (0, incrementperms * currentms-_ Dy); _ DY = incrementperms * currentms; If (currentms <durationms) {mhandler. post (this) ;}}) ;}protected void panby (float dx, float Dy) {posttranslate (dx, Dy); setimagematrix (getimageviewmatrix ());}}
Source code: click here