多点触碰实现图片的放大缩小

MainActivity

package com.ce.duodian;

import com.ce.view.MyView;

import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.Menu;

public class MainActivity extends Activity {

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        MyView view = (MyView) findViewById(R.id.img);
        Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(),
                R.drawable.a);
        view.setImage(bitmap);  
    }  
}

//自定义View

package com.ce.view;

import java.util.Observable;
import java.util.Observer;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class MyView extends View implements Observer {

/** Paint object used when drawing bitmap. */
    private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);

/** Rectangle used (and re-used) for cropping source image. */
    private final Rect mRectSrc = new Rect();

/** Rectangle used (and re-used) for specifying drawing area on canvas. */
    private final Rect mRectDst = new Rect();

/** Object holding aspect quotient */
    private final AspectQuotient mAspectQuotient = new AspectQuotient();

/** The bitmap that we‘re zooming in, and drawing on the screen. */
    private Bitmap mBitmap;

/** State of the zoom. */
    private ZoomState mState;

private BasicZoomControl mZoomControl;
    private BasicZoomListener mZoomListener;

public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);

mZoomControl = new BasicZoomControl();

mZoomListener = new BasicZoomListener();
        mZoomListener.setZoomControl(mZoomControl);

setZoomState(mZoomControl.getZoomState());

setOnTouchListener(mZoomListener);

mZoomControl.setAspectQuotient(getAspectQuotient());
    }

public void zoomImage(float f, float x, float y) {
        mZoomControl.zoom(f, x, y);
    }

public void setImage(Bitmap bitmap) {
        mBitmap = bitmap;

mAspectQuotient.updateAspectQuotient(getWidth(), getHeight(),
                mBitmap.getWidth(), mBitmap.getHeight());
        mAspectQuotient.notifyObservers();

invalidate();
    }

private void setZoomState(ZoomState state) {
        if (mState != null) {
            mState.deleteObserver(this);
        }

mState = state;
        mState.addObserver(this);

invalidate();
    }

private AspectQuotient getAspectQuotient() {
        return mAspectQuotient;
    }

@Override
    protected void onDraw(Canvas canvas) {
        if (mBitmap != null && mState != null) {

Log.d("ZoomImageView", "OnDraw");

final float aspectQuotient = mAspectQuotient.get();

final int viewWidth = getWidth();
            final int viewHeight = getHeight();
            final int bitmapWidth = mBitmap.getWidth();
            final int bitmapHeight = mBitmap.getHeight();

Log.d("ZoomImageView", "viewWidth = " + viewWidth);
            Log.d("ZoomImageView", "viewHeight = " + viewHeight);
            Log.d("ZoomImageView", "bitmapWidth = " + bitmapWidth);
            Log.d("ZoomImageView", "bitmapHeight = " + bitmapHeight);

final float panX = mState.getPanX();
            final float panY = mState.getPanY();
            final float zoomX = mState.getZoomX(aspectQuotient) * viewWidth
                    / bitmapWidth;
            final float zoomY = mState.getZoomY(aspectQuotient) * viewHeight
                    / bitmapHeight;

// Setup source and destination rectangles
            mRectSrc.left = (int) (panX * bitmapWidth - viewWidth / (zoomX * 2));
            mRectSrc.top = (int) (panY * bitmapHeight - viewHeight
                    / (zoomY * 2));
            mRectSrc.right = (int) (mRectSrc.left + viewWidth / zoomX);
            mRectSrc.bottom = (int) (mRectSrc.top + viewHeight / zoomY);
            // mRectDst.left = getLeft();
            mRectDst.left = 0;
            mRectDst.top = 0;
            // mRectDst.right = getRight();
            mRectDst.right = getWidth();
            mRectDst.bottom = getHeight();

// Adjust source rectangle so that it fits within the source image.
            if (mRectSrc.left < 0) {
                mRectDst.left += -mRectSrc.left * zoomX;
                mRectSrc.left = 0;
            }
            if (mRectSrc.right > bitmapWidth) {
                mRectDst.right -= (mRectSrc.right - bitmapWidth) * zoomX;
                mRectSrc.right = bitmapWidth;
            }
            if (mRectSrc.top < 0) {
                mRectDst.top += -mRectSrc.top * zoomY;
                mRectSrc.top = 0;
            }
            if (mRectSrc.bottom > bitmapHeight) {
                mRectDst.bottom -= (mRectSrc.bottom - bitmapHeight) * zoomY;
                mRectSrc.bottom = bitmapHeight;
            }

mRectDst.left = 0;
            mRectDst.top = 0;
            mRectDst.right = viewWidth;
            mRectDst.bottom = viewHeight;

Log.d("ZoomImageView", "mRectSrc.top" + mRectSrc.top);
            Log.d("ZoomImageView", "mRectSrc.bottom" + mRectSrc.bottom);
            Log.d("ZoomImageView", "mRectSrc.left" + mRectSrc.left);
            Log.d("ZoomImageView", "mRectSrc.right" + mRectSrc.right);

Log.d("ZoomImageView", "mRectDst.top" + mRectDst.top);
            Log.d("ZoomImageView", "mRectDst.bottom" + mRectDst.bottom);
            Log.d("ZoomImageView", "mRectDst.left" + mRectDst.left);
            Log.d("ZoomImageView", "mRectDst.right" + mRectDst.right);

canvas.drawBitmap(mBitmap, mRectSrc, mRectDst, mPaint);
        }
    }

@Override
    protected void onLayout(boolean changed, int left, int top, int right,
            int bottom) {
        super.onLayout(changed, left, top, right, bottom);

mAspectQuotient.updateAspectQuotient(right - left, bottom - top,
                mBitmap.getWidth(), mBitmap.getHeight());
        mAspectQuotient.notifyObservers();
    }

@Override
    public void update(Observable observable, Object data) {
        invalidate();
    }

private class BasicZoomListener implements View.OnTouchListener {

/** Zoom control to manipulate */
        private BasicZoomControl mZoomControl;

private float mFirstX = -1;
        private float mFirstY = -1;
        private float mSecondX = -1;
        private float mSecondY = -1;

private int mOldCounts = 0;

/**
         * Sets the zoom control to manipulate
         *
         * @param control
         *            Zoom control
         */
        public void setZoomControl(BasicZoomControl control) {
            mZoomControl = control;
        }

public boolean onTouch(View v, MotionEvent event) {

switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mOldCounts = 1;
                mFirstX = event.getX();
                mFirstY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE: {
                float fFirstX = event.getX();
                float fFirstY = event.getY();

int nCounts = event.getPointerCount();

if (1 == nCounts) {
                    mOldCounts = 1;
                    float dx = (fFirstX - mFirstX) / v.getWidth();
                    float dy = (fFirstY - mFirstY) / v.getHeight();
                    mZoomControl.pan(-dx, -dy);
                } else if (1 == mOldCounts) {
                    mSecondX = event.getX(event.getPointerId(nCounts - 1));
                    mSecondY = event.getY(event.getPointerId(nCounts - 1));
                    mOldCounts = nCounts;
                } else {
                    float fSecondX = event
                            .getX(event.getPointerId(nCounts - 1));
                    float fSecondY = event
                            .getY(event.getPointerId(nCounts - 1));

double nLengthOld = getLength(mFirstX, mFirstY, mSecondX,
                            mSecondY);
                    double nLengthNow = getLength(fFirstX, fFirstY, fSecondX,
                            fSecondY);

float d = (float) ((nLengthNow - nLengthOld) / v.getWidth());

mZoomControl.zoom((float) Math.pow(20, d),
                            ((fFirstX + fSecondX) / 2 / v.getWidth()),
                            ((fFirstY + fSecondY) / 2 / v.getHeight()));

mSecondX = fSecondX;
                    mSecondY = fSecondY;
                }
                mFirstX = fFirstX;
                mFirstY = fFirstY;

break;
            }

}

return true;
        }

private double getLength(float x1, float y1, float x2, float y2) {
            return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
        }
    }

private class BasicZoomControl implements Observer {

/** Minimum zoom level limit */
        private static final float MIN_ZOOM = 1;

/** Maximum zoom level limit */
        private static final float MAX_ZOOM = 16;

/** Zoom state under control */
        private final ZoomState mState = new ZoomState();

/** Object holding aspect quotient of view and content */
        private AspectQuotient mAspectQuotient;

/**
         * Set reference object holding aspect quotient
         *
         * @param aspectQuotient
         *            Object holding aspect quotient
         */
        public void setAspectQuotient(AspectQuotient aspectQuotient) {
            if (mAspectQuotient != null) {
                mAspectQuotient.deleteObserver(this);
            }

mAspectQuotient = aspectQuotient;
            mAspectQuotient.addObserver(this);
        }

/**
         * Get zoom state being controlled
         *
         * @return The zoom state
         */
        public ZoomState getZoomState() {
            return mState;
        }

/**
         * Zoom
         *
         * @param f
         *            Factor of zoom to apply
         * @param x
         *            X-coordinate of invariant position
         * @param y
         *            Y-coordinate of invariant position
         */
        public void zoom(float f, float x, float y) {

// Log.d("Zoom", "zoom f = " + f);

final float aspectQuotient = mAspectQuotient.get();

final float prevZoomX = mState.getZoomX(aspectQuotient);
            final float prevZoomY = mState.getZoomY(aspectQuotient);

mState.setZoom(mState.getZoom() * f);
            limitZoom();

final float newZoomX = mState.getZoomX(aspectQuotient);
            final float newZoomY = mState.getZoomY(aspectQuotient);

// Pan to keep x and y coordinate invariant
            mState.setPanX(mState.getPanX() + (x - .5f)
                    * (1f / prevZoomX - 1f / newZoomX));
            mState.setPanY(mState.getPanY() + (y - .5f)
                    * (1f / prevZoomY - 1f / newZoomY));

limitPan();

mState.notifyObservers();
        }

/**
         * Pan
         *
         * @param dx
         *            Amount to pan in x-dimension
         * @param dy
         *            Amount to pan in y-dimension
         */
        public void pan(float dx, float dy) {
            final float aspectQuotient = mAspectQuotient.get();

mState.setPanX(mState.getPanX() + dx
                    / mState.getZoomX(aspectQuotient));
            mState.setPanY(mState.getPanY() + dy
                    / mState.getZoomY(aspectQuotient));

limitPan();

mState.notifyObservers();
        }

/**
         * Help function to figure out max delta of pan from center position.
         *
         * @param zoom
         *            Zoom value
         * @return Max delta of pan
         */
        private float getMaxPanDelta(float zoom) {
            return Math.max(0f, .5f * ((zoom - 1) / zoom));
        }

/**
         * Force zoom to stay within limits
         */
        private void limitZoom() {
            if (mState.getZoom() < MIN_ZOOM) {
                mState.setZoom(MIN_ZOOM);
            } else if (mState.getZoom() > MAX_ZOOM) {
                mState.setZoom(MAX_ZOOM);
            }
        }

/**
         * Force pan to stay within limits
         */
        private void limitPan() {
            final float aspectQuotient = mAspectQuotient.get();

final float zoomX = mState.getZoomX(aspectQuotient);
            final float zoomY = mState.getZoomY(aspectQuotient);

final float panMinX = .5f - getMaxPanDelta(zoomX);
            final float panMaxX = .5f + getMaxPanDelta(zoomX);
            final float panMinY = .5f - getMaxPanDelta(zoomY);
            final float panMaxY = .5f + getMaxPanDelta(zoomY);

if (mState.getPanX() < panMinX) {
                mState.setPanX(panMinX);
            }
            if (mState.getPanX() > panMaxX) {
                mState.setPanX(panMaxX);
            }
            if (mState.getPanY() < panMinY) {
                mState.setPanY(panMinY);
            }
            if (mState.getPanY() > panMaxY) {
                mState.setPanY(panMaxY);
            }
        }

// Observable interface implementation

public void update(Observable observable, Object data) {
            limitZoom();
            limitPan();
        }
    }

private class AspectQuotient extends Observable {

/**
         * Aspect quotient
         */
        private float mAspectQuotient;

// Public methods

/**
         * Gets aspect quotient
         *
         * @return The aspect quotient
         */
        public float get() {
            return mAspectQuotient;
        }

/**
         * Updates and recalculates aspect quotient based on supplied view and
         * content dimensions.
         *
         * @param viewWidth
         *            Width of view
         * @param viewHeight
         *            Height of view
         * @param contentWidth
         *            Width of content
         * @param contentHeight
         *            Height of content
         */
        public void updateAspectQuotient(float viewWidth, float viewHeight,
                float contentWidth, float contentHeight) {
            final float aspectQuotient = (contentWidth / contentHeight)
                    / (viewWidth / viewHeight);

if (aspectQuotient != mAspectQuotient) {
                mAspectQuotient = aspectQuotient;
                setChanged();
            }
        }
    }

private class ZoomState extends Observable {
        /**
         * Zoom level A value of 1.0 means the content fits the view.
         */
        private float mZoom;

/**
         * Pan position x-coordinate X-coordinate of zoom window center
         * position, relative to the width of the content.
         */
        private float mPanX;

/**
         * Pan position y-coordinate Y-coordinate of zoom window center
         * position, relative to the height of the content.
         */
        private float mPanY;

// Public methods

/**
         * Get current x-pan
         *
         * @return current x-pan
         */
        public float getPanX() {
            return mPanX;
        }

/**
         * Get current y-pan
         *
         * @return Current y-pan
         */
        public float getPanY() {
            return mPanY;
        }

/**
         * Get current zoom value
         *
         * @return Current zoom value
         */
        public float getZoom() {
            return mZoom;
        }

/**
         * Help function for calculating current zoom value in x-dimension
         *
         * @param aspectQuotient
         *            (Aspect ratio content) / (Aspect ratio view)
         * @return Current zoom value in x-dimension
         */
        public float getZoomX(float aspectQuotient) {
            return Math.min(mZoom, mZoom * aspectQuotient);
        }

/**
         * Help function for calculating current zoom value in y-dimension
         *
         * @param aspectQuotient
         *            (Aspect ratio content) / (Aspect ratio view)
         * @return Current zoom value in y-dimension
         */
        public float getZoomY(float aspectQuotient) {
            return Math.min(mZoom, mZoom / aspectQuotient);
        }

/**
         * Set pan-x
         *
         * @param panX
         *            Pan-x value to set
         */
        public void setPanX(float panX) {
            if (panX != mPanX) {
                mPanX = panX;
                setChanged();
            }
        }

/**
         * Set pan-y
         *
         * @param panY
         *            Pan-y value to set
         */
        public void setPanY(float panY) {
            if (panY != mPanY) {
                mPanY = panY;
                setChanged();
            }
        }

/**
         * Set zoom
         *
         * @param zoom
         *            Zoom value to set
         */
        public void setZoom(float zoom) {
            if (zoom != mZoom) {
                mZoom = zoom;
                setChanged();
            }
        }
    }
}

时间: 2024-11-05 22:55:56

多点触碰实现图片的放大缩小的相关文章

Android基础入门教程——3.4 TouchListener PK OnTouchEvent + 多点触碰

Android基础入门教程--3.4 TouchListener PK OnTouchEvent + 多点触碰 标签(空格分隔): Android基础入门教程 本节引言: 如题,本节给大家带来的是TouchListener与OnTouchEvent的比较,以及多点触碰的知识点! TouchListener是基于监听的,而OnTouchEvent则是基于回调的!下面通过两个简单的例子来加深 大家的理解! 1.基于监听的TouchListener 代码示例: 实现效果图: 实现代码: main.xm

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

本文主要介绍Android的多点触控,使用了一个图片缩放的实例,来更好的说明其原理.需要实现OnTouchListener接口,重写其中的onTouch方法. 实现效果图: 源代码: 布局文件: activity_main: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools&quo

UIButon 控件的尺寸放大缩小(也可以理解为图片的放大缩小,思路是一样的)-学习笔记

图片的放大缩小功能的简单实现(以一个简单的猜图项目中的放大缩小为例) 思路: 1.创建一个UIButton * guessimage  控件,设定好位置,再创建一个button bigImage控件测试一下 放大图片的方法 goToBig,同样放好位置: 2.给 guessimage 设置边距,尺寸大小,同样 bigImage 也进行设置等等: 3.给 bigImage 添加点击 放大图片的方法:goToBig, 在goToBig里面 定义 4个 座标的值,也就是 CGFloat guessim

Android 本地/网路下载图片实现放大缩小

 Android 本地加载/网路下载图片实现放大缩小拖拉效果,自定义控件. package com.example.ImageViewCustom; import android.app.Activity; import android.os.Bundle; import com.example.ImageViewCustom.CustomControl.MImageView; public class MyActivity extends Activity { MImageView mImag

9. Cocos2d-x 游戏编程 之 多点触碰

上一篇内容讲了 单点触碰,然后这篇接着讲 多点触碰.多点触碰就是说,多个手指同时在屏幕上操作,然后触发监听器,回调方法实现功能而已. 1.先了解这个代码如何在手机上调试.因为这个是关乎到多个手指触碰才能触发的监听器,所以说,在模拟器上实现不了手指的触碰.必须在真机上跑才行. 其实很简单,只要在项目中的 ios 这个文件夹中的 AppController.mm 文件里边的 - (BOOL)application:(UIApplication *)application didFinishLaunc

unity3D实现多点触碰

实现多点触碰是利用input这个类里面的方法实现的. 从edit-project settings-input就可以看到input能够得到的轴. 想要读取轴向可以使用Input.GetAxis方法获取下列默认轴: "Horizontal" 和"Vertical" 映射于控制杆.A.W.S.D和箭头键(方向键). "Mouse X" 和"Mouse Y" 映射于鼠标,"Fire1", "Fire2&

Java界面程序实现图片的放大缩小

Java界面程序实现图片的放大缩小.这个程序简单地实现了图片的打开.保存.放大一倍.缩小一倍和固定缩放尺寸,但是并没有过多的涵盖对图片的细节处理,只是简单地实现了图片大小的放缩. 思维导图如下: 效果图如下: 代码如下: package picture; import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import javax.swing.*; import java.io.*; i

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

首先推荐一下鸿洋大大的打造个性的图片预览与多点触控视频教程,这套教程教我们一步一步实现了多点触控实现对图片的平移和缩放的功能,这篇文章我将在鸿洋大大的基础之上做了一些扩展功能: 1.图片的惯性滑动 2.图片缩放小于正常比例时,松手会自动回弹成正常比例 3.图片缩放大于最大比例时,松手会自动回弹成最大比例 实现图片的缩放,平移,双击缩放等基本功能的代码如下,每一行代码我都做了详细的注释 public class ZoomImageView extends ImageView implements

ViewPager图片预览之图片的放大缩小,移动,切换(第三课)连载

第三课(第三步):支持以手指触控的任意点为中心开始缩放 关键部分是在缩放的时候不断进行边界检测,防止放大后缩小后出现白边: /** * 在缩放的时候进行边界控制范围位置控制 */ private void checkBorderAndCenterWhenScale() { // TODO Auto-generated method stub RectF rect = getMatrixRectF(); float deltaX = 0; float deltaY = 0; float width