Android中图像变换Matrix的原理、代码验证和应用(三)
16lz
2021-01-23
第三部分 应用
在这一部分,我们会将前面两部分所了解到的内容和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. 长按出现振动后,可以很方便地旋转图片(一个手指固定,另外一个手指围绕那个固定的手指运动)。更多相关文章
- Android 使用Glide4.9 压缩并保存图片(jpg/png/gif)到本地
- Android中ListView使用- 网络图片的异步加载
- Android带进度条的下载图片示例(AsyncTask异步任务)
- [置顶] android从图库(gallery)选择一张图片
- 【Android 内存优化】Android 工程中使用 libjpeg-turbo 压缩图
- Android中关于Volley的使用(四)利用NetworkImageView来加载图片
- Android中网络图片的异步加载
- Android拍照调用系统相册仿微信封装总结,治疗各种崩溃,图片横竖
- 【Android 工具】Android 点9图片制作及讲解