由于需要真机测试, 所以没有弄效果图..
1, 建立一个类MultiTouch 继承 ImageView, 并在xml使用, 获取要缩放图片. 如果图片的宽/高大于屏幕宽/高, 那么我们进行缩放,并移动到屏幕中心点.
那么问题来了. 如果我们在构造器中直接获取宽度 那么可能会获取不到. 我们需要知道布局什么时候加载完成. 这时候就需要用到一个接口 OnGlobalLayoutListener (全球布局监听) 实现 onGlobalLayout() 方法. 并且需要在view 从window出现时 监听它, 从window时 移除.
于是对图片初始化的操作 都会在 onGlobalLayout()内执行.
2,我们还需要实现 OnScaleGestureListener 接口 来对 多点触控进行操作... 很方便
3. 把touch 事件 交给 OnScaleGestureListener .
下面贴代码
public class MultiTouch extends ImageView implements OnGlobalLayoutListener,
OnScaleGestureListener, OnTouchListener {
private Context context;
private boolean mOnce = false; // 初始化一次
private float scale = 1.0f; // 默认缩放比
private float mInitScale;// 初始化缩放比, 也就是最小缩放
private float mMidScale; // 双击时的 缩放比
private float mMaxScale; // 极限 最大 的缩放比
private ScaleGestureDetector mScaleGestureDetector;
private Matrix mMatrix;
private Drawable drawable;
public MultiTouch(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MultiTouch(Context context) {
this(context, null);
}
public MultiTouch(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
// 初始化操作
// 是一个 3*3的矩阵.
// xScale xskwe xtrans
// yskwe yscale ytrans
// 0 0 0
mMatrix = new Matrix();
setOnTouchListener(this);
}
/**
* 当 自定义空间 显示在window上
*/
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// 返回一个布局层级视图
getViewTreeObserver().addOnGlobalLayoutListener(this);// 监听布局加载完成事件
}
/**
* 当view 从window消失
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// 取消监听
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
// 当图片加载完成后, 图片大的话我们需要进行 缩小, 图片小的话我们需要进行放大.
// 怎么知道图片加载完成 ? 需要实现 接口 OnGlobalLayoutListener 全球布局监听
// 布局都加载完的方法. 需要注册
@Override
public void onGlobalLayout() {
// 初始化只需要一次. need boolean 变量
if (!mOnce) {
int width = getWidth(); // 控件宽
int height = getHeight(); // 控件高
drawable = getDrawable();
if (drawable != null) {
// 返回的是根据像素密度 变化后的值.. dip.
// ldip * 0.75 mdip *1 hdip *1.5 xhdip*2 xxhdip *3
int dw = drawable.getIntrinsicWidth();
int dh = drawable.getIntrinsicHeight();
// 图片宽大于 view宽, 高小于view 高
if (dw > width && dh < height) {
scale = width * 1.0f / dw;
}
// 图片宽小于view宽,高大于view高
if (dw < width && dh > height) {
scale = height * 1.0f / dh;
}
// 图片宽高 都大于 view宽高 || 图片宽高 都小于 view宽高
if ((dw > width && dh > height) || (dw < width && dh < height)) {
scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);
}
mInitScale = scale; // 初始缩放比
mMidScale = mInitScale * 2; // 双击时缩放比
mMaxScale = mInitScale * 4; // 最大缩放比
int dx = getWidth() / 2 - dw / 2;
int dy = getHeight() / 2 - dh / 2;
mMatrix.postTranslate(dx, dy);
mMatrix.postScale(mInitScale, mInitScale);
setImageMatrix(mMatrix);
// 多点触控 的api
mScaleGestureDetector = new ScaleGestureDetector(context, this);
}
mOnce = true;
}
}
public float getScale() {
float[] values = new float[9];
mMatrix.getValues(values);
return values[Matrix.MSCALE_X];
}
/**
* 缩放进行
*/
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scale = getScale(); // 当前的缩放比
float currScale = detector.getScaleFactor(); // 准备要缩放的值
if (drawable == null)
return true;
if ((scale < mMaxScale && currScale > 1.0f)
|| (scale > mInitScale && currScale < 1.0f)) {
// 进行放大 || 缩小
if (scale * currScale < mInitScale) { //当缩放比 小于最小点时 直接返回
return true;
}
if (scale * currScale > mMaxScale) { // 当缩放比 大于最大点时,直接返回
return true;
}
}
mMatrix.postScale(currScale, currScale, detector.getFocusX(),
detector.getFocusY());
checkBorderAndCenterWhenScale();
setImageMatrix(mMatrix);
return true;
}
/**
* 返回缩放时候图片的信息
*
* @return
*/
private RectF getMatrixRectF() {
Matrix matrix = mMatrix;
RectF rect = new RectF();
Drawable d = getDrawable();
if (d != null) {
rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
matrix.mapRect(rect); // 这样就能得到图片放大缩小以后的大小,位置
}
return rect;
}
/**
* 检查边界和中心在缩放时
*/
private void checkBorderAndCenterWhenScale() {
// 获取到缩放后的图片大小
RectF rect = getMatrixRectF();
float deltaX = 0f;
float deltaY = 0f;
int width = getWidth();
int height = getHeight();
// Log.v("info", "rect.left--->" + rect.left);
// Log.v("info", "rect.top--->" + rect.top);
// Log.v("info", "rect.right--->" + rect.right);
// Log.v("info", "rect.bottom--->" + rect.bottom);
// Log.v("info", "rect.width--->" + rect.width());
// Log.v("info", "rect.height--->" + rect.height());
if (rect.width() >= width) {
if (rect.left > 0) {
deltaX = -rect.left;
}
if (rect.right < width) {
deltaX = width - rect.right;
}
}
if (rect.height() >= height) {
if (rect.top > 0) {
deltaY = -rect.top;
}
if (rect.bottom < height) {
deltaY = height - rect.bottom;
}
}
// 如果宽度或高度 小于控件的宽和高 让齐居中
if (rect.width() < width) {
deltaX = width / 2f - rect.right + rect.width() / 2f;
}
if (rect.height() < height) {
deltaY = height / 2f - rect.bottom + rect.height() / 2f;
}
mMatrix.postTranslate(deltaX, deltaY);
}
/**
* 缩放开始
*/
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
// 必须返回true
return true;
}
/**
* 缩放结束
*/
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
}
@Override
public boolean onTouch(View v, MotionEvent event) {
mScaleGestureDetector.onTouchEvent(event);
return true;
}
}