Android 自定义ImageView添加手势后,移动或缩放怎么判断越界的问题? ImageView越界判断手势拖动缩放越界处理canvas画板Android自定义ImageView 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 我先把我的源码贴出来,大神们试着帮我改下吧!拜托!import java.io.IOException;import android.annotation.SuppressLint;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.PaintFlagsDrawFilter;import android.graphics.Path;import android.graphics.PointF;import android.util.AttributeSet;import android.util.FloatMath;import android.view.MotionEvent;import android.view.View;@SuppressLint({"NewApi", "DrawAllocation" })public class CustomFourImageView extends View { private int state = -1; private final int START = 1; private Bitmap topImage; private Bitmap bottomImage; private Bitmap leftImage; private Bitmap rightImage; private Paint paint; private Matrix topMatrix; private Matrix bottomMatrix; private Matrix leftMatrix; private Matrix rightMatrix; private float padding = 14; private Path top; private Path bottom; private Path left; private Path right; /** 记录是拖拉照片模式还是放大缩小照片模式 */ private int mode = 0;// 初始状态 /** 拖拉照片模式 */ private static final int MODE_DRAG = 1; /** 放大缩小照片模式 */ private static final int MODE_ZOOM = 2; /** 用于记录开始时候的坐标位置 */ private PointF startPoint = new PointF(); /** 两个手指的开始距离 */ private float startDis; /** 两个手指的中间点 */ private PointF midPoint; private static int TYPE = 0; public CustomFourImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public CustomFourImageView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomFourImageView(Context context) { super(context); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (state > 0) { return; } state = START; init(); } /**初始化图片资源(存放于assets文件夹下)**/ private void init() { setLayerType(View.LAYER_TYPE_SOFTWARE, null);// 软件加速 try { topImage = BitmapFactory.decodeStream(getContext().getAssets() .open("m1.jpg")); bottomImage = BitmapFactory.decodeStream(getContext().getAssets() .open("m2.jpg")); leftImage = BitmapFactory.decodeStream(getContext().getAssets() .open("m3.jpg")); rightImage = BitmapFactory.decodeStream(getContext().getAssets() .open("m4.jpg")); } catch (IOException e) { e.printStackTrace(); } paint = new Paint(); paint.setAntiAlias(true); paint.setDither(true);// 防抖动 paint.setFilterBitmap(true);// 过滤 initPath(); } /**画好矩阵模块**/ private void initPath() { float cpad = padding / 2;// padding = 14 // 视图宽高 float w = getWidth(); float h = getWidth(); float bx = w / 2;//相当于中心点 float by = h / 2;//相当于中心点 top = new Path(); bottom = new Path(); left = new Path(); right = new Path(); // 上图 top.moveTo(padding, padding); top.lineTo(w -w/4-cpad, padding); top.lineTo(bx - cpad, by - cpad); top.lineTo(padding, h/4 - cpad); top.close(); // 左图 left.moveTo(padding, h/4 + cpad); left.lineTo(bx - cpad, by+cpad); left.lineTo(w/4 - cpad, h - padding); left.lineTo(padding, h - padding); left.close(); // 下图 bottom.moveTo(w/4+cpad, h-padding); bottom.lineTo(w -padding, h-padding); bottom.lineTo(w - padding, h - h/4+cpad); bottom.lineTo(bx+cpad, by+cpad); bottom.close(); // 右图 right.moveTo(w - w/4+cpad, padding); right.lineTo(w -padding, padding); right.lineTo(w - padding, h - h/4-cpad); right.lineTo(bx+cpad, by-cpad); right.close(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (topImage != null) { // 设置画板抗锯齿 PaintFlagsDrawFilter pfd = new PaintFlagsDrawFilter(0,Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); canvas.setDrawFilter(pfd); canvas.save(); canvas.clipPath(top);// 先画好模块 canvas.drawBitmap(topImage, topMatrix, paint);// 再画图 canvas.restore(); canvas.save(); canvas.clipPath(left); canvas.drawBitmap(leftImage, leftMatrix, paint); canvas.restore(); canvas.save(); canvas.clipPath(bottom); canvas.drawBitmap(bottomImage, bottomMatrix, paint); canvas.restore(); canvas.save(); canvas.clipPath(right); canvas.drawBitmap(rightImage, rightMatrix, paint); canvas.restore(); } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: // 当第一个手指按下时 mode = MODE_DRAG; if (isInsideTop(event)) { // 上图 TYPE = 1; startPoint.set(event.getX(), event.getY()); } else if (isInsideBottom(event)) { // 下图 TYPE = 2; startPoint.set(event.getX(), event.getY()); } else if (isInsideLeft(event)) { // 左图 TYPE = 3; startPoint.set(event.getX(), event.getY()); }else if(isInsideRight(event)){ // 右图 TYPE = 4; startPoint.set(event.getX(), event.getY()); } break; case MotionEvent.ACTION_MOVE: // 移动或缩放 if (mode == MODE_DRAG) {// 拖拉图片 int left = 0, top = 0, right = 0, bottom = 0; float dx = event.getX() - startPoint.x;// 减去第一次的移动距离 float dy = event.getY() - startPoint.y; startPoint.x = event.getX(); startPoint.y = event.getY(); // 在没有移动之前的位置上进行移动 getCurrentMatrix().postTranslate(dx, dy); } else if (mode == MODE_ZOOM) {// 放大缩小图片 float endDis = distance(event); // 结束距离 if (endDis > 10f) { // 两个手指并拢在一起的时候素大于10 float scale = endDis / startDis; startDis = endDis; // 得到缩放倍数进行缩放 getCurrentMatrix().postScale(scale, scale, midPoint.x, midPoint.y); } } break; case MotionEvent.ACTION_UP: // 当触点离开屏幕,但是屏幕上还有触点(手指) break; case MotionEvent.ACTION_POINTER_UP: mode = 0; break; case MotionEvent.ACTION_POINTER_DOWN: // 当屏幕上已经有触点(手指),再有一个触点压下屏幕 mode = MODE_ZOOM; startDis = distance(event); if (startDis > 10f) { // 两个手指并拢在一起的时候像素大于10 midPoint = mid(event); // 记录当前ImageView的缩放倍数 } break; } invalidate();// 重绘 return true; } /**根据TYPE值返回对应的矩阵**/ private Matrix getCurrentMatrix() { switch (TYPE) { case 1: return topMatrix; case 2: return bottomMatrix; case 3: return leftMatrix; default: return rightMatrix; } } /**计算上图的焦点区域**/ private boolean isInsideTop(MotionEvent event) { float x = event.getX(); float y = event.getY(); float w = getWidth(); return y < (-2*x + 3*w/2) && y < (x/2 + w/4); } /**计算下图的焦点区域**/ private boolean isInsideBottom(MotionEvent event) { float x = event.getX(); float y = event.getY(); float w = getWidth(); return y > (-2*x + 3*w/2) && y > (x/2 + w/4); } /**计算左图的焦点区域**/ private boolean isInsideLeft(MotionEvent event) { float x = event.getX(); float y = event.getY(); float w = getWidth(); return y < (-2*x + 3*w/2) && y > (x/2 + w/4); } /**计算右图的焦点区域**/ private boolean isInsideRight(MotionEvent event) { float x = event.getX(); float y = event.getY(); float w = getWidth(); return y > (-2*x + 3*w/2) && y < (x/2 + w/4); } /** 计算两个手指间的距离 */ private float distance(MotionEvent event) { float dx = event.getX(1) - event.getX(0); float dy = event.getY(1) - event.getY(0); //使用勾股定理返回两点之间的距离 return FloatMath.sqrt(dx * dx + dy * dy); } /** 计算两个手指间的中间点 */ private PointF mid(MotionEvent event) { float midX = (event.getX(1) + event.getX(0)) / 2; float midY = (event.getY(1) + event.getY(0)) / 2; return new PointF(midX, midY); }} 说了那么多你还没清楚,真是晕死。你把我这个源码copy一份跑起来看看,你就知道我所说的这两个问题了!帮我看看吧!哥 在init方法中加上如下四句: topMatrix = new Matrix(); bottomMatrix = new Matrix(); leftMatrix = new Matrix(); rightMatrix = new Matrix();我这里把原来的缩小图片方法删掉了,所以把初始化矩阵也删了。然后你说的那个边界问题,其实等下你试着移动图片就明白了!就是判断图片不能移出边界。还有缩小图片的时候,默认最小也要是边界大小。你看看把!我在线等你回复! 感觉楼主需要一个容器,在容器里放imageview,不要把四张图在一个imagefview里绘制出来。如果按照你现在的代码即使是实现了扩展性应该也不好的 这样更不好做吧!单独用ImageView控件,这样的怎么布局?我现在就差添加图片时的位置,和手势越界判断,就差这两个问题没解决了。 import java.io.IOException;import android.annotation.SuppressLint;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.PaintFlagsDrawFilter;import android.graphics.Path;import android.graphics.PointF;import android.util.AttributeSet;import android.util.FloatMath;import android.util.Log;import android.view.MotionEvent;import android.view.View; @SuppressLint({"NewApi", "DrawAllocation" })public class CustomFourImageView extends View { private int state = -1; private final int START = 1; private Bitmap topImage; private Bitmap bottomImage; private Bitmap leftImage; private Bitmap rightImage; private Paint paint; private Matrix topMatrix; private Matrix bottomMatrix; private Matrix leftMatrix; private Matrix rightMatrix; private float topMinScale = 1; private float bottomMinScale = 1; private float leftMinScale = 1; private float rightMinScale = 1; private float padding = 14; private Path top; private Path bottom; private Path left; private Path right; /** 记录是拖拉照片模式还是放大缩小照片模式 */ private int mode = 0;// 初始状态 /** 拖拉照片模式 */ private static final int MODE_DRAG = 1; /** 放大缩小照片模式 */ private static final int MODE_ZOOM = 2; /** 用于记录开始时候的坐标位置 */ private PointF startPoint = new PointF(); /** 两个手指的开始距离 */ private float startDis; /** 两个手指的中间点 */ private PointF midPoint; private static int TYPE = 0; public CustomFourImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public CustomFourImageView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomFourImageView(Context context) { super(context); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (state > 0) { return; } state = START; init(); initMatrix(); } /**初始化图片资源(存放于assets文件夹下)**/ private void init() { setLayerType(View.LAYER_TYPE_SOFTWARE, null);// 软件加速 try { topImage = BitmapFactory.decodeStream(getContext().getAssets() .open("clip_image.png")); bottomImage = BitmapFactory.decodeStream(getContext().getAssets() .open("down.png")); leftImage = BitmapFactory.decodeStream(getContext().getAssets() .open("shapeBackground.png")); rightImage = BitmapFactory.decodeStream(getContext().getAssets() .open("right.png")); } catch (IOException e) { } paint = new Paint(); paint.setAntiAlias(true); paint.setDither(true);// 防抖动 paint.setFilterBitmap(true);// 过滤 initPath(); } private void initMatrix(){ leftMatrix = new Matrix(); rightMatrix = new Matrix(); topMatrix = new Matrix(); bottomMatrix = new Matrix(); float w = getWidth(); float h = getHeight(); //第一个图片 float scaleX = w / leftImage.getWidth(); float scaleY = h / leftImage.getHeight(); leftMinScale = scaleX > scaleY ? scaleX : scaleY; leftMatrix.setScale(leftMinScale, leftMinScale); //第二个图片 scaleX = w / rightImage.getWidth(); scaleY = h / rightImage.getHeight(); rightMinScale = scaleX > scaleY ? scaleX : scaleY; rightMatrix.setScale(rightMinScale, rightMinScale); //第三个图片 scaleX = w / bottomImage.getWidth(); scaleY = h / bottomImage.getHeight(); bottomMinScale = scaleX > scaleY ? scaleX : scaleY; bottomMatrix.setScale(bottomMinScale, bottomMinScale); //第4个图片 scaleX = w / topImage.getWidth(); scaleY = h / topImage.getHeight(); topMinScale = scaleX > scaleY ? scaleX : scaleY; topMatrix.setScale(topMinScale, topMinScale); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: // 当第一个手指按下时 mode = MODE_DRAG; if (isInsideTop(event)) { // 上图 TYPE = 1; startPoint.set(event.getX(), event.getY()); } else if (isInsideBottom(event)) { // 下图 TYPE = 2; startPoint.set(event.getX(), event.getY()); } else if (isInsideLeft(event)) { // 左图 TYPE = 3; startPoint.set(event.getX(), event.getY()); }else if(isInsideRight(event)){ // 右图 TYPE = 4; startPoint.set(event.getX(), event.getY()); } break; case MotionEvent.ACTION_MOVE: float[] values = new float[9]; getCurrentMatrix().getValues(values); // 移动或缩放 if (mode == MODE_DRAG) {// 拖拉图片 int left = 0, top = 0, right = 0, bottom = 0; float dx = event.getX() - startPoint.x;// 减去第一次的移动距离 float dy = event.getY() - startPoint.y; startPoint.x = event.getX(); startPoint.y = event.getY(); // 在没有移动之前的位置上进行移动 Log.e("matrix ", "a: " + values[0] + " , " + values[1] + " , " + values[2]); Log.e("matrix ", "b: " + values[3] + " , " + values[4] + " , " + values[5]); Log.e("matrix ", "c: " + values[6] + " , " + values[7] + " , " + values[8]); Log.e("matrix ", "========================"); float maxW = (values[0] - getCurMinScale()) * getCurBitmap().getWidth(); float maxH = (values[0] - getCurMinScale()) * getCurBitmap().getHeight(); if(values[2] < 0 && dx + values[2] <= 0 && dx + values[2] > -maxW ){ getCurrentMatrix().postTranslate(dx, 0); } if(values[5] < 0 && dy + values[5] <= 0 && dy < 0 && dy + values[5] > -maxH){ getCurrentMatrix().postTranslate(0, dy); } } else if (mode == MODE_ZOOM) {// 放大缩小图片 float endDis = distance(event); // 结束距离 if (endDis > 10f) { // 两个手指并拢在一起的时候素大于10 float scale = endDis / startDis; startDis = endDis; float oldScale = values[0]; if(oldScale * scale > getCurMinScale()){ getCurrentMatrix().postScale(scale, scale, midPoint.x, midPoint.y); } } } break; case MotionEvent.ACTION_UP: // 当触点离开屏幕,但是屏幕上还有触点(手指) break; case MotionEvent.ACTION_POINTER_UP: mode = 0; break; case MotionEvent.ACTION_POINTER_DOWN: // 当屏幕上已经有触点(手指),再有一个触点压下屏幕 mode = MODE_ZOOM; startDis = distance(event); if (startDis > 10f) { // 两个手指并拢在一起的时候像素大于10 midPoint = mid(event); // 记录当前ImageView的缩放倍数 } break; } invalidate();// 重绘 return true; } private float getCurMinScale(){ switch (TYPE) { case 1: return topMinScale; case 2: return bottomMinScale; case 3: return leftMinScale; default: return rightMinScale; } } private Bitmap getCurBitmap(){ switch (TYPE) { case 1: return topImage; case 2: return bottomImage; case 3: return leftImage; default: return rightImage; } }}贴出的代码不全,回复有字数限制,贴出的有几个新加的方法和属性。你先试试吧,然后自己再微调下 其实你看能不能做到这样,我前面图中不是画了对应的图片容器大小嘛,就是画了各种颜色的,它就相当于是ImageView控件的大小。当图片添加进来之后,在用户没有操作放大或缩小图片的情况下,1:如果图片是横着的长方形,容器也是横着的长方形,就让图片的高缩放到跟容器的高一样,然后只可以进行左右滑动。2:如果图片是竖着的长方形,容器是竖着的长方形,就让图片的宽缩放到跟容器的宽一样,然后只可以进行上下滑动。3:相反之也一样,如果容器是横着的长方形,图片也是横着的长方形,就让图片的高缩放到跟容器的高一样,然后只可以进行左右滑动。4:相反之也一样,如果容器是竖着的长方形,图片也是竖着的长方形,就让图片的宽缩放到跟容器的宽一样,然后只可以进行上下滑动。5:只有当用户进行了缩放操作之后,才可以使图片上下左右都可以进行缩放。不知道我这样说,你有没有理解。下面有一个例图: float[] values = new float[9];getCurrentMatrix().getValues(values);这段是获取矩阵,你不用管,你只要知道 values[2]和 values[5]分别是x的位移和y的位移就行了。图片没动的时候, values[2]和 values[5]都是0。当缩放之后,图片的x和y变化了,这两个值也会变化。如下图缩放后values[2]和values[5]就变化为负值了,所以图片可以向右移动就是values[2] < 0 && dx + values[2] <= 0 这个判读了。 是的,因为初始化的时候已经进行了缩放 //第一个图片 float scaleX = w / leftImage.getWidth(); float scaleY = h / leftImage.getHeight(); leftMinScale = scaleX > scaleY ? scaleX : scaleY; leftMatrix.setScale(leftMinScale, leftMinScale);将这个改下,想以宽方向为准就用leftMinScale = scaleX,高为准就leftMinScale = scaleY 。 这个位置的我弄好了,加上这个rightMatrix.postTranslate(w/2, 0);就OK了!右图的矩阵往右偏移一半(w/2)看下图: 对了,其实我想到的就是没那么复杂,只要每条边都算一下不越界就好了,就如下图,但这个还不会搞dx是判读移动距离的:values[2] < 0 && dx + values[2] <= 0 是左边的那个情况dx + values[2] > -maxW 是右边的情况,dx和values[2]都是负值但是最多移动距离是放大后和原来宽度的差值 if (mode == MODE_DRAG) {// 拖拉图片 float dx = event.getX() - startPoint.x;// 减去第一次的移动距离 float dy = event.getY() - startPoint.y; startPoint.x = event.getX(); startPoint.y = event.getY(); // 在没有移动之前的位置上进行移动 float maxW = (values[0] - getCurMinScale()) * getCurBitmap().getWidth(); float maxH = (values[0] - getCurMinScale()) * getCurBitmap().getHeight(); if(dy > 0 && dy + values[5] < 0){ getCurrentMatrix().postTranslate(0, dy); } if(dy < 0 && dy + values[5] > -maxH){ getCurrentMatrix().postTranslate(0, dy); } if(dx > 0 && values[2] + dx < 0){ getCurrentMatrix().postTranslate(dx, 0); } if(dx < 0 && values[2] + dx > -maxW){ getCurrentMatrix().postTranslate(dx, 0); } }我加上了,这个还是不行的,太多问题了!你说的什么要减去滑动过后的距离,我想你是想错了,就比如说向右滑的时候,你不是减去向左滑动的距离嘛?这样是错的!你仔细看看下图: if (mode == MODE_DRAG) {// 拖拉图片 float dx = event.getX() - startPoint.x;// 减去第一次的移动距离 float dy = event.getY() - startPoint.y; startPoint.x = event.getX(); startPoint.y = event.getY(); // 在没有移动之前的位置上进行移动 float maxW = (values[0] - getCurMinScale()) * getCurBitmap().getWidth(); float maxH = (values[0] - getCurMinScale()) * getCurBitmap().getHeight(); if(dy > 0 && dy + values[5] < 0){ getCurrentMatrix().postTranslate(0, dy); } if(dy < 0 && dy + values[5] > -maxH){ getCurrentMatrix().postTranslate(0, dy); } if(dx > 0 && values[2] + dx < 0){ getCurrentMatrix().postTranslate(dx, 0); } if(dx < 0 && values[2] + dx > -maxW){ getCurrentMatrix().postTranslate(dx, 0); } }我加上了,这个还是不行的,太多问题了!你说的什么要减去滑动过后的距离,我想你是想错了,就比如说向右滑的时候,你不是减去向左滑动的距离嘛?这样是错的!你仔细看看下图:会向有移动吗?dx > 0 && values[2] + dx < 0会出现红色框的情况吗? 万恶的拼音啊,总是打错字。按你图画的,1向右移动产生的距离是大于0的。跟判断:dx > 0 && values[2] + dx < 0是不可能移动的,也不会出现红色框的情况。 我说的红色是图片往右移动,你先看看这3个图片的吧!从少的开始搞,这搞得我真的要疯了,怎么判断都不行。唉,气死了。@SuppressLint("NewApi")public class CustomTopImageView extends View { private int state = -1; private final int START = 1; private Bitmap topImage; private Bitmap leftImage; private Bitmap rightImage; private Paint paint; private Matrix topMatrix; private Matrix leftMatrix; private Matrix rightMatrix; private float padding = 10; private Path left; private Path right; private Path top; /** 记录是拖拉照片模式还是放大缩小照片模式 */ private int mode = 0;// 初始状态 /** 拖拉照片模式 */ private static final int MODE_DRAG = 1; /** 放大缩小照片模式 */ private static final int MODE_ZOOM = 2; /** 用于记录开始时候的坐标位置 */ private PointF startPoint = new PointF(); /** 两个手指的开始距离 */ private float startDis; /** 两个手指的中间点 */ private PointF midPoint; private static int TYPE = 0; private float topMinScale = 1; private float leftMinScale = 1; private float rightMinScale = 1; private int excessImageH=0;//图片超出矩阵部分高度; private int excessImageW = 0;//图片超出矩阵部分宽度; private float scaleX = 0; public CustomTopImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public CustomTopImageView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomTopImageView(Context context) { super(context); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (state > 0) { return; } state = START; init(); } private void init() { setLayerType(View.LAYER_TYPE_SOFTWARE, null);// 软件加速 try { leftImage = BitmapFactory.decodeStream(getContext().getAssets() .open("m1.jpg")); rightImage = BitmapFactory.decodeStream(getContext().getAssets() .open("m2.jpg")); topImage = BitmapFactory.decodeStream(getContext().getAssets() .open("m3.jpg")); } catch (IOException e) { e.printStackTrace(); } paint = new Paint(); paint.setAntiAlias(true); paint.setDither(true);// 防抖动 paint.setFilterBitmap(true);// 过滤 initMatrix();// 缩小图片 initPath(); }// // 初始化矩阵(3X3)并缩放图片// private void initMatrix() {// leftMatrix = new Matrix();// rightMatrix = new Matrix();// topMatrix = new Matrix();// float w = getWidth();// float h = getWidth();// // setImageZoom(leftMatrix,w/2,h,leftImage);// setImageZoom(rightMatrix,w/2,h,rightImage);// setImageZoom(topMatrix,w,h/2,topImage);// // rightMatrix.postTranslate(w/2, 0);//矩阵偏移// } private void initMatrix(){ leftMatrix = new Matrix(); rightMatrix = new Matrix(); topMatrix = new Matrix(); float w = getWidth(); float h = getHeight(); //第一个图片 scaleX = w / leftImage.getWidth(); float scaleY = h / leftImage.getHeight(); leftMinScale = scaleX > scaleY ? scaleX : scaleY; leftMatrix.setScale(leftMinScale, leftMinScale); //第二个图片 scaleX = w / rightImage.getWidth(); scaleY = h / rightImage.getHeight(); rightMinScale = scaleX > scaleY ? scaleX : scaleY; rightMatrix.setScale(rightMinScale, rightMinScale); //第三个图片 scaleX = w / topImage.getWidth(); scaleY = h / topImage.getHeight(); topMinScale = scaleX > scaleY ? scaleX : scaleY; topMatrix.setScale(topMinScale, topMinScale); rightMatrix.postTranslate(w/2, 0);//右图矩阵偏移 } /** * 根据矩阵的形状动态缩放图片 * @param matrix 矩阵 * @param matrixW 控件宽度 * @param matrixH 控件高度 * @param bmp 图片 */ private void setImageZoom(Matrix matrix,float matrixW,float matrixH,Bitmap bmp){ float imgW = bmp.getWidth(); float imgH = bmp.getHeight(); //得出比例 float w = matrixW/imgW; float h = matrixH/imgH; if(matrixW < matrixH){ matrix.setScale(h, h); }else{ matrix.setScale(w, w); } } // 画好矩阵模块 private void initPath() { float cpad = padding / 2;// padding = 10 // 视图宽高 float w = getWidth(); float h = getWidth(); float bx = w / 2;// float by = h / 2;// 相当于中心点 top = new Path(); left = new Path(); right = new Path(); // 上图 top.moveTo(padding * 1.7f, padding); top.lineTo(w - padding * 1.7f, padding); top.lineTo(bx, by - 0.7f * padding); top.close(); // 左图 left.moveTo(padding, padding * 1.7f); left.lineTo(bx - cpad, by + 0.2f * padding); left.lineTo(bx - cpad, h - padding); left.lineTo(padding, h - padding); left.close(); // 右图 right.moveTo(w - padding, padding * 1.7f); right.lineTo(bx + cpad, by + 0.2f * padding); right.lineTo(bx + cpad, h - padding); right.lineTo(w - padding, h - padding); right.close(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (topImage != null) { // 设置抗锯齿 PaintFlagsDrawFilter pfd = new PaintFlagsDrawFilter(0,Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); canvas.setDrawFilter(pfd); canvas.save(); canvas.clipPath(top);// 先画好模块 canvas.drawBitmap(topImage, topMatrix, paint);// 再画图 canvas.restore(); canvas.save(); canvas.clipPath(left); canvas.drawBitmap(leftImage, leftMatrix, paint); canvas.restore(); canvas.save(); canvas.clipPath(right); canvas.drawBitmap(rightImage, rightMatrix, paint); canvas.restore(); } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: // 当第一个手指按下时 mode = MODE_DRAG; if (isInsideTop(event)) { // 上图 TYPE = 1; startPoint.set(event.getX(), event.getY()); } else if (isInsideLeft(event)) { // 左图 TYPE = 2; startPoint.set(event.getX(), event.getY()); } else if (isInsideRight(event)) { // 右图 TYPE = 3; startPoint.set(event.getX(), event.getY()); } break; case MotionEvent.ACTION_MOVE: // 移动或缩放 float[] values = new float[9];//拿到矩阵中的元素 getCurrentMatrix().getValues(values);//获取图片3x3矩阵 if (mode == MODE_DRAG) {// 拖拉图片 float dx = event.getX() - startPoint.x;//减去第一次的移动距离 float dy = event.getY() - startPoint.y; startPoint.x = event.getX(); startPoint.y = event.getY(); //往上移动 if(dy < 0 && dy + values[5] > excessImageH){ getCurrentMatrix().postTranslate(0, dy); } //往下移动 if(dy > 0 && dy + values[5] < -excessImageH){ getCurrentMatrix().postTranslate(0, dy); } //往左移动 if(dx > 0 && values[2]+dx < -excessImageW){ getCurrentMatrix().postTranslate(dx, 0); } //往右移动 if(dx < 0 && values[2]+dx > excessImageW){ getCurrentMatrix().postTranslate(dx, 0); } } else if (mode == MODE_ZOOM) {// 放大缩小图片 float endDis = distance(event); // 结束距离 if (endDis > 10f) { // 两个手指并拢在一起的时候素大于10 float scale = endDis / startDis; startDis = endDis; float oldScale = values[0]; // 得到缩放倍数进行缩放 if(oldScale * scale > getCurMinScale()){ getCurrentMatrix().postScale(scale, scale, midPoint.x,midPoint.y); } } } break; case MotionEvent.ACTION_UP: // 当触点离开屏幕,但是屏幕上还有触点(手指) break; case MotionEvent.ACTION_POINTER_UP: mode = 0; break; case MotionEvent.ACTION_POINTER_DOWN: // 当屏幕上已经有触点(手指),再有一个触点压下屏幕 mode = MODE_ZOOM; startDis = distance(event); if (startDis > 10f) { // 两个手指并拢在一起的时候像素大于10 midPoint = mid(event); // 记录当前ImageView的缩放倍数 } break; } invalidate();// 重绘 return true; } /**根据TYPE值返回对应的矩阵*/ private Matrix getCurrentMatrix() { switch (TYPE) { case 1: excessImageH = (topImage.getHeight()*(int)topMinScale)-(getHeight()/2); excessImageW = (topImage.getWidth()*(int)topMinScale)-getWidth(); return topMatrix; case 2: excessImageH = (leftImage.getHeight()*(int)leftMinScale)-getHeight(); excessImageW = (leftImage.getWidth()*(int)leftMinScale)-(getWidth()/2); return leftMatrix; default: excessImageH = (rightImage.getHeight()*(int)rightMinScale)-getHeight(); excessImageW = (rightImage.getWidth()*(int)rightMinScale)-(getWidth()/2); return rightMatrix; } } /**根据TYPE值返回对应的缩放系数*/ private float getCurMinScale(){ switch (TYPE) { case 1: return topMinScale; case 2: return leftMinScale; default: return rightMinScale; } } private boolean isInsideTop(MotionEvent event) { float x = event.getX(); float y = event.getY(); float w = getWidth(); float h = getWidth(); float by = h / 2; return y < by && y < (h - h * x / w) && y < x; } private boolean isInsideLeft(MotionEvent event) { float x = event.getX(); float y = event.getY(); float w = getWidth(); float bx = w / 2; return x < bx && y > x; } private boolean isInsideRight(MotionEvent event) { float x = event.getX(); float y = event.getY(); float w = getWidth(); float h = getWidth(); float bx = w / 2; return x > bx && y > (h - h * x / w); } /** 计算两个手指间的距离 */ private float distance(MotionEvent event) { float dx = event.getX(1) - event.getX(0); float dy = event.getY(1) - event.getY(0); /** 使用勾股定理返回两点之间的距离 */ return FloatMath.sqrt(dx * dx + dy * dy); } /** 计算两个手指间的中间点 */ private PointF mid(MotionEvent event) { float midX = (event.getX(1) + event.getX(0)) / 2; float midY = (event.getY(1) + event.getY(0)) / 2; return new PointF(midX, midY); }} android如何记录用户打开各个应用的时间 新手求一个简单问题 调用webservicce 报operation timed out 异常 .apk文件在手机浏览器上如何下载 和高手探讨下Android项目的SVN管理! 关于Alarmmanager计时不准的问题 android 如何 获取当前『前台』正在运行的程序名? 类似于微信订阅号的图文消息的实现 android7.1 NTFS 支持 android 打包遇到的一个问题 ragmentActivity嵌套多个Fragment,做底部和顶部选项菜单,请前辈帮给些思路!小弟先感谢了! 这个错误昨天纠结了一天!求大神帮忙!!!
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.View;@SuppressLint({"NewApi", "DrawAllocation" })
public class CustomFourImageView extends View { private int state = -1;
private final int START = 1;
private Bitmap topImage;
private Bitmap bottomImage;
private Bitmap leftImage;
private Bitmap rightImage;
private Paint paint;
private Matrix topMatrix;
private Matrix bottomMatrix;
private Matrix leftMatrix;
private Matrix rightMatrix;
private float padding = 14;
private Path top;
private Path bottom;
private Path left;
private Path right;
/** 记录是拖拉照片模式还是放大缩小照片模式 */
private int mode = 0;// 初始状态
/** 拖拉照片模式 */
private static final int MODE_DRAG = 1;
/** 放大缩小照片模式 */
private static final int MODE_ZOOM = 2;
/** 用于记录开始时候的坐标位置 */
private PointF startPoint = new PointF();
/** 两个手指的开始距离 */
private float startDis;
/** 两个手指的中间点 */
private PointF midPoint;
private static int TYPE = 0;
public CustomFourImageView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
} public CustomFourImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomFourImageView(Context context) {
super(context);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (state > 0) {
return;
}
state = START;
init();
}
/**初始化图片资源(存放于assets文件夹下)**/
private void init() {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);// 软件加速
try {
topImage = BitmapFactory.decodeStream(getContext().getAssets()
.open("m1.jpg"));
bottomImage = BitmapFactory.decodeStream(getContext().getAssets()
.open("m2.jpg"));
leftImage = BitmapFactory.decodeStream(getContext().getAssets()
.open("m3.jpg"));
rightImage = BitmapFactory.decodeStream(getContext().getAssets()
.open("m4.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);// 防抖动
paint.setFilterBitmap(true);// 过滤
initPath();
}
/**画好矩阵模块**/
private void initPath() {
float cpad = padding / 2;// padding = 14
// 视图宽高
float w = getWidth();
float h = getWidth();
float bx = w / 2;//相当于中心点
float by = h / 2;//相当于中心点 top = new Path();
bottom = new Path();
left = new Path();
right = new Path();
// 上图
top.moveTo(padding, padding);
top.lineTo(w -w/4-cpad, padding);
top.lineTo(bx - cpad, by - cpad);
top.lineTo(padding, h/4 - cpad);
top.close();
// 左图
left.moveTo(padding, h/4 + cpad);
left.lineTo(bx - cpad, by+cpad);
left.lineTo(w/4 - cpad, h - padding);
left.lineTo(padding, h - padding);
left.close();
// 下图
bottom.moveTo(w/4+cpad, h-padding);
bottom.lineTo(w -padding, h-padding);
bottom.lineTo(w - padding, h - h/4+cpad);
bottom.lineTo(bx+cpad, by+cpad);
bottom.close();
// 右图
right.moveTo(w - w/4+cpad, padding);
right.lineTo(w -padding, padding);
right.lineTo(w - padding, h - h/4-cpad);
right.lineTo(bx+cpad, by-cpad);
right.close();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (topImage != null) {
// 设置画板抗锯齿
PaintFlagsDrawFilter pfd = new PaintFlagsDrawFilter(0,Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
canvas.setDrawFilter(pfd);
canvas.save();
canvas.clipPath(top);// 先画好模块
canvas.drawBitmap(topImage, topMatrix, paint);// 再画图
canvas.restore();
canvas.save();
canvas.clipPath(left);
canvas.drawBitmap(leftImage, leftMatrix, paint);
canvas.restore(); canvas.save();
canvas.clipPath(bottom);
canvas.drawBitmap(bottomImage, bottomMatrix, paint);
canvas.restore();
canvas.save();
canvas.clipPath(right);
canvas.drawBitmap(rightImage, rightMatrix, paint);
canvas.restore();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// 当第一个手指按下时
mode = MODE_DRAG;
if (isInsideTop(event)) {
// 上图
TYPE = 1;
startPoint.set(event.getX(), event.getY());
} else if (isInsideBottom(event)) {
// 下图
TYPE = 2;
startPoint.set(event.getX(), event.getY());
} else if (isInsideLeft(event)) {
// 左图
TYPE = 3;
startPoint.set(event.getX(), event.getY());
}else if(isInsideRight(event)){
// 右图
TYPE = 4;
startPoint.set(event.getX(), event.getY());
}
break;
case MotionEvent.ACTION_MOVE:
// 移动或缩放
if (mode == MODE_DRAG) {// 拖拉图片
int left = 0, top = 0, right = 0, bottom = 0;
float dx = event.getX() - startPoint.x;// 减去第一次的移动距离
float dy = event.getY() - startPoint.y;
startPoint.x = event.getX();
startPoint.y = event.getY();
// 在没有移动之前的位置上进行移动
getCurrentMatrix().postTranslate(dx, dy);
} else if (mode == MODE_ZOOM) {// 放大缩小图片
float endDis = distance(event);
// 结束距离
if (endDis > 10f) {
// 两个手指并拢在一起的时候素大于10
float scale = endDis / startDis;
startDis = endDis;
// 得到缩放倍数进行缩放
getCurrentMatrix().postScale(scale, scale, midPoint.x,
midPoint.y);
}
}
break;
case MotionEvent.ACTION_UP:
// 当触点离开屏幕,但是屏幕上还有触点(手指)
break;
case MotionEvent.ACTION_POINTER_UP:
mode = 0;
break;
case MotionEvent.ACTION_POINTER_DOWN:
// 当屏幕上已经有触点(手指),再有一个触点压下屏幕
mode = MODE_ZOOM;
startDis = distance(event);
if (startDis > 10f) { // 两个手指并拢在一起的时候像素大于10
midPoint = mid(event);
// 记录当前ImageView的缩放倍数
}
break;
}
invalidate();// 重绘
return true;
}
/**根据TYPE值返回对应的矩阵**/
private Matrix getCurrentMatrix() {
switch (TYPE) {
case 1:
return topMatrix;
case 2:
return bottomMatrix;
case 3:
return leftMatrix;
default:
return rightMatrix;
}
}
/**计算上图的焦点区域**/
private boolean isInsideTop(MotionEvent event) {
float x = event.getX();
float y = event.getY();
float w = getWidth();
return y < (-2*x + 3*w/2) && y < (x/2 + w/4);
} /**计算下图的焦点区域**/
private boolean isInsideBottom(MotionEvent event) {
float x = event.getX();
float y = event.getY();
float w = getWidth();
return y > (-2*x + 3*w/2) && y > (x/2 + w/4);
} /**计算左图的焦点区域**/
private boolean isInsideLeft(MotionEvent event) {
float x = event.getX();
float y = event.getY();
float w = getWidth();
return y < (-2*x + 3*w/2) && y > (x/2 + w/4);
}
/**计算右图的焦点区域**/
private boolean isInsideRight(MotionEvent event) {
float x = event.getX();
float y = event.getY();
float w = getWidth();
return y > (-2*x + 3*w/2) && y < (x/2 + w/4);
}
/** 计算两个手指间的距离 */
private float distance(MotionEvent event) {
float dx = event.getX(1) - event.getX(0);
float dy = event.getY(1) - event.getY(0);
//使用勾股定理返回两点之间的距离
return FloatMath.sqrt(dx * dx + dy * dy);
} /** 计算两个手指间的中间点 */
private PointF mid(MotionEvent event) {
float midX = (event.getX(1) + event.getX(0)) / 2;
float midY = (event.getY(1) + event.getY(0)) / 2;
return new PointF(midX, midY);
}}
说了那么多你还没清楚,真是晕死。你把我这个源码copy一份跑起来看看,你就知道我所说的这两个问题了!帮我看看吧!哥
topMatrix = new Matrix();
bottomMatrix = new Matrix();
leftMatrix = new Matrix();
rightMatrix = new Matrix();我这里把原来的缩小图片方法删掉了,所以把初始化矩阵也删了。
然后你说的那个边界问题,其实等下你试着移动图片就明白了!就是判断图片不能移出边界。还有缩小图片的时候,默认最小也要是边界大小。你看看把!我在线等你回复!
import java.io.IOException;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
@SuppressLint({"NewApi", "DrawAllocation" })
public class CustomFourImageView extends View {
private int state = -1;
private final int START = 1;
private Bitmap topImage;
private Bitmap bottomImage;
private Bitmap leftImage;
private Bitmap rightImage;
private Paint paint;
private Matrix topMatrix;
private Matrix bottomMatrix;
private Matrix leftMatrix;
private Matrix rightMatrix;
private float topMinScale = 1;
private float bottomMinScale = 1;
private float leftMinScale = 1;
private float rightMinScale = 1;
private float padding = 14;
private Path top;
private Path bottom;
private Path left;
private Path right;
/** 记录是拖拉照片模式还是放大缩小照片模式 */
private int mode = 0;// 初始状态
/** 拖拉照片模式 */
private static final int MODE_DRAG = 1;
/** 放大缩小照片模式 */
private static final int MODE_ZOOM = 2;
/** 用于记录开始时候的坐标位置 */
private PointF startPoint = new PointF();
/** 两个手指的开始距离 */
private float startDis;
/** 两个手指的中间点 */
private PointF midPoint;
private static int TYPE = 0;
public CustomFourImageView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomFourImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomFourImageView(Context context) {
super(context);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (state > 0) {
return;
}
state = START;
init();
initMatrix();
}
/**初始化图片资源(存放于assets文件夹下)**/
private void init() {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);// 软件加速
try {
topImage = BitmapFactory.decodeStream(getContext().getAssets()
.open("clip_image.png"));
bottomImage = BitmapFactory.decodeStream(getContext().getAssets()
.open("down.png"));
leftImage = BitmapFactory.decodeStream(getContext().getAssets()
.open("shapeBackground.png"));
rightImage = BitmapFactory.decodeStream(getContext().getAssets()
.open("right.png"));
} catch (IOException e) {
}
paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);// 防抖动
paint.setFilterBitmap(true);// 过滤
initPath();
}
private void initMatrix(){
leftMatrix = new Matrix();
rightMatrix = new Matrix();
topMatrix = new Matrix();
bottomMatrix = new Matrix();
float w = getWidth();
float h = getHeight();
//第一个图片
float scaleX = w / leftImage.getWidth();
float scaleY = h / leftImage.getHeight();
leftMinScale = scaleX > scaleY ? scaleX : scaleY;
leftMatrix.setScale(leftMinScale, leftMinScale);
//第二个图片
scaleX = w / rightImage.getWidth();
scaleY = h / rightImage.getHeight();
rightMinScale = scaleX > scaleY ? scaleX : scaleY;
rightMatrix.setScale(rightMinScale, rightMinScale);
//第三个图片
scaleX = w / bottomImage.getWidth();
scaleY = h / bottomImage.getHeight();
bottomMinScale = scaleX > scaleY ? scaleX : scaleY;
bottomMatrix.setScale(bottomMinScale, bottomMinScale);
//第4个图片
scaleX = w / topImage.getWidth();
scaleY = h / topImage.getHeight();
topMinScale = scaleX > scaleY ? scaleX : scaleY;
topMatrix.setScale(topMinScale, topMinScale);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// 当第一个手指按下时
mode = MODE_DRAG;
if (isInsideTop(event)) {
// 上图
TYPE = 1;
startPoint.set(event.getX(), event.getY());
} else if (isInsideBottom(event)) {
// 下图
TYPE = 2;
startPoint.set(event.getX(), event.getY());
} else if (isInsideLeft(event)) {
// 左图
TYPE = 3;
startPoint.set(event.getX(), event.getY());
}else if(isInsideRight(event)){
// 右图
TYPE = 4;
startPoint.set(event.getX(), event.getY());
}
break;
case MotionEvent.ACTION_MOVE:
float[] values = new float[9];
getCurrentMatrix().getValues(values);
// 移动或缩放
if (mode == MODE_DRAG) {// 拖拉图片
int left = 0, top = 0, right = 0, bottom = 0;
float dx = event.getX() - startPoint.x;// 减去第一次的移动距离
float dy = event.getY() - startPoint.y;
startPoint.x = event.getX();
startPoint.y = event.getY();
// 在没有移动之前的位置上进行移动
Log.e("matrix ", "a: " + values[0] + " , " + values[1] + " , " + values[2]);
Log.e("matrix ", "b: " + values[3] + " , " + values[4] + " , " + values[5]);
Log.e("matrix ", "c: " + values[6] + " , " + values[7] + " , " + values[8]);
Log.e("matrix ", "========================");
float maxW = (values[0] - getCurMinScale()) * getCurBitmap().getWidth();
float maxH = (values[0] - getCurMinScale()) * getCurBitmap().getHeight();
if(values[2] < 0 && dx + values[2] <= 0 && dx + values[2] > -maxW ){
getCurrentMatrix().postTranslate(dx, 0);
}
if(values[5] < 0 && dy + values[5] <= 0 && dy < 0 && dy + values[5] > -maxH){
getCurrentMatrix().postTranslate(0, dy);
}
} else if (mode == MODE_ZOOM) {// 放大缩小图片
float endDis = distance(event);
// 结束距离
if (endDis > 10f) {
// 两个手指并拢在一起的时候素大于10
float scale = endDis / startDis;
startDis = endDis;
float oldScale = values[0];
if(oldScale * scale > getCurMinScale()){
getCurrentMatrix().postScale(scale, scale, midPoint.x,
midPoint.y);
}
}
}
break;
case MotionEvent.ACTION_UP:
// 当触点离开屏幕,但是屏幕上还有触点(手指)
break;
case MotionEvent.ACTION_POINTER_UP:
mode = 0;
break;
case MotionEvent.ACTION_POINTER_DOWN:
// 当屏幕上已经有触点(手指),再有一个触点压下屏幕
mode = MODE_ZOOM;
startDis = distance(event);
if (startDis > 10f) { // 两个手指并拢在一起的时候像素大于10
midPoint = mid(event);
// 记录当前ImageView的缩放倍数
}
break;
}
invalidate();// 重绘
return true;
}
private float getCurMinScale(){
switch (TYPE) {
case 1:
return topMinScale;
case 2:
return bottomMinScale;
case 3:
return leftMinScale;
default:
return rightMinScale;
}
}
private Bitmap getCurBitmap(){
switch (TYPE) {
case 1:
return topImage;
case 2:
return bottomImage;
case 3:
return leftImage;
default:
return rightImage;
}
}
}贴出的代码不全,回复有字数限制,贴出的有几个新加的方法和属性。
你先试试吧,然后自己再微调下
1:如果图片是横着的长方形,容器也是横着的长方形,就让图片的高缩放到跟容器的高一样,然后只可以进行左右滑动。
2:如果图片是竖着的长方形,容器是竖着的长方形,就让图片的宽缩放到跟容器的宽一样,然后只可以进行上下滑动。
3:相反之也一样,如果容器是横着的长方形,图片也是横着的长方形,就让图片的高缩放到跟容器的高一样,然后只可以进行左右滑动。
4:相反之也一样,如果容器是竖着的长方形,图片也是竖着的长方形,就让图片的宽缩放到跟容器的宽一样,然后只可以进行上下滑动。
5:只有当用户进行了缩放操作之后,才可以使图片上下左右都可以进行缩放。不知道我这样说,你有没有理解。下面有一个例图:
getCurrentMatrix().getValues(values);
这段是获取矩阵,你不用管,你只要知道 values[2]和 values[5]分别是x的位移和y的位移就行了。
图片没动的时候, values[2]和 values[5]都是0。当缩放之后,图片的x和y变化了,这两个值也会变化。
如下图
缩放后values[2]和values[5]就变化为负值了,所以图片可以向右移动就是values[2] < 0 && dx + values[2] <= 0 这个判读了。
//第一个图片
float scaleX = w / leftImage.getWidth();
float scaleY = h / leftImage.getHeight();
leftMinScale = scaleX > scaleY ? scaleX : scaleY;
leftMatrix.setScale(leftMinScale, leftMinScale);
将这个改下,想以宽方向为准就用leftMinScale = scaleX,高为准就leftMinScale = scaleY 。
对了,其实我想到的就是没那么复杂,只要每条边都算一下不越界就好了,就如下图,但这个还不会搞
dx是判读移动距离的:
values[2] < 0 && dx + values[2] <= 0 是左边的那个情况
dx + values[2] > -maxW 是右边的情况,dx和values[2]都是负值但是最多移动距离是放大后和原来宽度的差值
if (mode == MODE_DRAG) {// 拖拉图片
float dx = event.getX() - startPoint.x;// 减去第一次的移动距离
float dy = event.getY() - startPoint.y;
startPoint.x = event.getX();
startPoint.y = event.getY();
// 在没有移动之前的位置上进行移动
float maxW = (values[0] - getCurMinScale()) * getCurBitmap().getWidth();
float maxH = (values[0] - getCurMinScale()) * getCurBitmap().getHeight();
if(dy > 0 && dy + values[5] < 0){
getCurrentMatrix().postTranslate(0, dy);
}
if(dy < 0 && dy + values[5] > -maxH){
getCurrentMatrix().postTranslate(0, dy);
}
if(dx > 0 && values[2] + dx < 0){
getCurrentMatrix().postTranslate(dx, 0);
}
if(dx < 0 && values[2] + dx > -maxW){
getCurrentMatrix().postTranslate(dx, 0);
}
}我加上了,这个还是不行的,太多问题了!你说的什么要减去滑动过后的距离,我想你是想错了,就比如说向右滑的时候,你不是减去向左滑动的距离嘛?这样是错的!你仔细看看下图:
if (mode == MODE_DRAG) {// 拖拉图片
float dx = event.getX() - startPoint.x;// 减去第一次的移动距离
float dy = event.getY() - startPoint.y;
startPoint.x = event.getX();
startPoint.y = event.getY();
// 在没有移动之前的位置上进行移动
float maxW = (values[0] - getCurMinScale()) * getCurBitmap().getWidth();
float maxH = (values[0] - getCurMinScale()) * getCurBitmap().getHeight();
if(dy > 0 && dy + values[5] < 0){
getCurrentMatrix().postTranslate(0, dy);
}
if(dy < 0 && dy + values[5] > -maxH){
getCurrentMatrix().postTranslate(0, dy);
}
if(dx > 0 && values[2] + dx < 0){
getCurrentMatrix().postTranslate(dx, 0);
}
if(dx < 0 && values[2] + dx > -maxW){
getCurrentMatrix().postTranslate(dx, 0);
}
}我加上了,这个还是不行的,太多问题了!你说的什么要减去滑动过后的距离,我想你是想错了,就比如说向右滑的时候,你不是减去向左滑动的距离嘛?这样是错的!你仔细看看下图:
会向有移动吗?
dx > 0 && values[2] + dx < 0会出现红色框的情况吗?
按你图画的,1向右移动产生的距离是大于0的。
跟判断:
dx > 0 && values[2] + dx < 0
是不可能移动的,也不会出现红色框的情况。
public class CustomTopImageView extends View { private int state = -1;
private final int START = 1; private Bitmap topImage;
private Bitmap leftImage;
private Bitmap rightImage; private Paint paint;
private Matrix topMatrix;
private Matrix leftMatrix;
private Matrix rightMatrix; private float padding = 10;
private Path left;
private Path right;
private Path top; /** 记录是拖拉照片模式还是放大缩小照片模式 */
private int mode = 0;// 初始状态
/** 拖拉照片模式 */
private static final int MODE_DRAG = 1;
/** 放大缩小照片模式 */
private static final int MODE_ZOOM = 2;
/** 用于记录开始时候的坐标位置 */
private PointF startPoint = new PointF();
/** 两个手指的开始距离 */
private float startDis;
/** 两个手指的中间点 */
private PointF midPoint;
private static int TYPE = 0;
private float topMinScale = 1;
private float leftMinScale = 1;
private float rightMinScale = 1;
private int excessImageH=0;//图片超出矩阵部分高度;
private int excessImageW = 0;//图片超出矩阵部分宽度;
private float scaleX = 0; public CustomTopImageView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
} public CustomTopImageView(Context context, AttributeSet attrs) {
super(context, attrs);
} public CustomTopImageView(Context context) {
super(context);
} @Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (state > 0) {
return;
}
state = START;
init();
} private void init() {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);// 软件加速
try {
leftImage = BitmapFactory.decodeStream(getContext().getAssets()
.open("m1.jpg"));
rightImage = BitmapFactory.decodeStream(getContext().getAssets()
.open("m2.jpg"));
topImage = BitmapFactory.decodeStream(getContext().getAssets()
.open("m3.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);// 防抖动
paint.setFilterBitmap(true);// 过滤
initMatrix();// 缩小图片
initPath();
}// // 初始化矩阵(3X3)并缩放图片
// private void initMatrix() {
// leftMatrix = new Matrix();
// rightMatrix = new Matrix();
// topMatrix = new Matrix();
// float w = getWidth();
// float h = getWidth();
//
// setImageZoom(leftMatrix,w/2,h,leftImage);
// setImageZoom(rightMatrix,w/2,h,rightImage);
// setImageZoom(topMatrix,w,h/2,topImage);
//
// rightMatrix.postTranslate(w/2, 0);//矩阵偏移
// } private void initMatrix(){
leftMatrix = new Matrix();
rightMatrix = new Matrix();
topMatrix = new Matrix();
float w = getWidth();
float h = getHeight();
//第一个图片
scaleX = w / leftImage.getWidth();
float scaleY = h / leftImage.getHeight();
leftMinScale = scaleX > scaleY ? scaleX : scaleY;
leftMatrix.setScale(leftMinScale, leftMinScale);
//第二个图片
scaleX = w / rightImage.getWidth();
scaleY = h / rightImage.getHeight();
rightMinScale = scaleX > scaleY ? scaleX : scaleY;
rightMatrix.setScale(rightMinScale, rightMinScale);
//第三个图片
scaleX = w / topImage.getWidth();
scaleY = h / topImage.getHeight();
topMinScale = scaleX > scaleY ? scaleX : scaleY;
topMatrix.setScale(topMinScale, topMinScale);
rightMatrix.postTranslate(w/2, 0);//右图矩阵偏移
}
/**
* 根据矩阵的形状动态缩放图片
* @param matrix 矩阵
* @param matrixW 控件宽度
* @param matrixH 控件高度
* @param bmp 图片
*/
private void setImageZoom(Matrix matrix,float matrixW,float matrixH,Bitmap bmp){
float imgW = bmp.getWidth();
float imgH = bmp.getHeight();
//得出比例
float w = matrixW/imgW;
float h = matrixH/imgH;
if(matrixW < matrixH){
matrix.setScale(h, h);
}else{
matrix.setScale(w, w);
}
}
// 画好矩阵模块
private void initPath() {
float cpad = padding / 2;// padding = 10
// 视图宽高
float w = getWidth();
float h = getWidth();
float bx = w / 2;//
float by = h / 2;// 相当于中心点 top = new Path();
left = new Path();
right = new Path();
// 上图
top.moveTo(padding * 1.7f, padding);
top.lineTo(w - padding * 1.7f, padding);
top.lineTo(bx, by - 0.7f * padding);
top.close();
// 左图
left.moveTo(padding, padding * 1.7f);
left.lineTo(bx - cpad, by + 0.2f * padding);
left.lineTo(bx - cpad, h - padding);
left.lineTo(padding, h - padding);
left.close();
// 右图
right.moveTo(w - padding, padding * 1.7f);
right.lineTo(bx + cpad, by + 0.2f * padding);
right.lineTo(bx + cpad, h - padding);
right.lineTo(w - padding, h - padding);
right.close();
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (topImage != null) {
// 设置抗锯齿
PaintFlagsDrawFilter pfd = new PaintFlagsDrawFilter(0,Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
canvas.setDrawFilter(pfd);
canvas.save();
canvas.clipPath(top);// 先画好模块
canvas.drawBitmap(topImage, topMatrix, paint);// 再画图
canvas.restore(); canvas.save();
canvas.clipPath(left);
canvas.drawBitmap(leftImage, leftMatrix, paint);
canvas.restore(); canvas.save();
canvas.clipPath(right);
canvas.drawBitmap(rightImage, rightMatrix, paint);
canvas.restore();
}
} @Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// 当第一个手指按下时
mode = MODE_DRAG;
if (isInsideTop(event)) {
// 上图
TYPE = 1;
startPoint.set(event.getX(), event.getY());
} else if (isInsideLeft(event)) {
// 左图
TYPE = 2;
startPoint.set(event.getX(), event.getY());
} else if (isInsideRight(event)) {
// 右图
TYPE = 3;
startPoint.set(event.getX(), event.getY());
}
break;
case MotionEvent.ACTION_MOVE:
// 移动或缩放
float[] values = new float[9];//拿到矩阵中的元素
getCurrentMatrix().getValues(values);//获取图片3x3矩阵
if (mode == MODE_DRAG) {// 拖拉图片
float dx = event.getX() - startPoint.x;//减去第一次的移动距离
float dy = event.getY() - startPoint.y;
startPoint.x = event.getX();
startPoint.y = event.getY();
//往上移动
if(dy < 0 && dy + values[5] > excessImageH){
getCurrentMatrix().postTranslate(0, dy);
}
//往下移动
if(dy > 0 && dy + values[5] < -excessImageH){
getCurrentMatrix().postTranslate(0, dy);
}
//往左移动
if(dx > 0 && values[2]+dx < -excessImageW){
getCurrentMatrix().postTranslate(dx, 0);
}
//往右移动
if(dx < 0 && values[2]+dx > excessImageW){
getCurrentMatrix().postTranslate(dx, 0);
}
} else if (mode == MODE_ZOOM) {// 放大缩小图片
float endDis = distance(event);
// 结束距离
if (endDis > 10f) {
// 两个手指并拢在一起的时候素大于10
float scale = endDis / startDis;
startDis = endDis;
float oldScale = values[0];
// 得到缩放倍数进行缩放
if(oldScale * scale > getCurMinScale()){
getCurrentMatrix().postScale(scale, scale, midPoint.x,midPoint.y);
}
}
}
break;
case MotionEvent.ACTION_UP:
// 当触点离开屏幕,但是屏幕上还有触点(手指)
break;
case MotionEvent.ACTION_POINTER_UP:
mode = 0;
break;
case MotionEvent.ACTION_POINTER_DOWN:
// 当屏幕上已经有触点(手指),再有一个触点压下屏幕
mode = MODE_ZOOM;
startDis = distance(event);
if (startDis > 10f) { // 两个手指并拢在一起的时候像素大于10
midPoint = mid(event);
// 记录当前ImageView的缩放倍数
}
break;
}
invalidate();// 重绘
return true;
} /**根据TYPE值返回对应的矩阵*/
private Matrix getCurrentMatrix() {
switch (TYPE) {
case 1:
excessImageH = (topImage.getHeight()*(int)topMinScale)-(getHeight()/2);
excessImageW = (topImage.getWidth()*(int)topMinScale)-getWidth();
return topMatrix;
case 2:
excessImageH = (leftImage.getHeight()*(int)leftMinScale)-getHeight();
excessImageW = (leftImage.getWidth()*(int)leftMinScale)-(getWidth()/2);
return leftMatrix;
default:
excessImageH = (rightImage.getHeight()*(int)rightMinScale)-getHeight();
excessImageW = (rightImage.getWidth()*(int)rightMinScale)-(getWidth()/2);
return rightMatrix;
}
} /**根据TYPE值返回对应的缩放系数*/
private float getCurMinScale(){
switch (TYPE) {
case 1:
return topMinScale;
case 2:
return leftMinScale;
default:
return rightMinScale;
}
} private boolean isInsideTop(MotionEvent event) {
float x = event.getX();
float y = event.getY();
float w = getWidth();
float h = getWidth();
float by = h / 2;
return y < by && y < (h - h * x / w) && y < x;
} private boolean isInsideLeft(MotionEvent event) {
float x = event.getX();
float y = event.getY();
float w = getWidth();
float bx = w / 2;
return x < bx && y > x;
} private boolean isInsideRight(MotionEvent event) {
float x = event.getX();
float y = event.getY();
float w = getWidth();
float h = getWidth();
float bx = w / 2;
return x > bx && y > (h - h * x / w);
} /** 计算两个手指间的距离 */
private float distance(MotionEvent event) {
float dx = event.getX(1) - event.getX(0);
float dy = event.getY(1) - event.getY(0);
/** 使用勾股定理返回两点之间的距离 */
return FloatMath.sqrt(dx * dx + dy * dy);
} /** 计算两个手指间的中间点 */
private PointF mid(MotionEvent event) {
float midX = (event.getX(1) + event.getX(0)) / 2;
float midY = (event.getY(1) + event.getY(0)) / 2;
return new PointF(midX, midY);
}
}