您的位置:首页 > 移动开发 > Android开发

Android 实现可以自由移动缩放的图片控件

2016-06-10 23:04 796 查看

一、概述:

1、需要实现的功能

1)可以自由的缩放

2)双击可以缩放

3)自动边界检测

4)放大后可以自由的移动

5)处理与viewpager之间的事件冲突

2、需要用到的技术

1)Handle事件分发机制

2)Matrix矩阵

3)ScaleGuestureDetector:手势缩放

4)GuestureDetector:手势移动

5)postdelay + runnable:实现缩放动画

6)根据矩阵Matrix获得x,y轴的缩放值

7)放大后的图片宽度大于屏幕宽度时,父控件消费掉事件

if (rectF.width() > getWidth()) {
getParent().requestDisallowInterceptTouchEvent(true);
}


3、如何实现?

通过继承ImageView来实现

二、创建基本的框架

1、创建自定义的视图
package com.android.imooc.imagescale;

import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ImageView;

/**
* @描述         实现可以自由移动缩放的图片控件
* @项目名称      App_imooc
* @包名         com.android.imooc.imagescale
* @类名         ScaleView
* @author      chenlin
* @date        2013年6月10日 下午10:11:11
* @version     1.0
*/

public class ScaleView extends ImageView implements OnGlobalLayoutListener{

public ScaleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public ScaleView(Context context) {
this(context, null);
}

public ScaleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

@Override
public void onGlobalLayout() {

}

/**
* 注册全局事件
*/
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnGlobalLayoutListener(this);
}

/**
* 移除全局事件
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}

}


2、把视图添加到布局里

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<com.android.imooc.imagescale.ScaleView
android:id="@+id/scaleView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</LinearLayout>


3、创建主页

package com.android.imooc.imagescale;

import com.android.imooc.R;

import android.app.Activity;
import android.os.Bundle;

/**
* @描述         TODO
* @项目名称      App_imooc
* @包名         com.android.imooc.imagescale
* @类名         ScaleActivity
* @author      chenlin
* @date        2013年6月10日 下午10:17:16
* @version     1.0
*/

public class ScaleActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scale);
}
}


三、添加基本的事件处理

1、设置合适的图片大小

1)图片只加载一此,所以用isOnce来判断是否加载了图片

2)首先获得控件的大小

3)获得图片的大小

4)进行对比

//如果还没有加载图片
if (!isOne) {

//获得控件的宽高
int width = getWidth();
int height = getHeight();

Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
//获得图片的宽高
int bitmapWidth = drawable.getIntrinsicWidth();
int bitmapHeight = drawable.getIntrinsicHeight();

//设定比例值
float scale = 0.0f;

//如果图片的宽度>控件的宽度,缩小
if (bitmapWidth > width && bitmapHeight < height) {
scale =  width * 1.0f / bitmapWidth;
}
//如果图片的高度>控件的高度,缩小
if (bitmapHeight > height && bitmapWidth < width) {
scale =  height * 1.0f / bitmapHeight;
}
//如果图片的宽高度>控件的宽高度,缩小  或者  如果图片的宽高度<控件的宽高度,放大
if ((bitmapWidth > width && bitmapHeight > height) || (bitmapWidth < width && bitmapHeight < height) ) {
float f1 = width * 1.0f / bitmapWidth;
float f2 =  height * 1.0f / bitmapHeight;
scale = Math.min(f1, f2);
}

isOne = true;
}


2、让图片居中缩放显示

1)定义三个缩放的变量

/**初始时的缩放值*/
private float mInitScale;
/**双击时 的缩放值*/
private float mClickScale ;
/**最大的缩放值*/
private float mMaxScale;


2)在onGlobalLayout里初始化

mInitScale = scale;
mClickScale = mInitScale * 2;
mMaxScale = mInitScale * 4;


3)得到图片移动到中心点时的距离



//得到移动的距离
int dx = width/2 - bitmapWidth/2;
int dy = height/2 - bitmapHeight/2;


4)将图片移动到控件的中心

Matrix matrix = new Matrix();
//记得必须先平移才缩放,否则没效果
matrix.postTranslate(dx, dy);
//在控件的中心缩放
mMatrix.postScale(scale, scale, width/2, height/2);

//设置矩阵
setImageMatrix(matrix);

//关于matrix,就是个3*3的矩阵
/**
*   xscale xskew   xtrans
*   yskew  yscale  ytrans
*   0       0        0
*/


5)添加图片测试:

public class ScaleActivity extends Activity {
private ScaleView mScaleView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scale);
mScaleView = (ScaleView) findViewById(R.id.scaleView);
mScaleView.setImageResource(R.drawable.pic_1);
}
}


如图:图片居中,并缩小了



3、实现图片以屏幕中心进行缩放

1)使用到的类:ScaleGestureDetector

2)初始化:

pirvate ScaleGestureDetector mScaleGesture = new ScaleGestureDetector (context, this);

3)让类实现OnScaleGestureListener,并实现下面三个方法:

@Override
public boolean onScale(ScaleGestureDetector detector) {
// TODO Auto-generated method stub
return false;
}

@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
// 必须返回true
return true;
}

@Override
public void onScaleEnd(ScaleGestureDetector detector) {
// TODO Auto-generated method stub

}


4)要实现屏幕触摸,必须实现OnTouchListener, 把触屏事件给缩放手势处理

@Override
public boolean onTouch(View v, MotionEvent event) {
mScaleGesture.onTouchEvent(event);
//必须返回true
return true;
}


5)在onScale方法里实现缩放

先取得缩放值

/**
* 获得缩放值
* @return
*/
public float getScale(){
/**
*   xscale xskew   xtrans
*   yskew  yscale  ytrans
*   0       0        0
*/
float[] values = new float[9];
mMatrix.getValues(values);
return values[Matrix.MSCALE_X];
}


控制缩放:

@Override
public boolean onScale(ScaleGestureDetector detector) {
//如果没有图片,返回
if (getDrawable() == null) {
return true;
}
//缩放因子,>0表示正在放大,<0表示正在缩小
float intentScale = detector.getScaleFactor();
float scale = getScale();

//进行缩放范围的控制
//判断,如果<最大缩放值,表示可以放大,如果》最小缩放,说明可以缩小
if ((scale < mMaxScale && intentScale > 1.0f )|| (scale > mInitScale && intentScale < 1.0f)) {

//scale 变小时, intentScale变小
if (scale * intentScale < mInitScale) {
//intentScale * scale = mInitScale ;
intentScale = mInitScale / scale;
}

//scale 变大时, intentScale变大
if (scale * intentScale > mMaxScale) {
//intentScale * scale = mMaxScale ;
intentScale = mMaxScale / scale;
}

mMatrix.postScale(intentScale, intentScale, getWidth()/2, getHeight()/2);
setImageMatrix(mMatrix);
}

return true;
}


4、实现图片多点缩放

1)首先不能以控件为中心缩放了,改为以手势为中心缩放

mMatrix.postScale(intentScale, intentScale, detector.getFocusX(), detector.getFocusY());


2)调整边界

首先得到图片缩放后的矩阵

/**
* 获得图片缩放后的矩阵
* @return
*/
public RectF getMatrixRectF(){
Matrix matrix = mMatrix;
RectF rectF = new RectF();
Drawable drawable = getDrawable();
if (drawable != null) {
//初始化矩阵
rectF.set(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
//移动s
matrix.mapRect(rectF);
}
return rectF;
}


如图:三种情况



private void checkSideAndCenter() {
RectF rectF = getMatrixRectF();
float deltaX = 0f;
float deltaY = 0f;
int width = getWidth();
int height = getHeight();

//情况1, 如果图片的宽度大于控件的宽度
if (rectF.width() >= width) {
if (rectF.left > 0) {
deltaX = - rectF.left;//如果图片没有左边对齐,就往左边移动
}
if (rectF.right < width) {
deltaX = width - rectF.right;//如果图片没有右边对齐,就往右边移动
}
}
//情况2, 如果图片的宽度大于控件的宽度
if (rectF.height() >= height) {
if (rectF.top > 0) {
deltaY = - rectF.top;//
}
if (rectF.bottom < height) {
deltaY = height - rectF.bottom;//往底部移动
}
}

//情况3,如图图片在控件内,则让其居中
if (rectF.width() < width ) {
//deltaX = width/2-rectF.left - rectF.width()/2;
//或
deltaX = width/2-rectF.right + rectF.width()/2;
}

if (rectF.height() < height) {
deltaY = height/2-rectF.bottom + rectF.height()/2;
}

mMatrix.postTranslate(deltaX, deltaY);
setImageMatrix(mMatrix);
}


情况三公式:



5、实现图片的自由移动

1)事件处理在onTouchEvent里,首先定义变量记录上次手指的个数;

private int lastPointerCount;


2)求得手指的中心点

float x = event.getX();
float y = event.getY();

int pointerCount = event.getPointerCount();
for(int i = 0 ; i < pointerCount ; i ++){
x += event.getX(i);
y += event.getY(i);
}
x/= pointerCount;
y/= pointerCount;


3)判断记录

// 说明手指改变
if (mLastPointerCount != pointerCount) {
mLastX = x;
mLastY = y;
}
mLastPointerCount = pointerCount;


4)事件处理

switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx = x - mLastX;
float dy = y - mLastX;

if (!isCanDrag) {
isCanDrag = isMoveAction(dx, dy);
}
/**
* 如果能移动
*/
if (isCanDrag) {
RectF rectF = getMatrixRectF();
if (getDrawable() == null) {
return true;
}

//如果图片在控件内,不允许移动
if (rectF.width() < getWidth()) {
dx = 0f;
}
if (rectF.height() < getHeight()) {
dy = 0f;
}

mMatrix.postTranslate(dx, dy);
//移动事检测边界
checkSideAndCenterWhenTrans();

setImageMatrix(mMatrix);
}

mLastX = x;
mLastY = y;

break;

case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
//清楚手指
mLastPointerCount = 0;

break;


5)测试,发现图片可有自由移到,所以必须重新检测边界

定义变量

/** 判断是否检测了x,y轴 */
private boolean isCheckX;
private boolean isCheckY;

//移到
private void checkSideAndCenterWhenTransate() {
RectF rectF = getMatrixRectF();
float deltaX = 0f;
float deltaY = 0f;
int width = getWidth();
int height = getHeight();

if (rectF.top > 0 && isCheckY) {
deltaY = - rectF.top;//往上边移动
}
if (rectF.bottom < height && isCheckY) {
deltaY = height - rectF.bottom;//往底部移动
}

if (rectF.left > 0 && isCheckX) {
deltaX = - rectF.left;//往左边移动
}
if (rectF.right < width && isCheckY) {
deltaX = width - rectF.right;//往右边移动
}
//移动
mMatrix.postTranslate(deltaX, deltaY);
}


6、实现图片双击放大与缩小

1)主要使用的类

private GestureDetector mGesture;


在构造方法里初始化

mGesture = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
});


2)传递事件,在onTouchEvent里

//把事件传递给双击手势
if (mGesture.onTouchEvent(event)) {
return true;
}


3)实现:

float px = e.getX();
float py = e.getY();
//只有小于最大缩放比例才能放大
float scale = getScale();
if (scale < mMaxScale) {
mMatrix.postScale(mClickScale/scale, mClickScale/scale, px, py);
}else {
mMatrix.postScale(mInitScale/scale, mInitScale/scale, px, py);
}
setImageMatrix(mMatrix);


4)测试发现,图片瞬间变大缩小,这不是我们需要的效果,我们要的是慢慢放大,慢慢缩小,有个动画的过程

如何实现?可有使用一个类,继承runnable,在run方法里进行缩放

private class ScaleRunnale implements Runnable{
//放大值
private static final float BIGGER = 1.08f;
//缩小值
private static final float SMALLER = 0.96f;
private float x;
private float y;
private float mTargetScale;
private float mTempScale;

public ScaleRunnale(float x, float y, float mTargetScale) {
super();
this.x = x;
this.y = y;
this.mTargetScale = mTargetScale;

if (getScale() < mTargetScale) {
mTempScale = BIGGER;
}else if (getScale() > mTargetScale) {
mTempScale = SMALLER;
}
}

@Override
public void run() {
//先进行缩放
mMatrix.postScale(mTempScale, mTempScale, x, y);
checkSideAndCenterWhenScale();
setImageMatrix(mMatrix);

float currentScale = getScale();

//如果想放大,并且当前的缩放值小于目标值
if ((mTempScale > 1.0f && currentScale < mTargetScale) || (mTempScale < 1.0f && currentScale > mTargetScale)) {
//递归执行run方法
postDelayed(this, 16);
}else {
float scale = mTargetScale / currentScale;
mMatrix.postScale(scale, scale, x, y);
checkSideAndCenterWhenScale();
setImageMatrix(mMatrix);

isAutoScale = false;
}
}

}


修改原来的缩放方法:

public boolean onDoubleTap(MotionEvent e) {

//如果正在缩放时,不能放大
if (isAutoScale) {
return true;
}

float px = e.getX();
float py = e.getY();
//只有小于最大缩放比例才能放大
float scale = getScale();
if (scale < mClickScale) {
//mMatrix.postScale(mClickScale/scale, mClickScale/scale, px, py);
postDelayed(new ScaleRunnale(px, py, mClickScale), 16);
isAutoScale = true;
}else {
//mMatrix.postScale(mInitScale/scale, mInitScale/scale, px, py);
postDelayed(new ScaleRunnale(px, py, mInitScale), 16);
isAutoScale = true;
}
//setImageMatrix(mMatrix);
return true;
}


效果图:



最后:全部代码

package com.android.imooc.imagescale;

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ImageView;

/**
* @描述 实现可以自由移动缩放的图片控件
* @项目名称 App_imooc
* @包名 com.android.imooc.imagescale
* @类名 ScaleView
* @author chenlin
* @date 2013年6月10日 下午10:11:11
* @version 1.0
*/

public class ScaleView extends ImageView implements OnGlobalLayoutListener, OnScaleGestureListener, OnTouchListener {

/** 表示是否只有一次加载 */
private boolean isOnce = false;
/** 初始时的缩放值 */
private float mInitScale;
/** 双击时 的缩放值 */
private float mClickScale;
/** 最大的缩放值 */
private float mMaxScale;
/** 图片缩放矩阵 */
private Matrix mMatrix;
/** 图片缩放手势 */
private ScaleGestureDetector mScaleGesture;

// ----------------------------自由移动--------------------------------
/** 可移动最短距离限制,大于这个值时就可移动 */
private int mTouchSlop;
/** 是否可以拖动 */
private boolean isCanDrag;

// ----------------------------双击放大--------------------------------
private GestureDetector mGesture;
// 是否自动缩放
private boolean isAutoScale;

public ScaleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public ScaleView(Context context) {
this(context, null);
}

public ScaleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 必须设置才能触发
this.setOnTouchListener(this);

mMatrix = new Matrix();
// 设置缩放模式
super.setScaleType(ScaleType.MATRIX);

mScaleGesture = new ScaleGestureDetector(context, this);
mGesture = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(MotionEvent e) {

// 如果正在缩放时,不能放大
if (isAutoScale) {
return true;
}

float px = e.getX();
float py = e.getY();
// 只有小于最大缩放比例才能放大
float scale = getScale();
if (scale < mClickScale) {
// mMatrix.postScale(mClickScale/scale, mClickScale/scale,
// px, py);
postDelayed(new ScaleRunnale(px, py, mClickScale), 16);
isAutoScale = true;
} else {
// mMatrix.postScale(mInitScale/scale, mInitScale/scale, px,
// py);
postDelayed(new ScaleRunnale(px, py, mInitScale), 16);
isAutoScale = true;
}
// setImageMatrix(mMatrix);
return true;
}
});

/**
* 是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。如果小于这个距离就不触发移动控件,如viewpager
* 就是用这个距离来判断用户是否翻页。
*/
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}

private class ScaleRunnale implements Runnable {
// 放大值
private static final float BIGGER = 1.08f;
// 缩小值
private static final float SMALLER = 0.96f;
private float x;
private float y;
private float mTargetScale;
private float mTempScale;

public ScaleRunnale(float x, float y, float mTargetScale) {
super();
this.x = x;
this.y = y;
this.mTargetScale = mTargetScale;

if (getScale() < mTargetScale) {
mTempScale = BIGGER;
} else if (getScale() > mTargetScale) {
mTempScale = SMALLER;
}
}

@Override
public void run() {
// 先进行缩放
mMatrix.postScale(mTempScale, mTempScale, x, y);
checkSideAndCenterWhenScale();
setImageMatrix(mMatrix);

float currentScale = getScale();

// 如果想放大,并且当前的缩放值小于目标值
if ((mTempScale > 1.0f && currentScale < mTargetScale)
|| (mTempScale < 1.0f && currentScale > mTargetScale)) {
// 递归执行run方法
postDelayed(this, 16);
} else {
float scale = mTargetScale / currentScale;
mMatrix.postScale(scale, scale, x, y);
checkSideAndCenterWhenScale();
setImageMatrix(mMatrix);

isAutoScale = false;
}
}

}

@Override
public void onGlobalLayout() {
// 如果还没有加载图片
if (!isOnce) {

// 获得控件的宽高
int width = getWidth();
int height = getHeight();

Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
// 获得图片的宽高
int bitmapWidth = drawable.getIntrinsicWidth();
int bitmapHeight = drawable.getIntrinsicHeight();

// 设定比例值
float scale = 0.0f;

// 如果图片的宽度>控件的宽度,缩小
if (bitmapWidth > width && bitmapHeight < height) {
scale = width * 1.0f / bitmapWidth;
}
// 如果图片的高度>控件的高度,缩小
if (bitmapHeight > height && bitmapWidth < width) {
scale = height * 1.0f / bitmapHeight;
}
// 如果图片的宽高度>控件的宽高度,缩小 或者 如果图片的宽高度<控件的宽高度,放大
if ((bitmapWidth > width && bitmapHeight > height) || (bitmapWidth < width && bitmapHeight < height)) {
float f1 = width * 1.0f / bitmapWidth;
float f2 = height * 1.0f / bitmapHeight;
scale = Math.min(f1, f2);
}

// 初始化缩放值
mInitScale = scale; mClickScale = mInitScale * 2; mMaxScale = mInitScale * 4;

// 得到移动的距离
int dx = width / 2 - bitmapWidth / 2;
int dy = height / 2 - bitmapHeight / 2;

// 平移
mMatrix.postTranslate(dx, dy);

// 在控件的中心缩放
mMatrix.postScale(scale, scale, width / 2, height / 2);

// 设置矩阵
setImageMatrix(mMatrix);

// 关于matrix,就是个3*3的矩阵
/**
* xscale xskew xtrans yskew yscale ytrans 0 0 0
*/

isOnce = true;
}
}

/**
* 注册全局事件
*/
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnGlobalLayoutListener(this);
}

/**
* 移除全局事件
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}

/**
* 获得缩放值
*
* @return
*/
public float getScale() {
/**
* xscale xskew xtrans yskew yscale ytrans 0 0 0
*/
float[] values = new float[9];
mMatrix.getValues(values);
return values[Matrix.MSCALE_X];
}

@Override
public boolean onScale(ScaleGestureDetector detector) {
// 如果没有图片,返回
if (getDrawable() == null) {
return true;
}
// 缩放因子,>0表示正在放大,<0表示正在缩小
float intentScale = detector.getScaleFactor();
float scale = getScale();

// 进行缩放范围的控制
// 判断,如果<最大缩放值,表示可以放大,如果》最小缩放,说明可以缩小
if ((scale < mMaxScale && intentScale > 1.0f) || (scale > mInitScale && intentScale < 1.0f)) {

// scale 变小时, intentScale变小
if (scale * intentScale < mInitScale) {
// intentScale * scale = mInitScale ;
intentScale = mInitScale / scale;
}

// scale 变大时, intentScale变大
if (scale * intentScale > mMaxScale) {
// intentScale * scale = mMaxScale ;
intentScale = mMaxScale / scale;
}

// 以控件为中心缩放
// mMatrix.postScale(intentScale, intentScale, getWidth()/2,
// getHeight()/2);
// 以手势为中心缩放
mMatrix.postScale(intentScale, intentScale, detector.getFocusX(), detector.getFocusY());

// 检测边界与中心点
checkSideAndCenterWhenScale();

setImageMatrix(mMatrix);
}

return true;
}

/**
* 获得图片缩放后的矩阵
*
* @return
*/
public RectF getMatrixRectF() {
Matrix matrix = mMatrix;
RectF rectF = new RectF();
Drawable drawable = getDrawable();
if (drawable != null) {
// 初始化矩阵
rectF.set(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
// 移动s
matrix.mapRect(rectF);
}
return rectF;
}

private void checkSideAndCenterWhenScale() {
RectF rectF = getMatrixRectF();
float deltaX = 0f;
float deltaY = 0f;
int width = getWidth();
int height = getHeight();

// 情况1, 如果图片的宽度大于控件的宽度
if (rectF.width() >= width) {
if (rectF.left > 0) {
deltaX = -rectF.left;// 如果图片没有左边对齐,就往左边移动
}
if (rectF.right < width) {
deltaX = width - rectF.right;// 如果图片没有右边对齐,就往右边移动
}
}
// 情况2, 如果图片的宽度大于控件的宽度
if (rectF.height() >= height) {
if (rectF.top > 0) {
deltaY = -rectF.top;//
}
if (rectF.bottom < height) {
deltaY = height - rectF.bottom;// 往底部移动
}
}

// 情况3,如图图片在控件内,则让其居中
if (rectF.width() < width) {
// deltaX = width/2-rectF.left - rectF.width()/2;
// 或
deltaX = width / 2f - rectF.right + rectF.width() / 2f;
}

if (rectF.height() < height) {
deltaY = height / 2f - rectF.bottom + rectF.height() / 2f;
}

mMatrix.postTranslate(deltaX, deltaY);
}

@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
// TODO Auto-generated method stub
return true;
}

@Override
public void onScaleEnd(ScaleGestureDetector detector) {
// TODO Auto-generated method stub

}

private float mLastX;
private float mLastY;
/** 上次手指的数量 */
private int mLastPointerCount;

/** 判断是否检测了x,y轴 */
private boolean isCheckX;
private boolean isCheckY;

@Override
public boolean onTouch(View v, MotionEvent event) {

// 把事件传递给双击手势
if (mGesture.onTouchEvent(event)) {
return true;
}
// 把事件传递给缩放手势
mScaleGesture.onTouchEvent(event);

float x = event.getX();
float y = event.getY();

int pointerCount = event.getPointerCount();
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:
if (rectF.width() > getWidth()) { getParent().requestDisallowInterceptTouchEvent(true); }
break;

case MotionEvent.ACTION_MOVE:
if (rectF.width() > getWidth()) { getParent().requestDisallowInterceptTouchEvent(true); }

float dx = x - mLastX;
float dy = y - mLastY;

if (!isCanDrag) {
isCanDrag = isMoveAction(dx, dy);
}
/**
* 如果能移动
*/
if (isCanDrag) {
//RectF rectF = getMatrixRectF();
if (getDrawable() == null) {
return true;
}

isCheckX = isCheckY = true;

// 如果图片在控件内,不允许移动
if (rectF.width() < getWidth()) {
isCheckX = false;
dx = 0f;
}
if (rectF.height() < getHeight()) {
isCheckY = false;
dy = 0f;
}

mMatrix.postTranslate(dx, dy);

// 移动事检测边界
checkSideAndCenterWhenTransate();

setImageMatrix(mMatrix);
}

mLastX = x;
mLastY = y;

break;

case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// 清楚手指
mLastPointerCount = 0;

break;
}

return true;
}

private void checkSideAndCenterWhenTransate() {
RectF rectF = getMatrixRectF();
float deltaX = 0f;
float deltaY = 0f;
int width = getWidth();
int height = getHeight();

if (rectF.top > 0 && isCheckY) {
deltaY = -rectF.top;// 往上边移动
}
if (rectF.bottom < height && isCheckY) {
deltaY = height - rectF.bottom;// 往底部移动
}

if (rectF.left > 0 && isCheckX) {
deltaX = -rectF.left;// 往左边移动
}
if (rectF.right < width && isCheckX) {
deltaX = width - rectF.right;// 往右边移动
}
// 移动
mMatrix.postTranslate(deltaX, deltaY);
}

private boolean isMoveAction(float dx, float dy) {
// 求得两点的距离
return Math.sqrt(dx * dx + dy * dy) > mTouchSlop;
}

}


主页

/**
* @描述 TODO
* @项目名称 App_imooc
* @包名 com.android.imooc.imagescale
* @类名 ScaleActivity
* @author chenlin
* @date 2013年6月10日 下午10:17:16
* @version 1.0
*/

public class ScaleActivity extends Activity {
// private ScaleView mScaleView;
private ViewPager mPager;
private ScalePagerAdapter mAdapter;

private int resIds[] = new int[] { R.drawable.pic_1, R.drawable.pic_2, R.drawable.pic_3, R.drawable.pic_4,
R.drawable.pic_5, R.drawable.pic_6 };
private ScaleView[] mScaleViews;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scale);
// mScaleView = (ScaleView) findViewById(R.id.scaleView);
// mScaleView.setImageResource(R.drawable.pic_1);
mScaleViews = new ScaleView[resIds.length];
//      for (int i = 0; i < resIds.length; i++) {
//          mScaleViews[i] = new ScaleView(this);
//          mScaleViews[i].setImageResource(resIds[i]);
//      }

mPager = (ViewPager) findViewById(R.id.viewPager);
mAdapter = new ScalePagerAdapter();
mPager.setAdapter(mAdapter);

}

private class ScalePagerAdapter extends PagerAdapter {

@Override
public int getCount() {
return resIds.length;
}

@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
//          if (object instanceof ScaleView) {
//              ScaleView scaleView = (ScaleView) object;
//              container.removeView(scaleView);
//          }
container.removeView(mScaleViews[position]);
}

@Override
public Object instantiateItem(ViewGroup container, int position) {

ScaleView scaleView = new ScaleView(getApplicationContext());
scaleView.setImageResource(resIds[position]);
mScaleViews[position] = scaleView;
container.addView(scaleView);
return scaleView;
}

}
}


———————————————————————

(java 架构师全套教程,共760G, 让你从零到架构师,每月轻松拿3万)

有需求者请进站查看,非诚勿扰

https://item.taobao.com/item.htm?spm=686.1000925.0.0.4a155084hc8wek&id=555888526201


01.高级架构师四十二个阶段高

02.Java高级系统培训架构课程148课时

03.Java高级互联网架构师课程

04.Java互联网架构Netty、Nio、Mina等-视频教程

05.Java高级架构设计2016整理-视频教程

06.架构师基础、高级片

07.Java架构师必修linux运维系列课程

08.Java高级系统培训架构课程116课时

(送:hadoop系列教程,java设计模式与数据结构, Spring Cloud微服务, SpringBoot入门)

——————————————————————–
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息