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

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. linux保留旧版本python,安装python3

    1.备份老版本 mv /usr/bin/python /usr/bin/python.bak 2. 下载python3 wget https://www.python.org/ftp/python/3 ...

  2. ABAP术语-Field

    Field 原文:http://www.cnblogs.com/qiangsheng/archive/2008/02/01/1061244.html Name in an ABAP program f ...

  3. Percona-Toolkit工具包之pt-archiver

      Preface       There's a common case that we neet to archive amount of records in some tables to a ...

  4. 上传文件到阿里云linux服务器

    在“运行”中输入cmd,打开控制台,切换到刚才Putty的安装目录下,我的是E:\Putty,然后输入pscp命令,我们需要这个命令来实现文件的上传.如下图所示,命令格式为: pscp D:\recy ...

  5. JAVAOOP I/O

    程序的主要任务就是操作数据,通过允许程序读取文件的内容或向文件写入数据,可以使程序应用更加广泛. I/O(input/output) 在不同操作系统之下,所占的字节数也不同,一般认为 8.1.1使用F ...

  6. Xcode升到7.1插件失效解决方法

    Mac前段时间下载了新的OS系统与Xcode 7.1,然而在使用Xcode 7.1时,发现插件不能用了,瞬间木有爱了,正好交流群里有人问到了插件失效的问题,经过各路大神的神通最终用下面这种方法完美解决 ...

  7. WinForm webbrowser控件的使用

    webbrowser是一个比较实用的工具,主要用于在winform窗体中嵌入浏览器,达到winform与webform互操作的目的. 先上一个demo,看一下能实现什么效果. private void ...

  8. mysql 5.7 配置初始化及修改 ROOT 用户密码

    1.修改配置文件 my.ini 放在 mysql\bin [mysqld] basedir=C:\Mysql datadir=C:\Mysql\data port=3306 # server_id = ...

  9. 8.2 USB键盘驱动编写和测试

    目标:根据USB驱动分析和上节的USB鼠标驱动,编写键盘驱动,并测试. 一.原理分析 1. 首先通过打印usb_buf[i]中的8字节数据,看一下按键按下之后会接收到什么. 1)通过按完所有键盘按键打 ...

  10. STM32(4)——系统时钟和SysTick

    1.STM32的时钟系统 在STM32中,一共有5个时钟源,分别是HSI.HSE.LSI.LSE.PLL HSI是高速内部时钟,RC振荡器,频率为8MHz: HSE是高速外部时钟,可接石英/陶瓷谐振器 ...