Created
July 16, 2014 02:11
-
-
Save ixiyang/929eee69c71083ae36d9 to your computer and use it in GitHub Desktop.
use matrix(mod via https://github.com/devunwired/custom-touch-examples)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class RotateZoomImageView extends ImageView { | |
private ScaleGestureDetector mScaleDetector; | |
private Matrix mImageMatrix; | |
/* Last Rotation Angle */ | |
private int mLastAngle = 0; | |
/* Pivot Point for Transforms */ | |
private int mPivotX, mPivotY; | |
private float mStartX, mStartY; | |
public RotateZoomImageView(Context context) { | |
super(context); | |
init(context); | |
} | |
public RotateZoomImageView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
init(context); | |
} | |
public RotateZoomImageView(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
init(context); | |
} | |
private void init(Context context) { | |
mScaleDetector = new ScaleGestureDetector(context, mScaleListener); | |
setScaleType(ScaleType.MATRIX); | |
mImageMatrix = new Matrix(); | |
} | |
/* | |
* Use onSizeChanged() to calculate values based on the view's size. The | |
* view has no size during init(), so we must wait for this callback. | |
*/ | |
@Override | |
protected void onSizeChanged(int w, int h, int oldw, int oldh) { | |
System.err.println("onSizeChanged!!!!!!!"); | |
if (w != oldw || h != oldh) { | |
// Shift the image to the center of the view | |
int translateX = (w - getDrawable().getIntrinsicWidth()) / 2; | |
int translateY = (h - getDrawable().getIntrinsicHeight()) / 2; | |
// move the image to center of the view | |
mImageMatrix.setTranslate(translateX, translateY); | |
setImageMatrix(mImageMatrix); | |
// Get the center point for future scale and rotate transforms | |
mPivotX = w / 2; | |
mPivotY = h / 2; | |
} | |
} | |
private ScaleGestureDetector.SimpleOnScaleGestureListener mScaleListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() { | |
@Override | |
public boolean onScale(ScaleGestureDetector detector) { | |
// ScaleGestureDetector calculates a scale factor based on whether | |
// the fingers are moving apart or together | |
float scaleFactor = detector.getScaleFactor(); | |
// Pass that factor to a scale for the image | |
mImageMatrix.postScale(scaleFactor, scaleFactor, mPivotX, mPivotY); | |
setImageMatrix(mImageMatrix); | |
return true; | |
} | |
}; | |
/* | |
* Operate on two-finger events to rotate the image. This method calculates | |
* the change in angle between the pointers and rotates the image | |
* accordingly. As the user rotates their fingers, the image will follow. | |
*/ | |
private boolean doRotationEvent(MotionEvent event) { | |
// Calculate the angle between the two fingers | |
float deltaX = event.getX(0) - event.getX(1); | |
float deltaY = event.getY(0) - event.getY(1); | |
double radians = Math.atan(deltaY / deltaX); | |
// Convert to degrees | |
int degrees = (int) (radians * 180 / Math.PI); | |
/* | |
* Must use getActionMasked() for switching to pick up pointer events. | |
* These events have the pointer index encoded in them so the return | |
* from getAction() won't match the exact action constant. | |
*/ | |
switch (event.getActionMasked()) { | |
case MotionEvent.ACTION_DOWN: | |
case MotionEvent.ACTION_POINTER_DOWN: | |
case MotionEvent.ACTION_POINTER_UP: | |
// Mark the initial angle | |
mLastAngle = degrees; | |
break; | |
case MotionEvent.ACTION_MOVE: | |
// ATAN returns a converted value between -90deg and +90deg | |
// which creates a point when two fingers are vertical where the | |
// angle flips sign. We handle this case by rotating a small amount | |
// (5 degrees) in the direction we were traveling | |
System.err.println("lastangle===>" + mLastAngle); | |
System.err.println("degrees===>" + degrees); | |
System.err.println(); | |
if ((degrees - mLastAngle) > 45) { | |
// Going CCW across the boundary反时针 | |
mImageMatrix.postRotate(-5, mPivotX, mPivotY); | |
} else if ((degrees - mLastAngle) < -45) { | |
// Going CW across the boundary顺时针 | |
mImageMatrix.postRotate(5, mPivotX, mPivotY); | |
} else { | |
// Normal rotation, rotate the difference | |
mImageMatrix.postRotate(degrees - mLastAngle, mPivotX, | |
mPivotY); | |
} | |
// Post the rotation to the image | |
setImageMatrix(mImageMatrix); | |
// Save the current angle | |
mLastAngle = degrees; | |
break; | |
} | |
return true; | |
} | |
private boolean doTranslateEvent(MotionEvent event) { | |
switch (event.getAction()) { | |
case MotionEvent.ACTION_MOVE: | |
float dx = event.getX() - mStartX; | |
float dy = event.getY() - mStartY; | |
mImageMatrix.postTranslate(dx, dy); | |
setImageMatrix(mImageMatrix); | |
mStartX = event.getX(); | |
mStartY = event.getY(); | |
break; | |
case MotionEvent.ACTION_UP: | |
case MotionEvent.ACTION_CANCEL: | |
break; | |
default: | |
break; | |
} | |
return true; | |
} | |
@Override | |
public boolean onTouchEvent(MotionEvent event) { | |
if (event.getAction() == MotionEvent.ACTION_DOWN) { | |
// We don't care about this event directly, but we declare | |
// interest so we can get later multi-touch events. | |
mStartX = event.getX(); | |
mStartY = event.getY(); | |
return true; | |
} | |
switch (event.getPointerCount()) { | |
case 3: | |
// With three fingers down, zoom the image | |
// using the ScaleGestureDetector | |
return mScaleDetector.onTouchEvent(event); | |
case 2: | |
// With two fingers down, rotate the image | |
// following the fingers | |
return doRotationEvent(event); | |
default: | |
// Ignore this event | |
// return super.onTouchEvent(event); | |
return doTranslateEvent(event); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment