android多点触控自由对图片缩放
在系统的相册中,观看相片就可以用多个手指进行缩放.
要实现这个功能,只需要这几步:
1.新建项目,在项目中新建一个ZoomImage.java
public class ZoomImageView extends View {
//初始化状态常量
public static final int STATUS_INIT=1;
//图片放大状态常量
public static final int STATUS_ZOOM_OUT=2;
//图片缩小状态常量
public static final int STATUS_ZOOM_IN=3;
//图片拖动状态的常量
public static final int STATUS_MOVE=4;
//对图片进行移动和缩放的矩阵
private Matrix matrix=new Matrix();
//需要处理的Bitmap对象
private Bitmap sourceBitmap;
//记录当前的操作状态
private int currentStatus;
//ZoomImageView的宽度
private int width;
//ZoomImageView的高度
private int height;
//记录两指同时放在屏幕上时,中心点的横坐标
private float centerPointX;
//记录两指同时放在屏幕上时,中心点的纵坐标
private float centerPointY;
//记录当前图片的宽度
private float currentBitmapWidth;
//记录当前图片的高度
private float currentBitmapHeight;
//记录上次手指移动时的横坐标
private float lastXMove=-1;
//记录上次手指移动时的纵坐标
private float lastYMove=-1;
//记录手指在横坐标上的距离
private float moveDistanceX;
//记录手指在纵坐标上的距离
private float moveDistanceY;
//记录图片在矩阵上横向偏移值
private float totalTranslateX;
//记录图片在矩阵上纵向偏移值
private float totalTranslateY;
//记录图片在矩阵上总缩放比例
private float totalRatio;
//记录手指移动的距离造成的缩放比例
private float scaledRatio;
//记录图片初始化时的缩放比例
private float initRatio;
//记录上次手指之间的距离
private double lastFingerDis;
//初始状态 设置当前操作状态为STATUS_INIT
public ZoomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
currentStatus=STATUS_INIT;
}
//将待展示的图片设置进来
public void setImageBitmap(Bitmap bitmap){
sourceBitmap=bitmap;
invalidate();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
if(changed){
width=getWidth();
height=getHeight();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_POINTER_DOWN:
if(event.getPointerCount()==2){
lastFingerDis=distanceBetweenFingers(event); //两指间按下的距离
}
break;
case MotionEvent.ACTION_MOVE:
if(event.getPointerCount()==1){ //如果只有一个手指在屏幕上 则为拖动模式
float xMove=event.getX();
float yMove=event.getY();
if(lastXMove==-1&&lastYMove==-1){
lastXMove=xMove;
lastYMove=yMove;
}
currentStatus=STATUS_MOVE;
moveDistanceX=xMove-lastXMove;
moveDistanceY=yMove-lastYMove;
//进行边界检查 不允许拖出边界
if(totalTranslateX+moveDistanceX>0){
moveDistanceX=0;
}
else if(width-(totalTranslateX+moveDistanceX)>currentBitmapWidth){
moveDistanceX=0;
}
if(totalTranslateY+moveDistanceY>0){
moveDistanceY=0;
}
else if(height-(totalTranslateY+moveDistanceY)>currentBitmapHeight){
moveDistanceY=0;
}
//调用onDraw()方法绘制图片
invalidate();
lastXMove=xMove;
lastYMove=yMove;
}
else if(event.getPointerCount()==2){
//有两个手指在屏幕上移动 为缩放状态
centerPointBetweenFingers(event);
double fingerDis=distanceBetweenFingers(event);
if(fingerDis>lastFingerDis){
currentStatus=STATUS_ZOOM_OUT;
}
else{
currentStatus=STATUS_ZOOM_IN;
}
//进行缩放倍数检查
if((currentStatus==STATUS_ZOOM_OUT&&totalRatio<4*initRatio)||(currentStatus==STATUS_ZOOM_IN&&totalRatio>initRatio)){
scaledRatio=(float) (fingerDis/lastFingerDis); //需要缩放的比例
totalRatio=totalRatio*scaledRatio;
if(totalRatio>4*initRatio){
totalRatio=4*initRatio;
}
else if(totalRatio<initRatio){
totalRatio=initRatio;
}
//调用onDraw
invalidate();
lastFingerDis=fingerDis;
}
}
break;
case MotionEvent.ACTION_POINTER_UP:
if(event.getPointerCount()==2){
lastXMove=-1;
lastYMove=-1;
}
break;
case MotionEvent.ACTION_UP:
lastXMove=-1;
lastYMove=-1;
break;
default:
break;
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (currentStatus) {
case STATUS_ZOOM_OUT:
case STATUS_ZOOM_IN:
zoom(canvas);
break;
case STATUS_MOVE:
move(canvas);
break;
case STATUS_INIT:
initBitmap(canvas);
break;
default:
canvas.drawBitmap(sourceBitmap, matrix, null);
break;
}
}
//初始化显示图片
private void initBitmap(Canvas canvas){
if(sourceBitmap!=null){
matrix.reset();
int bitmapWidth=sourceBitmap.getWidth();
int bitmapHeight=sourceBitmap.getHeight();
if(bitmapWidth>width||bitmapHeight>height){//如果图片的宽度或高度有大于屏幕宽高
if(bitmapWidth-width>bitmapHeight-height){ //判断这张图片 是宽度长 还是高度长 如果是宽度长,则按宽度的那边进行压缩 高度也等比例压缩
float radio=width/(bitmapWidth*1.0f); //需要压缩的比例
matrix.postScale(radio,radio); //缩放矩阵比例
float translateY=(height-(bitmapHeight*radio))/2f; //因为是按宽度进行压缩 所以宽度应该是占满全屏 这时候还应该将图片Y轴向下移动
//在纵坐标上进行偏移 以保证图片居中显示
matrix.postTranslate(0, translateY);
totalTranslateY=translateY;
totalRatio=initRatio=radio;
}
else{
//当图片高度大于屏幕高度时
float radio=height/(bitmapHeight*1.0f);
matrix.postScale(radio, radio);
float translateX=(width-(bitmapWidth*radio))/2f;
//在横坐标上进行偏移
matrix.postTranslate(translateX, 0);//平移
totalTranslateX=translateX;
totalRatio=initRatio=radio;
}
}
else{
//当图片的宽度与高度都小于屏幕宽高时,让图片居中显示
float translateX=(width-sourceBitmap.getWidth())/2f;
float translateY=(height-sourceBitmap.getHeight())/2f;
matrix.postTranslate(translateX, translateY);
totalTranslateX=translateX;
totalTranslateY=translateY;
totalRatio=initRatio=1f;
currentBitmapHeight=bitmapHeight;
currentBitmapWidth=bitmapWidth;
}
canvas.drawBitmap(sourceBitmap, matrix, null);
}
}
//对图片进行缩放处理
private void zoom(Canvas canvas){
matrix.reset();
//将图片按照比例缩放
matrix.postScale(totalRatio, totalRatio);
float scaledWidth=sourceBitmap.getWidth()*totalRatio;
float scaledHeight=sourceBitmap.getHeight()*totalRatio;
float translateX=0f;
float translateY=0f;
//如果当前图片宽度小于屏幕宽度 则按屏幕中心点 进行水平缩放,否则按两指中线点的横坐标进行缩放
if(currentBitmapWidth<width){
translateX=(width-scaledWidth)/2f;
}
else{
translateX=totalTranslateX*scaledRatio+centerPointX*(1-scaledRatio);
//进入边界检查 ,保证图片缩放后水平方向不会偏移屏幕
if(translateX>0){
translateX=0;
}
else if(width-translateX>scaledWidth){
translateX=width-scaledWidth;
}
}
if(currentBitmapHeight<height){
translateY=(height-scaledHeight)/2f;
}
else{
translateY=totalTranslateY*scaledRatio+centerPointY*(1-scaledRatio);
//进行边界检查
if(translateY>0){
translateY=0;
}
else if(height-translateY>scaledHeight){
translateY=height-scaledHeight;
}
}
//缩放后对图片进行偏移 保证缩放后中心点位置不变
matrix.postTranslate(translateX, translateY);
totalTranslateX=translateX;
totalTranslateY=translateY;
currentBitmapWidth=scaledWidth;
currentBitmapHeight=scaledHeight;
canvas.drawBitmap(sourceBitmap, matrix, null);
}
//对图片进行平移处理
private void move(Canvas canvas){
matrix.reset();
//根据手指移动的距离计算总偏移量
float translateX=totalTranslateX+moveDistanceX;
float translateY=totalTranslateY+moveDistanceY;
//按照已有的缩放比例对图片缩放
matrix.postScale(totalRatio, totalRatio);
//根据移动距离进行偏移
matrix.postTranslate(translateX, translateY);
totalTranslateX=translateX;
totalTranslateY=translateY;
canvas.drawBitmap(sourceBitmap, matrix, null);
}
//计算两个手指的距离
private double distanceBetweenFingers(MotionEvent event){
float disX=Math.abs(event.getX(0)-event.getX(1));
float disY=Math.abs(event.getY(0)-event.getY(1));
return Math.sqrt(disX*disX+disY*disY);
}
//计算两个手指之间中心点的坐标
private void centerPointBetweenFingers(MotionEvent event){
float xPoint0=event.getX(0);
float yPoint0=event.getY(0);
float xPoint1=event.getX(1);
float yPoint1=event.getY(1);
centerPointX=(xPoint0+xPoint1)/2;
centerPointY=(yPoint0+yPoint1)/2;
}
}
2.打开activity_main.xml
<com.example.bitmaptest.ZoomImageView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/zoom_image"
tools:context="com.example.bitmaptest.MainActivity" >
3.打开MainActivity.java
public class MainActivity extends ActionBarActivity {
private Bitmap bitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ZoomImageView zoomImage=(ZoomImageView) findViewById(R.id.zoom_image);
bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
if(bitmap!=null){
zoomImage.setImageBitmap(bitmap);
}
}
}
qq3061280@163.com