Android中图像变换Matrix的原理、代码验证和应用(三)

来源:互联网 发布:高邮淘宝美工培训机构 编辑:程序博客网 时间:2024/05/18 01:08

第三部分 应用

在这一部分,我们会将前面两部分所了解到的内容和Android手势结合起来,利用各种不同的手势对图像进行平移、缩放和旋转,前面两项都是在实践中经常需要用到的功能,后一项据说苹果也是最近才加上的,而实际上在Android中,咱们通过自己的双手,也可以很轻松地实现之。

 

首先创建一个Android项目PatImageView,同时创建一个Activity:PatImageViewActivity。完成这一步后, 记得在AndroidManifest.xml中增加如下许可:

<uses-permissionandroid:name="android.permission.VIBRATE"/>

因为我们将要通过短按还是长按,来确定将图片到底是缩放还是旋转。

 

现在来创建一个ImageView的派生类:PatImageView,其代码(PatImageView.java)如下(2011-11-22 revised):

package com.pat.imageview;import android.app.Service;import android.content.Context;import android.graphics.Matrix;import android.graphics.PointF;import android.os.Vibrator;import android.util.FloatMath;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;import android.widget.ImageView;public class PatImageView extends ImageView{private Matrix matrix;private Matrix savedMatrix;private boolean long_touch = false;private static int NONE = 0;private static int DRAG = 1;// 拖动private static int ZOOM = 2;// 缩放private static int ROTA = 3;// 旋转private int mode = NONE;private PointF startPoint;private PointF middlePoint;private float oldDistance;private float oldAngle;private Vibrator vibrator;private GestureDetector gdetector;public PatImageView(final Context context){super(context);matrix = new Matrix();savedMatrix = new Matrix();matrix.setTranslate(0f, 0f);setScaleType(ScaleType.MATRIX);setImageMatrix(matrix);startPoint = new PointF();middlePoint = new PointF();oldDistance = 1f;gdetector = new GestureDetector(context, new GestureDetector.OnGestureListener(){@Overridepublic boolean onSingleTapUp(MotionEvent e){return true;}@Overridepublic void onShowPress(MotionEvent e){}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY){return true;}@Overridepublic void onLongPress(MotionEvent e){long_touch = true;vibrator = (Vibrator) context.getSystemService(Service.VIBRATOR_SERVICE);// 振动50ms,提示后续的操作将是旋转图片,而非缩放图片vibrator.vibrate(50);}@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY){return true;}@Overridepublic boolean onDown(MotionEvent e){return true;}});setOnTouchListener(new OnTouchListener(){public boolean onTouch(View view, MotionEvent event){switch(event.getAction() & MotionEvent.ACTION_MASK){case MotionEvent.ACTION_DOWN:// 第一个手指touchsavedMatrix.set(matrix);startPoint.set(event.getX(), event.getY());mode = DRAG;long_touch = false;break;case MotionEvent.ACTION_POINTER_DOWN:// 第二个手指toucholdDistance = getDistance(event);// 计算第二个手指touch时,两指之间的距离oldAngle = getDegree(event);// 计算第二个手指touch时,两指所形成的直线和x轴的角度if(oldDistance > 10f){savedMatrix.set(matrix);middlePoint = midPoint(event);if(!long_touch){mode = ZOOM;}else{mode = ROTA;}}break;case MotionEvent.ACTION_UP:mode = NONE;break;case MotionEvent.ACTION_POINTER_UP:mode = NONE;break;case MotionEvent.ACTION_MOVE:if(vibrator != null)vibrator.cancel();if(mode == DRAG){matrix.set(savedMatrix);matrix.postTranslate(event.getX() - startPoint.x, event.getY() - startPoint.y);}if(mode == ZOOM){float newDistance = getDistance(event);if(newDistance > 10f){matrix.set(savedMatrix);float scale = newDistance / oldDistance;matrix.postScale(scale, scale, middlePoint.x, middlePoint.y);}}if(mode == ROTA){float newAngle = getDegree(event);matrix.set(savedMatrix);float degrees = newAngle - oldAngle;matrix.postRotate(degrees, middlePoint.x, middlePoint.y);}break;}setImageMatrix(matrix);invalidate();gdetector.onTouchEvent(event);return true;}});}// 计算两个手指之间的距离    private float getDistance(MotionEvent event)    {        float x = event.getX(0) - event.getX(1);        float y = event.getY(0) - event.getY(1);        return FloatMath.sqrt(x * x + y * y);    }        // 计算两个手指所形成的直线和x轴的角度    private float getDegree(MotionEvent event)    {    return (float)(Math.atan((event.getY(1) - event.getY(0)) / (event.getX(1) - event.getX(0))) * 180f);    }    // 计算两个手指之间,中间点的坐标    private PointF midPoint( MotionEvent event)    {    PointF point = new PointF();        float x = event.getX(0) + event.getX(1);        float y = event.getY(0) + event.getY(1);        point.set(x / 2, y / 2);                return point;    }}


 

下面完善PatImageViewActivity.java的代码,使之如下:

package com.pat.imageview;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.view.Window;import android.view.WindowManager;public class PatImageViewActivity extends Activity{    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);                requestWindowFeature(Window.FEATURE_NO_TITLE);        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,         WindowManager.LayoutParams.FLAG_FULLSCREEN);                PatImageView piv = new PatImageView(this);        Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.sophie);        piv.setImageBitmap(bmp);                setContentView(piv);    }}


 

由于有些手势在模拟器上无法模拟,所以就不上运行结果的图片了。本人在真机上运行后(照片就不拍了,有点累啦),可以轻松做到:

1.     很方便地拖动图片(比如,单指按住屏幕进行拖动)

2.     很方便地缩放图片(比如,双指按住屏幕进行分开或者并拢操作,可分别实现放大或者缩小图片的功能)

3.     长按出现振动后,可以很方便地旋转图片(一个手指固定,另外一个手指围绕那个固定的手指运动)。
原创粉丝点击