android实现图片缩放、移动、单击退出、双击缩放
来源:互联网 发布:电脑数据误删怎么恢复 编辑:程序博客网 时间:2024/04/30 09:48
实现思路
思路:重写用于显示图片的ImageView,定义ScaleGestureDetector(缩放手势检测)类型、GestureDetector(双击手势检测)类型的变量进行手势检测并重写方法实现图片的缩放、移动、单击退出、双击放大等功能。
重写的方法implements OnTouchListener接口,重写onTouch方法对手势进行监听
ScaleGestureDetector mScaleGestureDetector ;GestureDetector mGestureDetector;public boolean onTouch(View v, MotionEvent event){ if (mGestureDetector.onTouchEvent(event)) return true; //单双击监听 mScaleGestureDetector.onTouchEvent(event); //缩放监听 图片移动处理的code; //移动监听及处理 }
为什么单双击监听的时候检测到单双击直接就返回而不执行后面的代码?这里主要考虑到但双击的时候是自动缩放,一般我们不会在自动缩放的时候还会移动图片,但是如果是人手动考手势缩放图片,往往还会伴随着移动图片的处理,所以检测到手动缩放的代码时不返回,仍然要执行后面的移动图片的代码。
单双击处理代码:
mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener() { //单击退出 @Override public boolean onSingleTapConfirmed(MotionEvent e) { EventBus.getDefault().post(new ZoomBus()); return super.onSingleTapConfirmed(e); } //双击放大缩小 @Override public boolean onDoubleTap(MotionEvent e) { if (isAutoScale == true) //首先判断是否正在自动缩放,如果是直接返回true return true; float x = e.getX(); float y = e.getY(); Log.e("DoubleTap", getScale() + " , " + initScale); //postDelayed每16ms执行一个AutoScaleRunnable方法 if (getScale() < SCALE_MID) { ZoomImageView.this.postDelayed( new AutoScaleRunnable(SCALE_MID, x, y), 16);//如果获得的缩放比例小于SCALE_MID,那么就设置缩放比例为SCALE_MID isAutoScale = true; } else if (getScale() >= SCALE_MID && getScale() < SCALE_MAX) { ZoomImageView.this.postDelayed( new AutoScaleRunnable(SCALE_MAX, x, y), 16);//如果获得的缩放比例大于SCALE_MID并且小于SCALE_MAX,就设置缩放比例为SCALE_MAX isAutoScale = true; } else { ZoomImageView.this.postDelayed( new AutoScaleRunnable(initScale, x, y), 16);//同理 isAutoScale = true; } return true; } });/*AutoScaleRunnable()*/private class AutoScaleRunnable implements Runnable { static final float BIGGER = 1.07f; static final float SMALLER = 0.93f; private float mTargetScale; private float tmpScale; /** * 缩放的中心 */ private float x; private float y; /** * 传入目标缩放值,根据目标值与当前值,判断应该放大还是缩小 * * @param targetScale */ public AutoScaleRunnable(float targetScale, float x, float y) { this.mTargetScale = targetScale; this.x = x; this.y = y; if (getScale() < mTargetScale) { tmpScale = BIGGER; } else { tmpScale = SMALLER; } } @Override public void run() { // 进行缩放 mScaleMatrix.postScale(tmpScale, tmpScale, x, y); checkBorderAndCenterWhenScale();//如果不用,图片宽高大于屏幕时,图片与屏幕间出现白边;图片小于屏幕,但是不居中。 setImageMatrix(mScaleMatrix); final float currentScale = getScale(); // 如果值在合法范围内,继续缩放 if (((tmpScale > 1f) && (currentScale < mTargetScale)) || ((tmpScale < 1f) && (mTargetScale < currentScale))) { Log.d("合理范围",currentScale+" "+mTargetScale+" "+tmpScale); ZoomImageView.this.postDelayed(this, 16); } else // 设置为目标的缩放比例 { Log.d("目标范围","目标范围"+currentScale+" "+mTargetScale); final float deltaScale = mTargetScale / currentScale; Log.d("deltaScale",deltaScale+" "); mScaleMatrix.postScale(deltaScale, deltaScale, x, y); checkBorderAndCenterWhenScale(); setImageMatrix(mScaleMatrix); isAutoScale = false; } } }
new SimpleOnGestureListener()方法处理单击退出,这里用了EventBus,有关EventBus的使用可以搜索看一下,有handler的效果。在显示这个图片的Activity中的代码如下:
public class PictureShowActivity extends Activity { private ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_picture); EventBus.getDefault().register(this); .... @Subscribe(threadMode = ThreadMode.MAIN) public void onUserEvent(ZoomBus zoomBus) { //自己定义个ZoomBuS实体,可以是空实体 Log.d("zoomBus",zoomBus+""); finish(); }}
public boolean onDoubleTap(MotionEvent e)处理的是双击缩放,双击时首先判断当前缩放比例getScale(),然后拿当前缩放比例和initScale、SCALE_MID、SCALE_MAX进行比较以定出自动缩放的缩放比例,然后调用AutoScaleRunnable()方法,注意AutoScaleRunnable()方法进行了边界检测checkBorderAndCenterWhenScale()
手动缩放代码:
@SuppressLint("NewApi") @Override public boolean onScale(ScaleGestureDetector detector) { Log.d("scale","scale"); float scale = getScale();//当前已经缩放的缩放比例 float scaleFactor = detector.getScaleFactor();//通过手势检测检测到的缩放比例 if (getDrawable() == null) return true; /** * 缩放的范围控制 */ if ((scale < SCALE_MAX && scaleFactor > 1.0f) || (scale > initScale && scaleFactor < 1.0f)) { /** * 最大值最小值判断 */ if (scaleFactor * scale < initScale) { scaleFactor = initScale / scale; } if (scaleFactor * scale > SCALE_MAX) { scaleFactor = SCALE_MAX / scale; } /** * 设置缩放比例 */ mScaleMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY()); checkBorderAndCenterWhenScale(); setImageMatrix(mScaleMatrix); } return true; }
具体流程如下:
移动代码:(在onTouch方法里面)
float x = 0, y = 0; // 拿到触摸点的个数 final int pointerCount = event.getPointerCount(); // 得到多个触摸点的x与y均值 for (int i = 0; i < pointerCount; i++) { x += event.getX(i); y += event.getY(i); } x = x / pointerCount; y = y / pointerCount; /** * 每当触摸点发生变化时,重置mLasX , mLastY */ if (pointerCount != lastPointerCount) { isCanDrag = false; mLastX = x; mLastY = y; } lastPointerCount = pointerCount; RectF rectF = getMatrixRectF(); switch (event.getAction()) {// case MotionEvent.ACTION_DOWN:// if (rectF.width() > getWidth() || rectF.height() > getHeight())// {// getParent().requestDisallowInterceptTouchEvent(true);// }// break; case MotionEvent.ACTION_MOVE:// if (rectF.width() > getWidth() || rectF.height() > getHeight())// {// getParent().requestDisallowInterceptTouchEvent(true);// } Log.e(TAG, "ACTION_MOVE"); float dx = x - mLastX; float dy = y - mLastY; if (!isCanDrag) { isCanDrag = isCanDrag(dx, dy); } if (isCanDrag) { if (getDrawable() != null) { // if (getMatrixRectF().left == 0 && dx > 0) // { // getParent().requestDisallowInterceptTouchEvent(false); // } // // if (getMatrixRectF().right == getWidth() && dx < 0) // { // getParent().requestDisallowInterceptTouchEvent(false); // } isCheckLeftAndRight = isCheckTopAndBottom = true; // 如果宽度小于屏幕宽度,则禁止左右移动 if (rectF.width() < getWidth()) { dx = 0; isCheckLeftAndRight = false; } // 如果高度小雨屏幕高度,则禁止上下移动 if (rectF.height() < getHeight()) { dy = 0; isCheckTopAndBottom = false; } mScaleMatrix.postTranslate(dx, dy); checkMatrixBounds(); setImageMatrix(mScaleMatrix); } } mLastX = x; mLastY = y; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: Log.e(TAG, "ACTION_UP"); lastPointerCount = 0; break; } return true;
首先我们拿到触摸点的数量,然后求出多个触摸点的平均值,设置给我们的mLastX , mLastY , 然后在移动的时候,得到dx ,dy 进行范围检查以后,调用mScaleMatrix.postTranslate进行设置偏移量,设置完成以后,还需要再次校验一下,不能把图片移动的与屏幕边界出现白边,校验完成后,调用setImageMatrix.
完整demo下载
这个其实也有好多库,比如:
http://p.codekk.com/detail/Android/Dreddik/AndroidTouchGallery
- android实现图片缩放、移动、单击退出、双击缩放
- Android图片双击缩放,多点缩放,平移
- 自定义View实现仿朋友圈的图片查看器,缩放、双击、移动、回弹、下滑退出及动画等
- android实现手势缩放、移动图片
- 图片浏览器:利用UIScrollView做类似微信好友文件中的图片浏览器(缩放、单击退出、双击放大等)
- 转洋神博客android缩放平移图片预览(双击放大,单击还原)
- Android自定义ImageView实现图片缩放滑动,双击放大缩小,多点触控缩放
- 图片缩放和单击
- android——图片缩放(双击放大、手势缩放)
- android图片缩放双击旋转效果
- android-ImageView的拖动、旋转、缩放、边界回弹、双击缩放、单击销毁及源码下载
- Android单张图片查看、单指移动、双指缩放、双击最大化或最小化
- Android单张图片查看、单指移动、双指缩放、双击最大化或最小化
- Android onTouch 多点触控实现图片移动缩放
- Android 实现可以自由移动缩放的图片控件
- Android实现 通过手势随意缩放、移动ImageView图片
- Android实现 通过手势随意缩放、移动ImageView图片
- 手势状态控制图片的缩放和移动(双击放大,俩指滑动图片缩放)
- div随着鼠标移动而移动并获取鼠标坐标
- oracle常用命令
- tomcat webapp目录
- Hive创建外部表
- 300. Longest Increasing Subsequence
- android实现图片缩放、移动、单击退出、双击缩放
- Permutations II
- 进程间通信(无名管道,有名管道,共享内存)
- 24、H5新增js属性之地理信息
- android studio live templates
- mysql修改密码-忘记密码篇
- Android播放音频和视频
- vijos1049 送给圣诞夜的礼品
- 解决virtualbox不能上网