Android Multi-touch technology combat, free to zoom and move pictures

Source: Internet
Author: User
Tags gety

Reprint Please specify source: http://blog.csdn.net/guolin_blog/article/details/11100327


In the previous article I took everyone together to achieve the effect of the image wall of the Android waterfall, although the effect is very cool, but in fact, it can only be considered a semi-finished, because all the pictures in the photo wall can only be seen can not point. Therefore, in this article, we will be able to perfect this function, add click on the image can browse the function of large map, and in the view of large map can also be multi-touch to zoom the picture.


If you have not seen the Android waterfall stream photo wall implementation, experience the beauty of irregular arrangement This article, please try to read the first to see this article, because this time the code is completely on the basis of the last development.


So let's start now, first open the last Photowallfallsdemo project, add a Zoomimageview class inside, this class is for large-scale display and multi-touch scaling, the code is as follows:

public class Zoomimageview extends View {/** * Initialize state constant */public static final int status_init = 1;/** * Picture magnification state constant */public s tatic Final int status_zoom_out = 2;/** * Picture reduced state constant */public static final int status_zoom_in = 3;/** * Picture Drag state constant */public St  atic final int status_move = 4;/** * Matrix for moving and zooming the image */private matrix matrix = new Matrix ();/** * Bitmap object to be displayed */private Bitmap sourcebitmap;/** * Records the status of the current operation, with an optional value of Status_init, Status_zoom_out, status_zoom_in, and status_move */private int currentstatus;/** * Zoomimageview control width */private int width;/** * Zoomimageview control height */private int height;/** * Record two fingers simultaneously on screen When the center point of the horizontal value */private float centerpointx;/** * Record two fingers simultaneously on the screen, the center of the ordinate value */private float centerpointy;/** * Record the width of the current picture, the picture is scaled, This value will change together */private float currentbitmapwidth;/** * Records the height of the current picture, and when the image is scaled, the value changes */private float currentbitmapheight;/** * Record the horizontal axis of the last finger move */private float lastxmove = -1;/** * Record the last finger movement of the ordinate */private float lastymove = -1;/** * Record the moving distance of the finger in the horizontal direction */p rivate float moveddistancex;/** * record finger in ordinateMoving distance in direction */private float moveddistancey;/** * Record the horizontal offset value of the picture on the matrix */private float totaltranslatex;/** * Record the vertical offset value of the picture on the Matrix */priva Te Float totaltranslatey;/** * Record the total scale of the picture on the matrix */private float totalratio;/** * Record the distance caused by the finger movement */private float Scaledrat io;/** * Record the scale of the image initialization */private float initratio;/** * Record the distance between the last two fingers */private double lastfingerdis;/** * Zoomimageview constructor, Sets the current operation state to Status_init. * * @param context * @param attrs */public Zoomimageview (context context, AttributeSet Attrs) {Super (context, attrs); Curr Entstatus = Status_init;} /** * Set the image to be displayed in. * * @param bitmap * Bitmap object to be displayed */public void Setimagebitmap (bitmap bitmap) {Sourcebitmap = Bitmap;invalidate ();}  @Overrideprotected void OnLayout (Boolean changed, int left, int top, int. right, int. bottom) {super.onlayout (changed, left, Top, right, bottom), if (changed) {//Get to Zoomimageview width and height, respectively = getwidth (); height = getheight ();}} @Overridepublic boolean ontouchevent (Motionevent event) {switch (event.getactionmasked ()) {case MotionEvent.ACTION_POINTER_DOWN:if (event.getpointercount () = = 2) {//when there are two finger presses on the screen, calculate the distance between the two fingers Lastfingerdis = Distancebetweenfingers (event);} Break;case MotionEvent.ACTION_MOVE:if (event.getpointercount () = = 1) {//Only one finger presses on the screen while moving, float xmove = Event.getx () for the drag state; float ymove = event.gety (); if (Lastxmove = =-1 && lastymove = = 1) {lastxmove = Xmove;lastymove = Ymove;} Currentstatus = Status_move;moveddistancex = Xmove-lastxmove;moveddistancey = ymove-lastymove;//bounds checking, does not allow the picture to be dragged out of the boundary if ( Totaltranslatex + Moveddistancex > 0) {Moveddistancex = 0;} else if (width-(Totaltranslatex + Moveddistancex) > CU Rrentbitmapwidth) {Moveddistancex = 0;} if (Totaltranslatey + Moveddistancey > 0) {moveddistancey = 0;} else if (height-(totaltranslatey + Moveddistancey) &G T Currentbitmapheight) {Moveddistancey = 0;} Call the OnDraw () method to draw the picture invalidate (); lastxmove = Xmove;lastymove = Ymove;} else if (event.getpointercount () = = 2) {//have two fingers pressed on the screen when moving, to zoom the state centerpointbetweenfingers (event);d ouble Fingerdis = Distancebetweenfingers (event), if (Fingerdis > Lastfingerdis) {currentstatus = Status_zoom_out;} else { Currentstatus = status_zoom_in;} Zoom multiple check, maximum only allow to enlarge the picture 4 times times, the smallest can be reduced to the initial scale if (Currentstatus = = Status_zoom_out && Totalratio < 4 * Initratio) | | (Currentstatus = = status_zoom_in && totalratio > Initratio)) {scaledratio = (float) (fingerdis/lastfingerdis); totalratio = Totalratio * SCALEDRATIO;IF (Totalratio > 4 * initRatio {totalratio = 4 * initratio;} else if (Totalratio < initratio) {totalratio = Initratio;} Call the OnDraw () method to draw the picture invalidate (); Lastfingerdis = Fingerdis;}} Break;case MotionEvent.ACTION_POINTER_UP:if (event.getpointercount () = = 2) {//The temporary value is restored when the finger leaves the screen lastxmove = -1;lastymove =- 1;} Break;case motionevent.action_up://The temporary value when the finger leaves the screen lastxmove = -1;lastymove = -1;break;default:break;} return true;} /** * Depending on the value of the currentstatus, determines what kind of drawing is done to the picture. */@Overrideprotected void OnDraw (canvas canvas) {super.ondraw (canvas); switch (currentstatus) {case Status_zoom_out:Case Status_zoom_in:zoom (canvas), break;case status_move:move (canvas), break;case status_init:initbitmap (canvas); Default:canvas.drawBitmap (sourcebitmap, matrix, null); break;}} /** * Zoom to the image. * * @param canvas */private void zoom (canvas canvas) {matrix.reset ();//Scales the picture by the total zoom Matrix.postscale (Totalratio, TOTALR Atio); float scaledwidth = Sourcebitmap.getwidth () * Totalratio;float scaledheight = sourcebitmap.getheight () * Totalratio;float TranslateX = 0f;float Translatey = 0f;//If the current picture width is less than the width of the screen, it is scaled horizontally by the horizontal axis of the center of the screen. Otherwise, the horizontal scale of the center point of two fingers is scaled if (Currentbitmapwidth < width) {TranslateX = (width-scaledwidth)/2f;} else {TranslateX = Totalt Ranslatex * scaledratio + centerpointx * (1-scaledratio);//boundary check to ensure that the picture is scaled in a horizontal direction without offsetting the screen if (TranslateX > 0) {Translate X = 0;} else if (Width-translatex > Scaledwidth) {TranslateX = Width-scaledwidth;}} If the current picture height is less than the screen height, it is scaled vertically by the ordinate in the center of the screen. Otherwise, the vertical scale of the center point of the two fingers is scaled if (Currentbitmapheight < height) {Translatey = (height-scaledheight)/2f;} else {Translatey = Totaltranslatey * scaledratio + centerpointy * (1-scaledratio);//boundary check to ensure that the picture is scaled in a vertical direction without offsetting the screen if (Translatey > 0) {TR Anslatey = 0;} else if (Height-translatey > Scaledheight) {translatey = Height-scaledheight;}} The image is shifted after zooming to ensure that the center point position is unchanged after zooming matrix.posttranslate (TranslateX, translatey); Totaltranslatex = TranslateX; Totaltranslatey = Translatey;currentbitmapwidth = Scaledwidth;currentbitmapheight = ScaledHeight;canvas.drawBitmap ( Sourcebitmap, matrix, null);} /** * Panning the picture * * @param canvas */private void Move (canvas canvas) {matrix.reset ();//Calculates the total offset value based on the distance the finger moves float TranslateX = Totaltranslatex + Moveddistancex;float Translatey = Totaltranslatey + moveddistancey;// The image is scaled by the existing scaling Matrix.postscale (Totalratio, Totalratio), and/or offset by the moving distance matrix.posttranslate (TranslateX, Translatey); Totaltranslatex = Translatex;totaltranslatey = Translatey;canvas.drawbitmap (sourceBitmap, matrix, null);} /** * Initialize the image, including centering the picture and compressing the picture when it is larger than the screen width. * * @param canvas */private void Initbitmap (canvasCanvas) {if (Sourcebitmap! = null) {matrix.reset (); int bitmapwidth = Sourcebitmap.getwidth (); int bitmapheight = Sourcebit Map.getheight (); if (Bitmapwidth > Width | | bitmapheight > Height) {if (Bitmapwidth-width > Bitmapheight-heigh T) {//When the picture width is larger than the screen width, compress the picture proportionally so that it can be fully displayed float ratio = width/(bitmapwidth * 1.0f); Matrix.postscale (ratio, ratio); float TR Anslatey = (Height-(bitmapheight * ratio))/2f;//offset in the ordinate direction to ensure that the picture is centered matrix.posttranslate (0, Translatey); Totaltranslatey = Translatey;totalratio = Initratio = ratio;} else {//when the picture height is greater than the screen height, compress the picture proportionally so that it can be fully displayed float ratio = height/(bitmapheight * 1.0f); Matrix.postscale (ratio, ratio); Float TranslateX = (Width-(bitmapwidth * ratio))/2f;//offset in the horizontal direction to ensure that the picture is centered matrix.posttranslate (TranslateX, 0); total TranslateX = Translatex;totalratio = Initratio = ratio;} Currentbitmapwidth = bitmapwidth * initratio;currentbitmapheight = Bitmapheight * initratio;} else {//when the width of the picture is less than the width of the screen, direct the picture to the center of float TranslateX = (width-sourcebitmap.geTwidth ())/2f;float Translatey = (height-sourcebitmap.getheight ())/2f;matrix.posttranslate (TranslateX, TranslateY); Totaltranslatex = Translatex;totaltranslatey = Translatey;totalratio = Initratio = 1f;currentbitmapwidth = BitmapWidth; Currentbitmapheight = Bitmapheight;} Canvas.drawbitmap (sourcebitmap, matrix, NULL);}} /** * Calculates the distance between two fingers. * * @param event * @return distance between two fingers */private double distancebetweenfingers (motionevent event) {Float DISX = math.abs (ev Ent.getx (0)-event.getx (1)), float Disy = Math.Abs (event.gety (0)-event.gety (1)); return math.sqrt (DISX * disx + disy * di SY);} /** * Calculates the coordinates of a center point between two fingers.  * * @param event */private void Centerpointbetweenfingers (Motionevent event) {Float xPoint0 = event.getx (0); float yPoint0 = event.gety (0); float xPoint1 = Event.getx (1); float yPoint1 = event.gety (1); Centerpointx = (xPoint0 + xPoint1)/2;center Pointy = (yPoint0 + yPoint1)/2;}}

Since this class is the core of the entire multi-touch zoom feature, I'll give you a detailed explanation here. First, in Zoomimageview we define four states, Status_init, Status_zoom_out, status_zoom_in, and Status_move, which represent the actions of initialization, amplification, narrowing, and movement, respectively, Then in the constructor we set the current state to the initialization state. Then we can call the Setimagebitmap () method to pass in the picture object to be displayed, this method will invalidate the current view, so the OnDraw () method will be executed. The OnDraw () method then determines that the current state is the initialization state, so the Initbitmap () method is called to initialize the operation.


So let's take a look at the Initbitmap () method, in this method first to determine the size of the picture, if the width and height of the picture is smaller than the width and height of the screen, then directly offset the image, so that it can be centered on the screen. If the width of the picture is greater than the width of the screen, or the height of the picture is greater than the height of the screen, the picture is compressed, so that the width or height of the picture is exactly equal to the width or height of the screen, to ensure that the initialization of the state slice must be fully displayed. All of the offsets and scaling operations are done through matrices, and we place the values that we want to scale and offset in the matrix, and then pass in the Matrix object when we draw the picture.


Once the image has been initialized, the image can be scaled. Here in the Ontouchevent () method to judge the Click event, if you find that there are two fingers pressed on the screen at the same time (using Event.getpointercount () to determine the current state is set to zoom state, and call Distancebetweenfingers () to get the distance between the two fingers to calculate the scale. Then invalidate, the zoom () method is called in the OnDraw () method. Then in this method, according to the current scale and the location of the center point of the image to scale and offset, the specific logic please read the code carefully, the comments have been written very clearly.


Then when only one finger is pressed on the screen, the current state is moved, and then the moving distance of the finger is calculated, and the work of the boundary check is processed to prevent the picture from being offset from the screen. Then invalidate the current view and enters into the OnDraw () method, where it is determined that the current is moving, and the Move () method is called. The code in the Move () method is simple enough to offset a picture based on the distance the finger moves.


After the Zoomimageview is introduced, we create a new layout image_details.xml that directly references the created Zoomimageview in the layout:

<?xml version= "1.0" encoding= "Utf-8"? ><com.example.photowallfallsdemo.zoomimageview xmlns:android= "http ://schemas.android.com/apk/res/android "    android:id=" @+id/zoom_image_view "    android:layout_width=" Match_ Parent "    android:layout_height=" match_parent "    android:background=" #000000 "></ Com.example.photowallfallsdemo.zoomimageview>
Then create an activity to load the image_details layout in this activity. To create a new imagedetailsactivity, the code looks like this:
public class Imagedetailsactivity extends Activity {private Zoomimageview zoomimageview; @Overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Requestwindowfeature (Window.feature_no_ TITLE); Setcontentview (r.layout.image_details); Zoomimageview = (Zoomimageview) Findviewbyid (R.id.zoom_image_view); String ImagePath = Getintent (). Getstringextra ("Image_path"); Bitmap Bitmap = Bitmapfactory.decodefile (ImagePath); Zoomimageview.setimagebitmap (Bitmap);}}

As you can see, first we get an instance of Zoomimageview, and then we get the picture path to show through intent, then we use bitmapfactory to load the image under the path into memory. Then call Zoomimageview's Setimagebitmap () method to pass the picture in, you can let this picture show out.


The next thing we need to consider is how to add a click event to a picture wall to enable it to start imagedetailsactivity. In fact, this is also very simple, just need to dynamically add images to each ImageView instance register a click event, modify the code of the Myscrollview in the AddImage () method, as follows:

private void AddImage (Bitmap Bitmap, int imagewidth, int imageheight) {linearlayout.layoutparams params = new LinearLayout . Layoutparams (imagewidth,imageheight); if (Mimageview! = null) {Mimageview.setimagebitmap (bitmap);} else {ImageView ImageView = new ImageView (GetContext ()); Imageview.setlayoutparams (params); Imageview.setimagebitmap (bitmap); Imageview.setscaletype (SCALETYPE.FIT_XY); Imageview.setpadding (5, 5, 5, 5); Imageview.settag (R.string.image_url, Mimageurl); Imageview.setonclicklistener (new Onclicklistener () {@Overridepublic void OnClick (View v) {Intent Intent = New Intent (GetContext (), imagedetailsactivity.class); Intent.putextra ("Image_path", Getimagepath (Mimageurl)); GetContext (). StartActivity (intent);}); Findcolumntoadd (ImageView, ImageHeight). AddView (ImageView); Imageviewlist.add (ImageView);}}

As you can see, here we call the ImageView Setonclicklistener () method to add a click event to the image, and when the user clicks on any image in the wall of the photo, it launches imagedetailsactivity and passes the path of the picture.


Since we have added a new activity, don't forget to register it in the Androidmanifest.xml file:

<?xml version= "1.0" encoding= "Utf-8"? ><manifest xmlns:android= "http://schemas.android.com/apk/res/ Android "package=" Com.example.photowallfallsdemo "android:versioncode=" 1 "android:versionname=" 1.0 "> <u SES-SDK android:minsdkversion= "android:targetsdkversion=" "/> <uses-permission android:name=" Android.permission.WRITE_EXTERNAL_STORAGE "/> <uses-permission android:name=" Android.permission.INTERNET "/ > <application android:allowbackup= "true" android:icon= "@drawable/ic_launcher" Android:label = "@string/app_name" android:theme= "@style/apptheme" > <activity android:name= "com.example.p Hotowallfallsdemo. Mainactivity "android:label=" @string/app_name "> <intent-filter> <action Android:name= "Android.intent.action.MAIN"/> <category android:name= "Android.intent.category.LAUNCHER "/> </intent-filter> </activity> <activity android:name= "Com.example.photowallfallsdemo.ImageDetailsActiv ity "> </activity> </application></manifest>

So all the coding work has been completed, and now we run the program, we will see the familiar photo wall interface, click on any one of the images will go to the corresponding large image interface, and can be multi-touch to zoom the image, zoom in can also use a single finger to move the picture, as shown in.



Well, today's explanation to this end, a friend in doubt please leave a message below.


SOURCE download, please click here


Follow my technical public number and have high-quality technical articles pushed every day. Pay attention to my entertainment public number, work, study tired time to relax yourself.

Sweep the QR code below to follow:

Android Multi-touch technology combat, free to zoom and move pictures

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.