Android开发ImageView控件缩放图片(二)

该博客文章深入探讨了在Android开发中如何使用Matrix实现ImageView图片的缩放和平移,尤其是如何限制缩放范围和拖动边界。作者通过分析ImageView控件的不足,提出使用matrix操作来实现更流畅的图片缩放效果。文章详细介绍了关键变量的设置和ImageState类的设计,用于记录图片的实时参数,并提供了主要函数的实现方法。

本文是继续上一篇文章,接着讲ImageView图片缩放实现。上一文中已经实现了手势进行放大缩小,平移的效果。

主要解决的问题是:如何限制放大缩小的范围,以及拖动的边界控制。

我在网上搜索相关内容的时候,比较多的是Imageview控件的缩放,例如这篇文章:http://blog.youkuaiyun.com/jj120522/article/details/8467810

我的思路其中也参考了这篇文章,但是感觉ImageView控件缩放起来没有matrix缩放图片更流畅,更自然。


所以,我的思路是获取ImageView控件中图片的四周位置,然后进行控制。

1, 主要变量如下:

    private class ImageState
	{
		float left;
		float right;
		float top;
		float bottom;
		float width;    //图片的宽度
		float height;  
        }
        private float mScrWidth;      //ImageView宽度
	private float mScrHeight;      
	private float mMaxWidth;      //放大的最大宽度
	private float mMaxHeight;


其中,ImageState实时记录图片的参数,其他变量是控制的范围。

另外还有两个重要的变量:

private boolean m_IsHorCon = false;
private boolean m_IsVerCon = false;

这两个参数是判断水平/垂直是否已经超出了ImageView控件的宽度,因为如果超出了,所作的处理是不一样的。

例如:水平宽度如果比ImageView控件宽度小,则向左拖动需要保证left>=0, 否则就不能继续拖动了;而if(width> mSrcWidth) if(right <= mSrcWidth) 不能再向左拖动了。。

2, 主要函数,获取ImageState

public void GetCurrentRange()
    {
    	Matrix matrix = mImageView.getImageMatrix();
		Rect rect = mImageView.getDrawable().getBounds();
		float[] values = new float[9];
		matrix.getValues(values);
		
		mMapState.SetLeft(values[2]);
		mMapState.SetTop(values[5]);
		if(Math.abs(mMapState.GetTop()) > mScrHeight)
		{
			Log.v("touch", "bug");
		}
		mMapState.SetWidth(rect.width()*values[0]);
		mMapState.SetHeight(rect.height()*values[0]);
		float right = mMapState.GetLeft() + mMapState.GetWidth();
		float bottom = mMapState.GetTop() + mMapState.GetHeight();
		mMapState.SetRight(right);
		if(bottom == mMapState.GetTop())
		{
			Log.v("touch", "bug2");
		}
		mMapState.SetBottom(bottom);
    }

主要内容就这些,下面把所有代码都贴上来,是一个MyImageScale.java文件

使用方法如下:

myImgScale = new MyImageScale(imgView, mBmp, imgWidth, imgHeight); //
imgView.setOnTouchListener(myImgScale);

//imgView 为控件对象,mBmp为控件中的bitmap图片,imgWidth, imgHeight为指定的ImageView控件长宽,因为我在OnCreate函数中设置的,此时不能正确得到imgView控件的长宽。。

下面是MyImageScale.java文件

package com.walkinfo.walkiofficeandroid.media;

import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;


/* by sun 2014-4-11
 * 实现ImageView图片预览-放大缩小功能
 * edited 2014-4-14
 * 改进:在ImageView范围内缩放,缩放范围控制。
 * */
public class MyImageScale implements OnTouchListener {

	private ImageView mImageView;
	private Bitmap    mBmp;
	private int mMode;    //模式:1-拉动;2-缩放
	final private int DRAGMODE = 1;
	final private int ZOOMMODE = 2;
	
	private PointF   mStarPt = new PointF();
	private float    mStarDis;
	private PointF   mMidPt = new PointF();
	
	private Matrix mMatrix = new Matrix();
	private Matrix mCurrMatrix = new Matrix();
	
	private boolean m_IsHorCon = false;
	private boolean m_IsVerCon = false;
	
	private class ImageState
	{
		float left;
		float right;
		float top;
		float bottom;
		float width;    //图片的宽度
		float height;   //图片的高度
		
		float GetLeft(){ return left;}
		float GetRight(){ return right;}
		float GetTop(){ return top;}
		float GetBottom(){ return bottom;}
		float GetWidth(){ return width;}
		float GetHeight(){ return height;}
		void SetLeft(float l){left = l;}
		void SetRight(float r){right = r;}
		void SetTop(float t){top = t;}
		void SetBottom(float b){bottom  = b;}
		void SetWidth(float w){ width = w;}
		void SetHeight(float h){ height = h;}
	}
	
	
	//图片位置参数
	private ImageState mMapState = new ImageState();
	
	private float mScrWidth;    //ImageView宽度
	private float mScrHeight;   //ImageView高度
	private float mMaxWidth;
	private float mMaxHeight;
	
	public MyImageScale(ImageView imgView, Bitmap bm, int width, int height)
	{
		mImageView = imgView;
		mBmp = bm;
		mScrWidth = imgView.getWidth();
		mScrHeight = imgView.getHeight();
		if(bm != null)
		{
			mMaxWidth = bm.getWidth()*2;
			mMaxHeight = bm.getHeight()*2;
		}
		else
		{
			mMaxWidth = 0;
			mMaxHeight = 0;
		}
		//
		if(mScrWidth <= 0 || mScrHeight <= 0)
		{
			mScrWidth = width;
			mScrHeight = height;
		}
		GetCurrentRange();
	}
	
	public void SetPara(ImageView imgView, Bitmap bm)
	{
		if(mScrWidth <= 0 || mScrHeight <= 0)
		{
			mScrWidth = imgView.getWidth();
			mScrHeight = imgView.getHeight();
		}
		if(mMaxWidth <= 0 || mMaxHeight <= 0)
		{
			mMaxWidth = bm.getWidth()*2;
			mMaxHeight = bm.getHeight()*2;
		}
	}
	
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		// TODO Auto-generated method stub
		switch(event.getAction() & MotionEvent.ACTION_MASK)
		{
		//单指按下
		case MotionEvent.ACTION_DOWN:
		{
		    mMode = DRAGMODE;
		    mStarPt.set(event.getX(), event.getY());
		    mCurrMatrix = mImageView.getImageMatrix();
		    Log.v("touch", "drag");
		    break;
		}
		//多指缩放的按下
		case MotionEvent.ACTION_POINTER_DOWN:
		{
			mMode = ZOOMMODE;
			mStarDis = GetDistance(event);
			mMidPt   = GetMidPt(event);
			mCurrMatrix = mImageView.getImageMatrix();
			break;
		}
		//移动
		case MotionEvent.ACTION_MOVE:
		{
			if(mMode == DRAGMODE)
			{
				float left = 0, top = 0, right = 0, bottom = 0;
				float dx = event.getX() - mStarPt.x;
				float dy = event.getY() - mStarPt.y;
				left = mMapState.GetLeft() + dx;
				right = mMapState.GetRight() + dx;
				top  = mMapState.GetTop() + dy;
				bottom = mMapState.GetBottom() + dy;
				
				if (m_IsHorCon) {
					//左移动,越界控制
					if (left > 0) {
						left = 0;
						dx = left - mMapState.GetLeft();
					}
					if (right < mScrWidth) {
						right = mScrWidth;
						dx = right - mMapState.GetRight();
					}
				}
				else {
					if(left < 0)
					{
						left = 0;
						dx = left - mMapState.GetLeft();
					}
					if(right > mScrWidth)
					{
						right = mScrWidth;
						dx = mScrWidth - mMapState.GetRight();
					}
						
				}
				
				if (m_IsVerCon) {
					if (top > 0) {
						dy = 0 - mMapState.GetTop();
					}

					if (bottom < mScrHeight) {
						dy = mScrHeight-mMapState.GetBottom();
					}
				} else {
					if (top < 0) {
						dy = 0 - mMapState.GetTop();
					}

					if (bottom > mScrHeight) {
						dy = mScrHeight - mMapState.GetBottom();
					}
				}
				
				if(Math.abs(dx) > mScrWidth)
					dx = mScrWidth;
				if(Math.abs(dy) > mScrHeight)
					dy = mScrHeight;
				
				mMatrix.set(mCurrMatrix);
				mMatrix.postTranslate(dx, dy);
				mStarPt.set(event.getX(), event.getY());
			}
			else if(mMode == ZOOMMODE)
			{
				float endDis = GetDistance(event);
				if (endDis > 10f)
				{
					float fScale = endDis /mStarDis;
					mMatrix.set(mCurrMatrix);
					if(fScale < 1)
					{
						if(mMapState.GetWidth() < mScrWidth && mMapState.GetHeight() < mScrHeight)
							return true;
					}
					else
					{
						if(mMapState.GetWidth() > mMaxWidth && mMapState.GetHeight() > mMaxHeight)
							return true;
					}
					
					mMatrix.postScale(fScale, fScale, mMidPt.x, mMidPt.y);
					
					//String strMsg = String.format("%d, %d", mImageView.getWidth(), mBmp.getWidth());
					//Log.v("touch", strMsg);
					mStarDis = endDis;
				}
			}
			mImageView.setImageMatrix(mMatrix);
			break;
		}
		//单指抬起
		case MotionEvent.ACTION_UP:
		//多指抬起
		case MotionEvent.ACTION_POINTER_UP:
		{
			mMode = 0;
			break;
		}
		
		}
		
		GetCurrentRange();
		//判断是否越界了
		if(mMapState.GetWidth() > mScrWidth)
			m_IsHorCon = true;
		else
			m_IsHorCon = false;
		if(mMapState.GetHeight() > mScrHeight)
			m_IsVerCon = true;
		else
			m_IsVerCon = false;
		return true;
	}
	
	private float GetDistance(MotionEvent event)
	{
		float dx = event.getX(1) - event.getX(0);
		float dy = event.getY(1) - event.getY(0);
		return FloatMath.sqrt(dx*dx+dy*dy);
	}
	
	  
    private PointF GetMidPt(MotionEvent event) {  
        float midX = (event.getX(1) + event.getX(0)) / 2;  
        float midY = (event.getY(1) + event.getY(0)) / 2;  
        return new PointF(midX, midY);  
    }  
    
    
    //然后获取ImageView的matrix,根据matrix的getValues获得3x3矩阵。

    public void GetCurrentRange()
    {
    	Matrix matrix = mImageView.getImageMatrix();
		Rect rect = mImageView.getDrawable().getBounds();
		float[] values = new float[9];
		matrix.getValues(values);
		
		mMapState.SetLeft(values[2]);
		mMapState.SetTop(values[5]);
		if(Math.abs(mMapState.GetTop()) > mScrHeight)
		{
			Log.v("touch", "bug");
		}
		mMapState.SetWidth(rect.width()*values[0]);
		mMapState.SetHeight(rect.height()*values[0]);
		float right = mMapState.GetLeft() + mMapState.GetWidth();
		float bottom = mMapState.GetTop() + mMapState.GetHeight();
		mMapState.SetRight(right);
		if(bottom == mMapState.GetTop())
		{
			Log.v("touch", "bug2");
		}
		mMapState.SetBottom(bottom);
    }

}



评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值