在进入正题钱我们需要作一些准备工作,本文用到了Matrix , ScaleGestureDetector ,Metrix用来控制图片的缩放、平移等错,ScaleGestureDetector用于检测缩放手势。如果对以上两个东东不了解只能字节去查找相关的知识点了,这里不做过多描述。
效果图:因为文件图片不能大于2M所以画面质量、流畅度都不怎么好。
先贴出全部代码,一共三部分
//1、setSCale(x,y)是对单位矩阵进行操作、postScale(x,y)是对当前矩阵进行操作,对当前矩阵起到缩放(x,y)的效果、preScale(x,y)则不能起到缩放(x,y)的效果
//2、mapRectF(rect)用当前matrix对rect进行处理(与图片一样,缩放,平移,旋转)
import com.solo.imageviewer.tools.ImagePositonManager;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
class ScaleImageViewer extends ImageView implements OnTouchListener,OnScaleGestureListener{
private ScaleGestureDetector sgc;
private static final float MAX_SCALE=4.0F;
private static final float MIN_SCALE=0.2F;
private Matrix matrix=new Matrix();
private float[] values=new float[9];
private boolean once=true;
public ScaleImageViewer(Context context, AttributeSet attrs) {
super(context, attrs);
super.setScaleType(ScaleType.MATRIX);
this.setOnTouchListener(this);
sgc=new ScaleGestureDetector(context, this);
}
public ScaleImageViewer(Context context) {
this(context,null);
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactor=detector.getScaleFactor();
float currentScale=getScale();//相对原图的缩放比例
if(currentScale>MAX_SCALE && scaleFactor<1.0f || currentScale<MIN_SCALE
&& scaleFactor>1.0f || currentScale<MAX_SCALE && currentScale>MIN_SCALE){
matrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
}
ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight());
setImageMatrix(matrix);
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
}
@Override
public boolean onTouch(View v, MotionEvent event) {
return sgc.onTouchEvent(event);//这里的event会触发onScale的执行
}
@Override
protected void onDraw(Canvas canvas) {
if(once){
matrix=getImageMatrix();
once=false;
Drawable drawable=getDrawable();
//获取图片的宽和高
int dw=drawable.getIntrinsicWidth();
int dh=drawable.getIntrinsicHeight();
int w=getWidth();
int h=getHeight();
float scale=Math.min(1.0f*w/dw, 1.0f*h/dh);
matrix.postTranslate(w/2-dw/2, h/2-dh/2);
matrix.postScale(scale, scale, w/2, h/2);
setImageMatrix(matrix);
}
super.onDraw(canvas);
}
private float getScale(){
matrix.getValues(values);
return values[Matrix.MSCALE_X];
}
}
第二部分是一个工具类用来控制图片在缩放过程中的位置
public class ImagePositonManager {
public static void setShowPosition(Drawable drawable,Matrix matrix,int w,int h){
RectF rectF=new RectF(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
matrix.mapRect(rectF);
float rw=rectF.width();
float rh=rectF.height();
float moveX=0,moveY=0;
if(rw<w){
moveX=w/2-rw/2-rectF.left;
}
if (rh<h) {
moveY=h/2-rh/2-rectF.top;
}
if(rw>w && rectF.left>0){
moveX=-rectF.left;
}
if(rw>w && rectF.right<w){
moveX=w-rectF.right;
}
if(rh>h && rectF.top>0){
moveY=-rectF.top;
}
if(rh>h && rectF.bottom<h){
moveY=h-rectF.bottom;
}
matrix.postTranslate(moveX, moveY);
}
}
最后就是一个布局文件,,,这就没啥好贴出来了
现在对代码进行分析
protected void onDraw(Canvas canvas) {
if(once){
matrix=getImageMatrix();
once=false;
Drawable drawable=getDrawable();
//获取图片的宽和高
int dw=drawable.getIntrinsicWidth();
int dh=drawable.getIntrinsicHeight();
int w=getWidth();
int h=getHeight();
float scale=Math.min(1.0f*w/dw, 1.0f*h/dh);
matrix.postTranslate(w/2-dw/2, h/2-dh/2);
matrix.postScale(scale, scale, w/2, h/2);
setImageMatrix(matrix);
}
super.onDraw(canvas);
}
我们在onDraw方法中来控制图片初始显示时的大小位置,由于onDraw后图片才会显示到手机上,所以我们在这里进行图片初始显示的一些操作完全来的及
Drawable drawable=getDrawable();
//获取图片的宽和高
int dw=drawable.getIntrinsicWidth();
int dh=drawable.getIntrinsicHeight();
以上代码可以获得原图的宽和高,注意是原图,这个不会随着你缩放图片而改变
matrix.postTranslate(w/2-dw/2, h/2-dh/2);
matrix.postScale(scale, scale, w/2, h/2);
matrix.postTtranslate(x,y):b表示一个水平方向平移x竖直方向平移y的平移矩阵
matrix.postTranslate(x,y,cx,cy):表示以(cx,cy)为缩放中心水平方向缩放x倍,竖直方向缩放y倍
setImageMatrix(matrix);
将矩阵作用到图片,这一步完成后就对图片进行了移动和缩放操作
private float getScale(){
matrix.getValues(values);
return values[Matrix.MSCALE_X];
}
用上面的getScale来获取当前的缩放比例,注意是相对于原图
ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight());
调整图片显示的位置,这个要在setImageMatrix之前调用
RectF rectF=new RectF(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
matrix.mapRect(rectF);
<span style="font-family: Arial, Helvetica, sans-serif;">float rw=rectF.width();
</span><span style="font-family: Arial, Helvetica, sans-serif;">float rh=rectF.height();</span>
用来获取当前图片的狂和高,这时候图片还没有显示出来,当时matrix已经准备好了所以这里相当于是提前获得图片的宽和高,以便进行位置调整