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

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. Javascript的加载

    最新博客站点:欢迎来访 1. 浏览器加载     (1) 同步加载 在网页中,浏览器加载js文件的方式是通过<script>标签.如下所示: //内嵌脚本 <script type= ...

  2. loushang框架的开发中关于BSP的使用,将写好的功能模块部署到主页界面结构上

    前言: 当我们已经开发好相应的模块或者功能的时候,需要将这个功能部署在index主页上作为可点击直接使用的模块,而不是每次需要去浏览对应的url地址. 这时候就需要运用到L5的BSP. 作为刚刚入门l ...

  3. bean工具类

    package com.zq.utils; import java.lang.reflect.Method;import java.util.Arrays;import java.util.Colle ...

  4. web3.js_1.x.x--API(一)event/Constant/deploy/options

    /* 事件是使用EVM日志内置功能的方便工具,在DAPP的接口中,它可以反过来调用Javascript的监听事件的回调. 事件在合约中可被继承.当被调用时,会触发参数存储到交易的日志中(一种区块链上的 ...

  5. emlog博客插件分享openSug

    emlog博客插件百度搜索下拉提示框openSug.js发布上线啦: 下载:https://www.opensug.org/faq/.../opensug.emlog_v1.0.0.zip[~4KB]

  6. JavaScript Shell学习分享

    目录 JavaScript Shell学习分享 简介 安装 使用原因 小结 JavaScript Shell学习分享 简介 JavaScript Shell是由Mozilla提供的综合JavaScri ...

  7. python中协程实现的本质以及两个封装协程模块greenle、gevent

    协程 协程,又称微线程,纤程.英文名Coroutine. 协程是啥 协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源). 为啥说它是一个执行单元,因为 ...

  8. PHP中文乱码分类及解决办法大全

    PHP+MYSQL做网站开发通常都会碰到浏览器输出中文字符时乱码,这个问题的原因主要是因为HTML内容编码,PHP文件编码和MySQL数据库编码这三者不一致造成的.下面我们以UTF-8为例简述一下如何 ...

  9. Go语言使用百度翻译api

    Go语言使用百度翻译api 之前做过一个使用百度翻译api的工具,这个工具用于用户的自动翻译功能,是使用C#调用百度翻译api接口,既然在学习Go语言,那必然也是要使用Go来玩耍一番.这里我是这么安排 ...

  10. (数据科学学习手札23)决策树分类原理详解&Python与R实现

    作为机器学习中可解释性非常好的一种算法,决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方 ...