您的位置:首页 > 移动开发 > Android开发

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

2012-10-23 11:31 627 查看
第三部分 应用

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



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

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

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



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

[java] view
plaincopy

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()

{

@Override

public boolean onSingleTapUp(MotionEvent e)

{

return true;

}



@Override

public void onShowPress(MotionEvent e)

{

}



@Override

public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)

{

return true;

}



@Override

public void onLongPress(MotionEvent e)

{

long_touch = true;

vibrator = (Vibrator) context.getSystemService(Service.VIBRATOR_SERVICE);

// 振动50ms,提示后续的操作将是旋转图片,而非缩放图片

vibrator.vibrate(50);

}



@Override

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)

{

return true;

}



@Override

public 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: // 第一个手指touch

savedMatrix.set(matrix);

startPoint.set(event.getX(), event.getY());

mode = DRAG;

long_touch = false;

break;

case MotionEvent.ACTION_POINTER_DOWN: // 第二个手指touch

oldDistance = 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的代码,使之如下:

[java] view
plaincopy

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. 长按出现振动后,可以很方便地旋转图片(一个手指固定,另外一个手指围绕那个固定的手指运动)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: