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(sourceBitmapmatrixnull);
            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(sourceBitmapmatrixnull);
        }
    }
    
    //对图片进行缩放处理
    private void zoom(Canvas canvas){
        matrix.reset();
        //将图片按照比例缩放
        matrix.postScale(totalRatiototalRatio);
        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(sourceBitmapmatrixnull);
    }
    
    //对图片进行平移处理
    private void move(Canvas canvas){
        matrix.reset();
        //根据手指移动的距离计算总偏移量
        float translateX=totalTranslateX+moveDistanceX;
        float translateY=totalTranslateY+moveDistanceY;
        //按照已有的缩放比例对图片缩放
        matrix.postScale(totalRatiototalRatio);
        //根据移动距离进行偏移
        matrix.postTranslate(translateX, translateY);
        totalTranslateX=translateX;
        totalTranslateY=translateY;
        canvas.drawBitmap(sourceBitmapmatrixnull);
    }
    
    //计算两个手指的距离
    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" >
    
</com.example.bitmaptest.ZoomImageView>  

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);
        }
    }
}  




posted @ 2014-09-13 20:48  冷冷汤圆  阅读(622)  评论(0编辑  收藏  举报