Skip to content

Instantly share code, notes, and snippets.

@ixiyang
Created July 16, 2014 02:11
Show Gist options
  • Save ixiyang/929eee69c71083ae36d9 to your computer and use it in GitHub Desktop.
Save ixiyang/929eee69c71083ae36d9 to your computer and use it in GitHub Desktop.
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