双击图片不放大手机php,Android_Android App中实现可以双击放大和缩小图片功能的实例,先来看一个很简单的核心图片 - phpStudy...

Android App中实现可以双击放大和缩小图片功能的实例

先来看一个很简单的核心图片缩放方法:

public static Bitmap scale(Bitmap bitmap, float scaleWidth, float scaleHeight) {

int width = bitmap.getWidth();

int height = bitmap.getHeight();

Matrix matrix = new Matrix();

matrix.postScale(scaleWidth, scaleHeight);

Log.i(TAG, "scaleWidth:"+ scaleWidth +", scaleHeight:"+ scaleHeight);

return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);

}

注意要比例设置正确否则可能会内存溢出,比如曾经使用图片缩放时遇到这么个问题:

java.lang.IllegalArgumentException: bitmap size exceeds 32bits

后来一行行查代码,发现原来是 scale 的比例计算错误,将原图给放大了 20 多倍,导致内存溢出所致,重新修改比例值后就正常了。

好了,下面真正来看一下这个实现了放大和原大两个级别的缩放的模块。

功能有:

以触摸点为中心放大(这个是网上其他的代码没有的)

边界控制(这个是网上其他的代码没有的)

双击放大或缩小(主要考虑到电阻屏)

多点触摸放大和缩小

这个模块已经通过了测试,并且用户也使用有一段时间了,是属于比较稳定的了。

下面贴上代码及使用方法(没有写测试项目,大家见谅):

ImageControl 类似一个用户自定义的ImageView控件。用法将在下面的代码中贴出。

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.Matrix;

import android.util.AttributeSet;

import android.util.FloatMath;

import android.view.MotionEvent;

import android.widget.ImageView;

public class ImageControl extends ImageView {

public ImageControl(Context context) {

super(context);

// TODO Auto-generated constructor stub

}

public ImageControl(Context context, AttributeSet attrs) {

super(context, attrs);

// TODO Auto-generated constructor stub

}

public ImageControl(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

// TODO Auto-generated constructor stub

}

// ImageView img;

Matrix imgMatrix = null; // 定义图片的变换矩阵

static final int DOUBLE_CLICK_TIME_SPACE = 300; // 双击时间间隔

static final int DOUBLE_POINT_DISTANCE = 10; // 两点放大两点间最小间距

static final int NONE = 0;

static final int DRAG = 1; // 拖动操作

static final int ZOOM = 2; // 放大缩小操作

private int mode = NONE; // 当前模式

float bigScale = 3f; // 默认放大倍数

Boolean isBig = false; // 是否是放大状态

long lastClickTime = 0; // 单击时间

float startDistance; // 多点触摸两点距离

float endDistance; // 多点触摸两点距离

float topHeight; // 状态栏高度和标题栏高度

Bitmap primaryBitmap = null;

float contentW; // 屏幕内容区宽度

float contentH; // 屏幕内容区高度

float primaryW; // 原图宽度

float primaryH; // 原图高度

float scale; // 适合屏幕缩放倍数

Boolean isMoveX = true; // 是否允许在X轴拖动

Boolean isMoveY = true; // 是否允许在Y轴拖动

float startX;

float startY;

float endX;

float endY;

float subX;

float subY;

float limitX1;

float limitX2;

float limitY1;

float limitY2;

ICustomMethod mCustomMethod = null;

/**

* 初始化图片

*

* @param bitmap

* 要显示的图片

* @param contentW

* 内容区域宽度

* @param contentH

* 内容区域高度

* @param topHeight

* 状态栏高度和标题栏高度之和

*/

public void imageInit(Bitmap bitmap, int contentW, int contentH,

int topHeight, ICustomMethod iCustomMethod) {

this.primaryBitmap = bitmap;

this.contentW = contentW;

this.contentH = contentH;

this.topHeight = topHeight;

mCustomMethod = iCustomMethod;

primaryW = primaryBitmap.getWidth();

primaryH = primaryBitmap.getHeight();

float scaleX = (float) contentW / primaryW;

float scaleY = (float) contentH / primaryH;

scale = scaleX < scaleY ? scaleX : scaleY;

if (scale < 1 && 1 / scale < bigScale) {

bigScale = (float) (1 / scale + 0.5);

}

imgMatrix = new Matrix();

subX = (contentW - primaryW * scale) / 2;

subY = (contentH - primaryH * scale) / 2;

this.setImageBitmap(primaryBitmap);

this.setScaleType(ScaleType.MATRIX);

imgMatrix.postScale(scale, scale);

imgMatrix.postTranslate(subX, subY);

this.setImageMatrix(imgMatrix);

}

/**

* 按下操作

*

* @param event

*/

public void mouseDown(MotionEvent event) {

mode = NONE;

startX = event.getRawX();

startY = event.getRawY();

if (event.getPointerCount() == 1) {

// 如果两次点击时间间隔小于一定值,则默认为双击事件

if (event.getEventTime() - lastClickTime < DOUBLE_CLICK_TIME_SPACE) {

changeSize(startX, startY);

} else if (isBig) {

mode = DRAG;

}

}

lastClickTime = event.getEventTime();

}

/**

* 非第一个点按下操作

*

* @param event

*/

public void mousePointDown(MotionEvent event) {

startDistance = getDistance(event);

if (startDistance > DOUBLE_POINT_DISTANCE) {

mode = ZOOM;

} else {

mode = NONE;

}

}

/**

* 移动操作

*

* @param event

*/

public void mouseMove(MotionEvent event) {

if ((mode == DRAG) && (isMoveX || isMoveY)) {

float[] XY = getTranslateXY(imgMatrix);

float transX = 0;

float transY = 0;

if (isMoveX) {

endX = event.getRawX();

transX = endX - startX;

if ((XY[0] + transX) <= limitX1) {

transX = limitX1 - XY[0];

}

if ((XY[0] + transX) >= limitX2) {

transX = limitX2 - XY[0];

}

}

if (isMoveY) {

endY = event.getRawY();

transY = endY - startY;

if ((XY[1] + transY) <= limitY1) {

transY = limitY1 - XY[1];

}

if ((XY[1] + transY) >= limitY2) {

transY = limitY2 - XY[1];

}

}

imgMatrix.postTranslate(transX, transY);

startX = endX;

startY = endY;

this.setImageMatrix(imgMatrix);

} else if (mode == ZOOM && event.getPointerCount() > 1) {

endDistance = getDistance(event);

float dif = endDistance - startDistance;

if (Math.abs(endDistance - startDistance) > DOUBLE_POINT_DISTANCE) {

if (isBig) {

if (dif < 0) {

changeSize(0, 0);

mode = NONE;

}

} else if (dif > 0) {

float x = event.getX(0) / 2 + event.getX(1) / 2;

float y = event.getY(0) / 2 + event.getY(1) / 2;

changeSize(x, y);

mode = NONE;

}

}

}

}

/**

* 鼠标抬起事件

*/

public void mouseUp() {

mode = NONE;

}

/**

* 图片放大缩小

*

* @param x

* 点击点X坐标

* @param y

* 点击点Y坐标

*/

private void changeSize(float x, float y) {

if (isBig) {

// 如果处于最大状态,则还原

imgMatrix.reset();

imgMatrix.postScale(scale, scale);

imgMatrix.postTranslate(subX, subY);

isBig = false;

} else {

imgMatrix.postScale(bigScale, bigScale); // 在原有矩阵后乘放大倍数

float transX = -((bigScale - 1) * x);

float transY = -((bigScale - 1) * (y - topHeight)); // (bigScale-1)(y-statusBarHeight-subY)+2*subY;

float currentWidth = primaryW * scale * bigScale; // 放大后图片大小

float currentHeight = primaryH * scale * bigScale;

// 如果图片放大后超出屏幕范围处理

if (currentHeight > contentH) {

limitY1 = -(currentHeight - contentH); // 平移限制

limitY2 = 0;

isMoveY = true; // 允许在Y轴上拖动

float currentSubY = bigScale * subY; // 当前平移距离

// 平移后,内容区域上部有空白处理办法

if (-transY < currentSubY) {

transY = -currentSubY;

}

// 平移后,内容区域下部有空白处理办法

if (currentSubY + transY < limitY1) {

transY = -(currentHeight + currentSubY - contentH);

}

} else {

// 如果图片放大后没有超出屏幕范围处理,则不允许拖动

isMoveY = false;

}

if (currentWidth > contentW) {

limitX1 = -(currentWidth - contentW);

limitX2 = 0;

isMoveX = true;

float currentSubX = bigScale * subX;

if (-transX < currentSubX) {

transX = -currentSubX;

}

if (currentSubX + transX < limitX1) {

transX = -(currentWidth + currentSubX - contentW);

}

} else {

isMoveX = false;

}

imgMatrix.postTranslate(transX, transY);

isBig = true;

}

this.setImageMatrix(imgMatrix);

if (mCustomMethod != null) {

mCustomMethod.customMethod(isBig);

}

}

/**

* 获取变换矩阵中X轴偏移量和Y轴偏移量

*

* @param matrix

* 变换矩阵

* @return

*/

private float[] getTranslateXY(Matrix matrix) {

float[] values = new float[9];

matrix.getValues(values);

float[] floats = new float[2];

floats[0] = values[Matrix.MTRANS_X];

floats[1] = values[Matrix.MTRANS_Y];

return floats;

}

/**

* 获取两点间的距离

*

* @param event

* @return

*/

private float getDistance(MotionEvent event) {

float x = event.getX(0) - event.getX(1);

float y = event.getY(0) - event.getY(1);

return FloatMath.sqrt(x * x + y * y);

}

/**

* @author Administrator 用户自定义方法

*/

public interface ICustomMethod {

public void customMethod(Boolean currentStatus);

}

}

ImageVewActivity 这个用于测试的Activity

import android.app.Activity;

import android.graphics.Bitmap;

import android.graphics.Rect;

import android.graphics.drawable.BitmapDrawable;

import android.os.Bundle;

import android.view.MotionEvent;

import android.view.View;

import android.widget.LinearLayout;

import android.widget.TextView;

import android.widget.Toast;

import ejiang.boiler.ImageControl.ICustomMethod;

import ejiang.boiler.R.id;

public class ImageViewActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

// TODO Auto-generated method stub

super.onCreate(savedInstanceState);

setContentView(R.layout.common_image_view);

findView();

}

public void onWindowFocusChanged(boolean hasFocus) {

super.onWindowFocusChanged(hasFocus);

init();

}

ImageControl imgControl;

LinearLayout llTitle;

TextView tvTitle;

private void findView() {

imgControl = (ImageControl) findViewById(id.common_imageview_imageControl1);

llTitle = (LinearLayout) findViewById(id.common_imageview_llTitle);

tvTitle = (TextView) findViewById(id.common_imageview_title);

}

private void init() {

tvTitle.setText("图片测试");

// 这里可以为imgcontrol的图片路径动态赋值

// ............

Bitmap bmp;

if (imgControl.getDrawingCache() != null) {

bmp = Bitmap.createBitmap(imgControl.getDrawingCache());

} else {

bmp = ((BitmapDrawable) imgControl.getDrawable()).getBitmap();

}

Rect frame = new Rect();

getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);

int statusBarHeight = frame.top;

int screenW = this.getWindowManager().getDefaultDisplay().getWidth();

int screenH = this.getWindowManager().getDefaultDisplay().getHeight()

- statusBarHeight;

if (bmp != null) {

imgControl.imageInit(bmp, screenW, screenH, statusBarHeight,

new ICustomMethod() {

@Override

public void customMethod(Boolean currentStatus) {

// 当图片处于放大或缩小状态时,控制标题是否显示

if (currentStatus) {

llTitle.setVisibility(View.GONE);

} else {

llTitle.setVisibility(View.VISIBLE);

}

}

});

}

else

{

Toast.makeText(ImageViewActivity.this, "图片加载失败,请稍候再试!", Toast.LENGTH_SHORT)

.show();

}

}

@Override

public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction() & MotionEvent.ACTION_MASK) {

case MotionEvent.ACTION_DOWN:

imgControl.mouseDown(event);

break;

/**

* 非第一个点按下

*/

case MotionEvent.ACTION_POINTER_DOWN:

imgControl.mousePointDown(event);

break;

case MotionEvent.ACTION_MOVE:

imgControl.mouseMove(event);

break;

case MotionEvent.ACTION_UP:

imgControl.mouseUp();

break;

}

return super.onTouchEvent(event);

}

}

在上面的代码中,需要注意两点。一Activity中要重写onTouchEvent方法,将触摸事件传递到ImageControl,这点类似于WPF中的路由事件机制。二初始化imgControl即imgControl.imageInit,注意其中的参数。最后一个参数类似于C#中的委托,我这里使用接口来实现,在放大缩小的切换时要执行的操作都卸载这个方法中。

common_image_view.xml  布局文件

android:id="@+id/rl"

android:layout_width="fill_parent"

android:layout_height="fill_parent" >

android:id="@+id/common_imageview_imageControl1"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:src="@drawable/ic_launcher" />

android:id="@+id/common_imageview_llTitle"

style="@style/reportTitle1"

android:layout_alignParentLeft="true"

android:layout_alignParentTop="true" >

android:id="@+id/common_imageview_title"

style="@style/title2"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_weight="1"

android:text="报告" />

相关阅读:

margin-top负值解决label 文字与input 垂直居中对齐问题

JS中的进制转换以及作用

mysql jdbc连接步骤及常见参数

C#实现HTTP上传文件的方法

浅谈document.write()输出样式

在Linux系统中加密邮件的方法

应用Java泛型和反射导出CSV文件的方法

引用母版页后在page页面修改母版页控件的值的方法

MySQL查询空字段或非空字段(is null和not null)

Linux下swap耗尽该怎么办?如何释放swap?

jquery实现手风琴效果实例代码

Ubuntu 14.10上安装新的字体图文教程

Win8系统开机电脑自动进入正在修复磁盘错误页面的故障原因及解决方法

在IE浏览器下出发CSS的haslayout属性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值