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





