效果展示:

基本思路

<1>首先写一个图片控制类ImageControl,实现对图片控制的的基本操作,我们的图片控制类ImageControl是继承自ImageView自定义的视图;

<2>再写一个测试用的布局,这里就要用到自定义的ImageView;

<3>编写测试类ImageViewActivity,写onTouchEvent()方法

图片控制类ImageControl:

 package com.basecontrol.view;

 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);
}
public ImageControl(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ImageControl(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} Matrix imgMatrix=null;//定义图片的变换矩阵 static final int DOUBLE_CLICK_TIME_SPACE=300;//双击时间间隔
static final int DOUBLE_POINT_DISTANCE =10;// 两点放大两点间最小间距
static final int NONE = 0;
private int mode=NONE;//当前模式
static final int DRAG=1;
static final int ZOOM = 2; // 放大缩小操作 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 状态栏高度和标题栏高度之和
* @param iCustomMethod
*/
public void imageInit(Bitmap bitmap,int contentW,int contentH,int topHeight,ICustomMethod iCustomMethod)
{
this.primaryBitmap=bitmap;
this.contentW=contentH;
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;
}
}
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;
}
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 AILALA
*/
public interface ICustomMethod
{
public void customMethod(Boolean currentStatus);
}
}

ImageControl

测试布局:

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" > <com.basecontrol.view.ImageControl
android:id="@+id/common_imageview_imageControll"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="@drawable/ic_launcher"/> <LinearLayout
android:id="@+id/common_iamgeview_llTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" > <TextView
android:id="@+id/common_imageview_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="报告"/>
</LinearLayout>
</RelativeLayout>

测试的Activity:

 package com.basecontrol.ui;

 import com.basecontrol.view.ImageControl;
import com.basecontrol.view.ImageControl.ICustomMethod;
import com.example.basecontrol.R;
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; public class ImageViewActivity extends Activity
{ @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bc_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(R.id.common_imageview_imageControll);
llTitle=(LinearLayout) findViewById(R.id.common_iamgeview_llTitle);
tvTitle=(TextView) findViewById(R.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);
}
}

ImageViewActivity

嗯,就酱…………

Android 手势滑动,多点触摸放大缩小图片的更多相关文章

  1. Android多点触摸放大缩小图片

    1.Activity package com.fit.touchimage; import android.app.Activity; import android.graphics.Bitmap; ...

  2. WPF多点触摸放大缩小旋转

    原文:WPF多点触摸放大缩小旋转 版权声明:本文为博主原创文章,需要转载尽管转载. https://blog.csdn.net/z5976749/article/details/40118437 如果 ...

  3. 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果

    首先呢,还是一贯作风,我们先来看看众多应用中的示例:(这种效果是很常见的,可以说应用的必须品.)                搜狐客户端                               ...

  4. Android学习之多点触摸并不神秘

    最近研究了一下多点触摸,写了个利用多点触摸来控制图片大小和单点触摸控制图片移动的程序,和大家分享分享. Android中监听触摸事件是onTouchEvent方法,它的参数为MotionEvent,下 ...

  5. Android手势滑动Tab

    Android手势滑动Tab //MainActivity.java public class MainActivity extends TabActivity { ; ; ; private Ges ...

  6. Android事件处理之多点触摸与手势识别

    一.Muilti-touch 双指缩放的实现探索: 首先要实现OnTouchListener接口,然后重写方法: public boolean onTouch(View v, MotionEvent ...

  7. android 手势滑动

    1.概述, 两次都是画曲线统计图用到手势滑动.左滑动,右滑动曲线图翻页 2.直接上代码 3.注: 第一次使用的时候是implement了 OnTouchListener 接口,是在画图布局上layou ...

  8. ios 双指捏合放大缩小图片的例子

    图片跟随双指捏合的距离放大或者缩小. 利用-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event  实现. touchesMov ...

  9. HTML5:使用Canvas和Input range控件放大缩小图片,剪裁,并上传图片

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

随机推荐

  1. until与till的用法归纳

    until与till的用法归纳 崔荣斌 until和till两者都可作介词.连词,一般情况下可以互换使用.用于肯定句时,主句的动词只用延续性的,它所表示的动作一直延续到till或until表示的时间为 ...

  2. 终于可以发布Delphi下收点OSGI精髓皮毛而设计的插件框架WisdomPluginFramework

    这是一个Delphi实现的插件框架,我耗费了相当相当相当多的精力来设计她,虽然仅闪着点我微薄智慧的光芒,但我还是决定用Wisdom来命名她,也因它是我绝无仅有的,在完成1年多后回头来看仍能相当满意的作 ...

  3. Update-ServiceTemplate

    1: Update a service by using conventional servicing. PS C:\> $Service = Get-SCService -Name " ...

  4. 修改MyEclipse内存-------OutOfMemoryError错误

    1.打开MyEclipse后,进入Windows/Preferences/Java/Installed JREs 点击后,在右边窗口选择JREs,双击后进入 2.在Default VM Argumen ...

  5. 高斯混合和EM算法

    首先介绍高斯混合模型: 高斯混合模型是指具有以下形式的概率分布模型: 一般其他分布的混合模型用相应的概率密度代替(1)式中的高斯分布密度即可. 给定训练集,我们希望构建该数据联合分布 这里,其中是概率 ...

  6. 【M29】引用计数

    1.引用计数这项技术,是为了让等值对象对象共享同一实体.此技术的发展有两个动机:a.记录堆上分配的对象,是垃圾回收机制的简单原理:b.节省内存,多个对象具有相同的值,存储多次很笨.速度更快,等值对象避 ...

  7. 財哥面京东dm的经历【帮財哥发的】

        关于面京东,感触仅仅有一个,虐的快吐血了.首先说京东分四个板块,有京东商城.京东金融.京东刚收购的拍拍和海外事业部.我这个职位主要是在金融部数据组做数据挖掘和机器学习,还有推荐系统.面试是在周 ...

  8. 如何在 iOS 8 中使用 Swift 实现本地通知(上)

    当你的应用在后台运行时,可以简单地使用本地通知把信息呈现给用户.它可以允许你显示 提醒.播放提示音和数字角标(badge).本地通知可以被以下的事件触发:计划好的时间点或者用户进入和离开某个地理区域. ...

  9. 【剑指offer】Q18:树的子结构

    类似于字符串的匹配,我们总是找到第一个匹配的字符,在继续比較以后的字符是否所有同样,假设匹配串的第一个字符与模式串的第一个不同样,我们就去查看匹配串的下一个字符是否与模式串的第一个同样,相应到这里,就 ...

  10. 标准库 - fmt/print.go 解读

    // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a B ...