在系统的相册中,观看相片就可以用多个手指进行缩放.
要实现这个功能,只需要这几步:

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" >
    

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

}  

android多点触控自由对图片缩放的更多相关文章

  1. Android多点触控技术实战,自由地对图片进行缩放和移动

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11100327 在上一篇文章中我带着大家一起实现了Android瀑布流照片墙的效果, ...

  2. Android多点触控(图片的缩放Demo)

    本文主要介绍Android的多点触控,使用了一个图片缩放的实例,来更好的说明其原理.须要实现OnTouchListener接口,重写当中的onTouch方法. 实现效果图:       源码: 布局文 ...

  3. Android多点触控技术,实现对图片的放大缩小平移,惯性滑动等功能

    首先推荐一下鸿洋大大的打造个性的图片预览与多点触控视频教程,这套教程教我们一步一步实现了多点触控实现对图片的平移和缩放的功能.这篇文章我将在鸿洋大大的基础之上做了一些扩展功能: 1.图片的惯性滑动 2 ...

  4. Android多点触控技术

    1 简介 Android多点触控在本质上需要LCD驱动和程序本身设计上支持,目前市面上HTC.Motorola和Samsung等知名厂商只要使用电容屏触控原理的手机均可以支持多点触控Multitouc ...

  5. [yueqian_scut]Android多点触控技术和应用框架

    Android多点触控技术跟Linux输入子系统紧密相关.本文将从应用的角度说明Android多点触控技术的接口和应用. 一.多点触控场景分析 网络上有关Android多点触控技术的文章多见于两点拉伸 ...

  6. unity3d 触屏多点触控(旋转与缩放)

    unity3d 触屏多点触控(旋转与缩放) /*Touch OrbitProgrammed by: Randal J. Phillips (Caliber Mengsk)Original Creati ...

  7. Android 多点触控与简单手势(一)

    现在一般的Android手机都会使用电容触摸屏最少可以支持两点触摸,多的可能是七八个,所以基本上都会支持多点触控, android系统中应用程序可以使用多点触控的事件来完成各种手势和场景需求. And ...

  8. MultiTouch————多点触控,伸缩图片,变换图片位置

    前言:当今的手机都支持多点触控功能(可以进行图片伸缩,变换位置),但是我们程序员要怎样结合硬件去实现这个功能呢? 跟随我一起,来学习这个功能 国际惯例:先上DEMO免费下载地址:http://down ...

  9. 关于android多点触控

    最近项目需要一个多点触控缩放的功能.然后上网查了下资料 总结一下: 首先android sdk版本很重要,比如你在AndroidManifest.xml中指定android:minSdkVersion ...

随机推荐

  1. 菜鸟笔记 -- Chapter 6.2.6 内部类

    6.2.6  内部类 在权限修饰符中,我们已经见过内部类了,但我们看到的只是冰山一角,这节我们详细介绍一下内部类,内部类可以分为成员内部类,局部内部类,匿名内部类,静态内部类.下面我们来讲解一下,在讲 ...

  2. Python基础—13-面向对象及异常处理

    面向对象及异常处理 内置函数 总结:__init__.__del__.__str__.attr系列.item系列.__call__ __str__与__repr__ 使用print/str方法时会自动 ...

  3. Shiro 登录认证源码详解

    Shiro 登录认证源码详解 Apache Shiro 是一个强大且灵活的 Java 开源安全框架,拥有登录认证.授权管理.企业级会话管理和加密等功能,相比 Spring Security 来说要更加 ...

  4. 『ACM C++』PTA浙大 | 基础题 - 打印沙漏

    <数据结构>开课前的一些小作业练习,可能因为一个寒假都没有打C++手生了,整个寒假都在帮拍电影做后期特效,导致这道题居然用了两个钟去AC,深感惭愧,作个标记吧,下面上题. 一首好曲推荐:同 ...

  5. Kubernetes-ELK

    ElasticSearch日志搜集查询和展现案例 容器中输出到控制台的日志都会以*-json.log的命名方式存储在/var/lib/container目录之下: Kubernetes采用Fluent ...

  6. R语言学习笔记(十三):零碎知识点(36-40)

    36--diag() 如果它的参数是一个矩阵,它返回的是一个向量 如果它的参数是一个向量,它返回的是一个向量 如果它的参数是一个标量,它返回的是指定大小的单位矩阵 > diag(2) [,1] ...

  7. Servlet生命周期与线程安全

    上一篇介绍了Servlet初始化,以及如何处理HTTP请求,实际上在这两个过程中,都伴随着Servlet的生命周期,都是Servlet生命周期的一部分.同时,由于Tomcat容器默认是采用单实例多线程 ...

  8. VGA 时序标准

    VGA 显示器扫描方式从屏幕左上角一点开始,从左像右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,CRT 对电子束进行消隐,每行结束时,用行同步信号进行同步:当扫描完所有的行 ...

  9. Django-modelfrom组件

    ModelForm     a.  class Meta:             model,                           # 对应Model的             fi ...

  10. dubbo心跳机制 (1)

    此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. dubbo的心跳机制: 目的:检测provider与consumer之间的connection连接是不是还连 ...