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

第三部分 应用

在这一部分,我们会将前面两部分所了解到的内容和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()
		{
			@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的代码,使之如下:

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.     长按出现振动后,可以很方便地旋转图片(一个手指固定,另外一个手指围绕那个固定的手指运动)。
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值