/*** * Excerpted from "Hello, Android! 3e", * published by The Pragmatic Bookshelf. * Copyrights apply to this code. It may not be used to create training material, * courses, books, articles, and the like. Contact us if you are in doubt. * We make no guarantees that this code is fit for any purpose. * Visit http://www.pragmaticprogrammer.com/titles/eband3 for more book information. ***/ package com.buuuk.android.ui.touch; import com.buuuk.android.util.Geometry; import com.thankcreate.care.BaseActivity; import android.R; import android.app.Activity; import android.graphics.Matrix; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.FloatMath; import android.util.Log; import android.view.Display; import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.WindowManager; import android.view.View.OnTouchListener; import android.widget.ImageView; public abstract class TouchActivity extends BaseActivity { private static final String TAG = "Touch"; // These matrices will be used to move and zoom image protected Matrix matrix = new Matrix(); Matrix savedMatrix = new Matrix(); // We can be in one of these 3 states static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; int mode = NONE; // Remember some things for zooming PointF start = new PointF(); PointF refLineStart = null; PointF refLineEnd = null; PointF prevLineStart = null; PointF prevLineEnd = null; PointF newStart = new PointF(); PointF newEnd = new PointF(); float oldAngle = 0f; PointF mid = new PointF(); float oldDist = 1f; Float mRotateAngle = 0f; float scaleFactor = 0f; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(getContentView()); //ImageView view = getImageView(); //view.setOnTouchListener(this); // ... // Work around a Cupcake bug matrix.setTranslate(1f, 1f); //view.setImageMatrix(matrix); } public abstract float getMinZoomScale(); public abstract void resetImage(ImageView iv, Drawable draw); public boolean onTouchEvented(View v, MotionEvent rawEvent) { WrapMotionEvent event = WrapMotionEvent.wrap(rawEvent); // ... ImageView view = (ImageView)v; // Dump touch event to log dumpEvent(event); // Handle touch events here... switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: savedMatrix.set(matrix); start.set(event.getX(), event.getY()); Log.d(TAG, "mode=DRAG"); mode = DRAG; break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); Log.d(TAG, "oldDist=" + oldDist); if (oldDist > 10f) { savedMatrix.set(matrix); midPoint(mid, event); mode = ZOOM; Log.d(TAG, "mode=ZOOM"); // set the old line if first attempt refLineStart = new PointF(); refLineEnd = new PointF(); refLineStart.set(event.getX(0), event.getY(0)); refLineEnd.set(event.getX(1), event.getY(1)); prevLineStart = new PointF(); prevLineEnd = new PointF(); prevLineStart.set(event.getX(0), event.getY(0)); prevLineEnd.set(event.getX(1), event.getY(1)); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: mode = NONE; Log.d(TAG, "mode=NONE"); refLineStart = null; refLineEnd = null; mRotateAngle = 0f; boolean isScaleChanged=true; float[] values = new float[9]; view.getImageMatrix().getValues(values); // if(values[0]<=getMinZoomScale()) { // resetImage(view,view.getDrawable()); // isScaleChanged=false; // } // TODO begin // Rect rect = new Rect(); // view.getDrawingRect(rect); // Log.d("ImageView","Drawing Rect: "+rect.top+","+rect.right+","+rect.bottom+","+rect.left); // // float[] point = new float[2]; // // //for top and left // point[0]= rect.left; // point[1]= rect.top; // float[] topleft = new float[2]; // view.getImageMatrix().mapPoints(topleft,point); // topleft image point after applying matrix // // point[0] = view.getDrawable().getIntrinsicWidth(); // point[1] = view.getDrawable().getIntrinsicHeight(); // float[] bottomright = new float[2]; // view.getImageMatrix().mapPoints(bottomright,point); //bottomright image point after applying matrix // // // // get orientation // Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay(); // int rotation = display.getRotation(); // // int orientation = 0; // if( rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) // orientation = 0; // else // orientation = 1; // // // boolean direction = true; // // float width = bottomright[0]-topleft[0]; // float height = bottomright[1]-topleft[1]; // // // if( (width>rect.right && height>rect.bottom) ) // direction=true; // else // direction=false; // // // // // snap to topright // if(topleft[0]>rect.left && bottomright[0]>rect.right && isScaleChanged && direction){ // matrix.postTranslate(-topleft[0], 0); // } // else if(bottomright[0]<rect.right && topleft[0]<rect.left && isScaleChanged && direction){ // matrix.postTranslate(rect.right-bottomright[0], 0); // } // else if(topleft[0]>rect.left && bottomright[0]>rect.right && isScaleChanged && !direction){ // matrix.postTranslate(-(bottomright[0]-rect.right), 0); // } // else if(bottomright[0]<rect.right && topleft[0]<rect.left && isScaleChanged && !direction){ // matrix.postTranslate(-(topleft[0]-rect.left), 0); // } // // // if(bottomright[1]>rect.bottom && topleft[1]>rect.top && isScaleChanged && direction){ // matrix.postTranslate(0, -topleft[1]); // } // else if(bottomright[1]<rect.bottom && topleft[1]<rect.top && isScaleChanged && direction){ // matrix.postTranslate(0, rect.bottom-bottomright[1]); // } // else if(bottomright[1]>rect.bottom && topleft[1]>rect.top && isScaleChanged && !direction){ // matrix.postTranslate(0, -(bottomright[1]-rect.bottom)); // } // else if(bottomright[1]<rect.bottom && topleft[1]<rect.top && isScaleChanged && !direction){ // matrix.postTranslate(0, -(topleft[1]-rect.top)); // } // // Log.d("ImageView", "Map points source "+point[0]+","+point[1]+ " to topleft:"+topleft[0]+","+topleft[1]+" and bottomright:"+bottomright[0]+","+bottomright[1]); // TODO END break; case MotionEvent.ACTION_MOVE: if (mode == DRAG) { // ... matrix.set(savedMatrix); float betterX = event.getX() - start.x; float[] values1 = new float[9]; view.getImageMatrix().getValues(values1); if(values1[0] == getMinZoomScale()) { betterX = 0; } matrix.postTranslate(betterX, event.getY() - start.y); } else if (mode == ZOOM) { float newDist = spacing(event); Log.d(TAG, "newDist=" + newDist); if (newDist > 10f) { matrix.set(savedMatrix); float scale = newDist / oldDist; Log.v("Scaling","Scale: "+scale); Matrix test = new Matrix(matrix); // test scale matrix test.postScale(scale, scale, mid.x, mid.y); float[] svalues = new float[9]; test.getValues(svalues); //if(svalues[0]>=getMinZoomScale()) matrix.postScale(scale, scale, mid.x, mid.y); //else // matrix.setScale(getMinZoomScale(), getMinZoomScale(), mid.x, mid.y); // get the latest line newStart.set(event.getX(0), event.getY(0)); newEnd.set(event.getX(1), event.getY(1)); float angle = new Float(angleBetweenLinesInRadians(prevLineStart,prevLineEnd,newStart,newEnd)).floatValue(); // calculate the angle difference and do rotation mRotateAngle = mRotateAngle + angle; //matrix.postRotate( mRotateAngle ,mid.x, mid.y ); // record the old line value prevLineStart.set(event.getX(0), event.getY(0)); prevLineEnd.set(event.getX(1), event.getY(1)); } } break; } Log.v("Matrix","scale matrix: "+matrix); view.setImageMatrix(matrix); // ThankCreate remove the line below //System.gc(); return true; // indicate event was handled } public double angleBetweenLinesInRadians( PointF line1Start, PointF line1End, PointF line2Start, PointF line2End) { float a = line1End.x - line1Start.x; float b = line1End.y - line1Start.y; float c = line2End.x - line2Start.x; float d = line2End.y - line2Start.y; float line1Slope = (line1End.y - line1Start.y) / (line1End.x - line1Start.x); float line2Slope = (line2End.y - line2Start.y) / (line2End.x - line2Start.x); double subf = ((a*c) + (b*d)) / ((Math.sqrt(a*a + b*b)) * (Math.sqrt(c*c + d*d))); subf = subf>1?1:subf; subf = subf<-1?-1:subf; double degs = Math.acos(subf); double result = (line2Slope > line1Slope) ? degs*180/3.142 : -degs*180/3.142; return result; } /** Show an event in the LogCat view, for debugging */ private void dumpEvent(WrapMotionEvent event) { // ... String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE", "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" }; StringBuilder sb = new StringBuilder(); int action = event.getAction(); int actionCode = action & MotionEvent.ACTION_MASK; sb.append("event ACTION_").append(names[actionCode]); if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP) { sb.append("(pid ").append( action >> MotionEvent.ACTION_POINTER_ID_SHIFT); sb.append(")"); } sb.append("["); for (int i = 0; i < event.getPointerCount(); i++) { sb.append("#").append(i); sb.append("(pid ").append(event.getPointerId(i)); sb.append(")=").append((int) event.getX(i)); sb.append(",").append((int) event.getY(i)); if (i + 1 < event.getPointerCount()) sb.append(";"); } sb.append("]"); Log.d(TAG, sb.toString()); } /** Determine the space between the first two fingers */ private float spacing(WrapMotionEvent event) { // ... float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return FloatMath.sqrt(x * x + y * y); } /** Calculate the mid point of the first two fingers */ private void midPoint(PointF point, WrapMotionEvent event) { // ... float x = event.getX(0) + event.getX(1); float y = event.getY(0) + event.getY(1); point.set(x / 2, y / 2); } }