Android可平移缩放旋转的ImageView的实现

本文是在别人做的ImageView实现缩放,平移功能的基础上做了优化并加上了旋转功能.
一,缩放
缩放通过双击屏幕和双指移动实现.
1,双击缩放
通过GestureDetector获取双击事件

mGestureDetector = new GestureDetector(context,new GestureDetector.SimpleOnGestureListener(){
				@Override
				public boolean onDoubleTap(MotionEvent e) {
					//如果此刻正在进行自动的缓慢缩放,则禁止用户双击缩放
					if (isAutoScale){
						return true;
					}
					float x = e.getX();
					float y = e.getY();
					if (getScale() < mMidScale) {
						postDelayed(new AutoScaleRunnable(mMidScale,x,y),16);
					}
					else {
						postDelayed(new AutoScaleRunnable(mInitScale,getWidth()/2,getHeight()/2),16);
					}
					isAutoScale = true;
					return true;
				}
	双击后我们可以直接把图片缩放到指定的大小,但是为了提高用户体验,我们通过postDelayed(Runnable action, long delayMillis)
	实现过程缩放,我们看AutoScaleRunnable
//实现缓慢缩放
		private class AutoScaleRunnable implements Runnable{
			//缩放的目标比例
			private float mTargetScale;
			//缩放的中心点
			private float x;
			private float y;

			private final float BIGGER = 1.07f;
			private final float SMALLER = 0.93f;

			//临时缩放比例
			private float tempScale;
			public AutoScaleRunnable(float mTargetScale,float x,float y) {
				this.mTargetScale = mTargetScale;
				this.x = x;
				this.y = y;
				if (getScale() < mTargetScale) {
					tempScale = BIGGER;
				}
				if (getScale() > mTargetScale) {
					tempScale = SMALLER;
				}
			}
			@Override
			public void run() {
				//进行缩放
				mMatrix.postScale(tempScale,tempScale,x,y);
				checkBorderAndCenterWhenScale();
				setImageMatrix(mMatrix);

				float currentScale = getScale();
				//如果可以放大或者缩小
				if ((tempScale > 1.0f && currentScale < mTargetScale) || (tempScale < 1.0f && currentScale > mTargetScale) ){
					postDelayed(this,16);
				}
				//设置为目标缩放比例
				else {
					float scale = mTargetScale / currentScale;
					mMatrix.postScale(scale,scale,x,y);
					checkBorderAndCenterWhenScale();
					setImageMatrix(mMatrix);
					isAutoScale = false;
				}
			}
		}

1,先根据getScale()和mTargetScale判断是缩小还是放大并得到tempScale.其中BIGGER和SMALLER是指每次缩放倍数.
2,然后每次缩放tempScale倍,判断currentScale和mTargetScale,如果还可以放大或缩小,则继续postDelayed(this,16);
3,直到放大中currentScale > mTargetScale或缩小中currentScale < mTargetScale。则设置为目标缩放比例进行最后一次缩放.
每次缩放都要进行边界以及位置的控制,参看checkBorderAndCenterWhenScale()

//在缩放的时候进行边界以及位置的控制
		private void checkBorderAndCenterWhenScale() {
			RectF rectf = getMatrixRectF();
			float deltaX = 0;
			float deltaY = 0;
			int width = getWidth();
			int height = getHeight();

			//缩放时进行边界检测,防止出现留白
			if (rectf.width() >= width) {
				if (rectf.left > 0) {
					deltaX = -rectf.left;
				}
				if (rectf.right < width) {
					deltaX = width - rectf.right;
				}
			}
			if (rectf.height() >= height) {
				if (rectf.top > 0) {
					deltaY = -rectf.top;
				}
				if (rectf.bottom < height) {
					deltaY = height - rectf.bottom;
				}
			}
			//如果宽度或者高度小于控件的宽度或高度,则让其居中
			if (rectf.width() < width) {
				deltaX = width / 2f - rectf.right + rectf.width() / 2f;
			}
			if (rectf.height() < height) {
				deltaY = height / 2f - rectf.bottom + rectf.height() / 2f;
			}
			mMatrix.postTranslate(deltaX,deltaY);
		}

2,手指多点触控缩放
通过ScaleGestureDetector实现

mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.OnScaleGestureListener() {
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                //获取当前图片的缩放比例
                float scale = getScale();
                //多点触控缩放比例
                float scaleFactor = detector.getScaleFactor();
                if (getDrawable() == null){
                    return true;
                }
                //进行缩放范围的控制
                if ((scale < mMaxScale && scaleFactor > 1.0f) || (scale > mInitScale && scaleFactor < 1.0f)) {
                    if (scale * scaleFactor < mInitScale) {
                        scaleFactor = mInitScale / scale;
                    }
					if (scale * scaleFactor > mMaxScale) {
                        scaleFactor = mMaxScale / scale;
                    }
                    //缩放
                    mMatrix.postScale(scaleFactor,scaleFactor,detector.getFocusX(),detector.getFocusY());
                    //在缩放的时候进行边界以及位置的控制
                    checkBorderAndCenterWhenScale();
                    setImageMatrix(mMatrix);
                }
                return true;
            }

            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                return true;
            }

            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {

            }
        });

onScale中获取当前图片的缩放比例scale和多点触控缩放比例scaleFactor,进行缩放范围的控制后做缩放处理.
3,平移
平移要在onTouchEvent中,由于手势的优先级高,所以把mGestureDetector.onTouchEvent(event)和mScaleGestureDetector.onTouchEvent(event);
放在前面,注释比较清楚,不做详解

@Override
		public boolean onTouchEvent(MotionEvent event) {
			if (mGestureDetector.onTouchEvent(event)) {
				return true;
			}
			mScaleGestureDetector.onTouchEvent(event);

			float x = 0;
			float y = 0;
			int pointerCount = event.getPointerCount();

			//累加x和y方向的距离
			for (int i = 0; i < pointerCount; i++){
				x += event.getX(i);
				y += event.getY(i);
			}

			//获得中心点位置
			x /= pointerCount;
			y /= pointerCount;
			if (mLastPointerCount != pointerCount) {
				isCanDrag = false;
				mLastX = x;
				mLastY = y;
			}
			mLastPointerCount = pointerCount;
			RectF rectF = getMatrixRectF();
			switch (event.getAction()){
				case MotionEvent.ACTION_DOWN:
					/**
					 * 此View在ViewPager中使用时,图片放大后自由移动的事件会与
					 * ViewPager的左右切换的事件发生冲突,导致图片放大后如果左右
					 * 移动时不能自由移动图片,而是使ViewPager切换图片.这是由于事
					 * 件分发时外层的优先级比内层的高,使用下列判断可以解决
					 */
					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);
					}

					//偏移量
					float dx = x - mLastX;
					float dy = y - mLastY;

					if (!isCanDrag){
						isCanDrag = isMoveAction(dx,dy);
					}
					if (isCanDrag) {
						if (getDrawable() != null) {
							isCheckLeftAndRight = true;
							isCheckTopAndBottom = true;

							//如果宽度小于控件的宽度,不允许横向移动
							if (rectF.width() < getWidth()) {
								isCheckLeftAndRight = false;
								dx = 0;
							}

							//如果高度小于控件的高度,不允许纵向移动
							if (rectF.height() < getHeight()) {
								isCheckTopAndBottom = false;
								dy = 0;
							}

							mMatrix.postTranslate(dx,dy);
							//当自由移动时进行边界检查,防止留白
							checkBorderWhenTranslate();
							setImageMatrix(mMatrix);
						}
					}
					mLastX = x;
					mLastY = y;
					break;
				case MotionEvent.ACTION_CANCEL:
				case MotionEvent.ACTION_UP:
					mLastPointerCount = 0;
					break;
			}
			return true;
		}

4,旋转
对mMatrix做postRotate操作即可.

public void rotate(int i) {
			mMatrix.postRotate(i,getWidth()/2,getHeight()/2);
			checkBorderAndCenterWhenScale();
			setImageMatrix(mMatrix);
		}

5,getScale()方法
这个方法在多个地方调用,就是获取当前的scale
这里需要注意的是获取scale时,我们是从矩阵中获取MSCALE_X或MSCALE_Y
这里写图片描述
但旋转了以后就不能获取MSCALE_X了,如下矩阵:
0.72 0.0 -3.0517578E-5
0.0 0.72 -36.48004
0.0 0.0 1.0
旋转90°后变成这样
0.0 -0.72 1500.48
0.72 0.0 383.99997
0.0 0.0 1.0
此时我们就需要获取MSKEW_X或MSKEW_Y并取其绝对值

//获取当前图片的缩放比例
		public float getScale(){
			float[] values = new float[9];
			mMatrix.getValues(values);
			return values[Matrix.MSCALE_X]==0?Math.abs(values[Matrix.MSKEW_X]):Math.abs(values[Matrix.MSCALE_X]);
		}

代码地址:http://download.csdn.net/download/bigboysunshine/10025059

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Android平台上,可以使用一些常用的手势操作来实现图片的平移、双指缩放和双击放大缩小。 首先,为了实现平移功能,可以使用触摸事件的ACTION_MOVE来处理手指在屏幕上滑动的操作。通过计算滑动距离,可以改变图片的位置从而实现平移效果。 其次,双指缩放可以使用触摸事件的ACTION_POINTER_DOWN和ACTION_POINTER_UP来追踪并处理触摸屏幕上第二个手指按下和松开的操作。在处理时,可以通过计算两个手指触摸点之间的距离来改变图片的缩放比例,从而实现双指缩放效果。 最后,双击放大缩小可以通过设置一个双击的监听器来实现。在双击监听器的回调方法中,可以根据当前的图片缩放状态来判断是进行放大操作还是缩小操作。并根据需要更改图片的缩放比例,实现双击放大缩小功能。 在实现上述功能时,可以使用Android提供的一些核心类来辅助开发,如View、MotionEvent、GestureDetector等。同时,还可以结合自定义View和动画效果来提升用户体验,使图片的平移缩放和双击动作更加流畅和自然。 总之,通过合理运用触摸事件、手势识别、双击监听器等技术,可以在Android实现图片的平移、双指缩放和双击放大缩小功能,从而提升用户与应用程序的交互体验。 ### 回答2: 在Android开发中,可以通过使用ImageView控件来实现对图片的平移、双指缩放和双击放大缩小操作。 1. 平移:可以通过使用Matrix类对ImageView进行变换来实现图片的平移。首先,我们需要为ImageView设置一个OnTouchListener来监听用户的手势操作。在手势操作的回调方法中,可以通过获取手指按下和移动的位置差来计算出需要平移的距离,然后通过设置Matrix的平移矩阵来实现图片的平移效果。 2. 双指缩放:可以通过GestureDetector类来监听双指缩放手势。在手势操作的回调方法中,可以获取到两个手指的起始位置和当前位置,通过计算两个手指之间的距离差来判断缩放的比例。然后,再通过设置Matrix的缩放矩阵来实现图片的缩放效果。需要注意的是,在进行缩放操作时,还需要考虑到手指中心点的位置变化。 3. 双击放大缩小:也可以通过GestureDetector类来监听双击手势。在手势操作的回调方法中,可以判断是否发生了双击事件,并获取到双击的位置。当双击事件发生时,可以通过判断当前图片的缩放比例来决定是放大还是缩小。通过设置Matrix的缩放矩阵和平移矩阵来实现图片的放大缩小效果。 需要注意的是,为了实现图片的平移、双指缩放和双击放大缩小操作,我们需要对ImageView进行一系列的监听和处理操作。同时,为了方便管理和控制这些操作,可以将相关的代码封装成一个自定义的图片控件,并在该控件中进行处理。 ### 回答3: Android 提供了多种方法来实现图片的平移、双指缩放和双击放大缩小功能。 首先,要实现图片的平移,我们可以使用 GestureDetector 类。可以通过重写 onScroll() 方法来检测用户的滑动手势,然后将图片的位置进行相应的调整,从而实现平移效果。 其次,要实现双指缩放功能,我们可以借助 ScaleGestureDetector 类。通过重写 onScale() 方法,我们可以获取用户的缩放手势,并根据手势的缩放比例调整图片的尺寸,从而实现双指缩放的效果。 最后,要实现双击放大缩小功能,我们可以使用 GestureDetector 类。可以通过重写 onDoubleTap() 方法来检测用户的双击手势,然后根据当前图片的尺寸和双击事件的位置,来判断是进行放大还是缩小操作,最后将图片的尺寸进行相应的调整,实现双击放大缩小的效果。 需要注意的是,以上的功能实现是基于 Android 的原生 API,还有其他第三方库也提供了更便捷的方法来实现这些功能,例如 PhotoView 库,它提供了更多灵活的选项和交互效果,可以更加方便地实现图片的平移缩放和双击操作。 综上所述,Android 针对图片的平移、双指缩放和双击放大缩小,可以通过重写相应的手势监听方法或使用第三方库来实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值