Android UI How to - Use ScaleGestureDetector








The following code shows how to Use ScaleGestureDetector.

Code revised from
Android Recipes:A Problem-Solution Approach
http://www.apress.com/9781430234135
ISBN13: 978-1-4302-3413-5

Example

//from   www.  ja va2  s.  co m
import android.content.Context;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
import android.widget.ImageView;

import android.app.Activity;
import android.os.Bundle;

public class ImageActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        RotateZoomImageView imageView = new RotateZoomImageView(this);
        imageView.setImageResource(R.drawable.ic_launcher);
        
        setContentView(imageView);
    }
}
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;
    
    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) {
        if (w != oldw || h != oldh) {
            //Shift the image to the center of the view
            int translateX = Math.abs(w - getDrawable().getIntrinsicWidth()) / 2;
            int translateY = Math.abs(h - getDrawable().getIntrinsicHeight()) / 2;
            mImageMatrix.setTranslate(translateX, translateY);
            setImageMatrix(mImageMatrix);
            //Get the center point for future scale and rotate transforms
            mPivotX = w / 2;
            mPivotY = h / 2;
        }
    }
    
    private SimpleOnScaleGestureListener mScaleListener = new 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);
        
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //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
            
            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;
    }
    
    @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.
            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);
        }
    }
}
null