/*** 该模块主要实现了放大和原大两个级别的缩放。
功能有:
1.以触摸点为中心放大(这个是网上其他的代码没有的)
2.取消边界控制(这个是网上其他的代码没有的)也可以添加边界控制
3.双击放大或缩小(主要考虑到电阻屏)
4.多点触摸放大和缩小
这个模块已经通过了测试,并且用户也使用有一段时间了,是属于比较稳定的了。
5.新加了旋转和无极放大缩小及拖动(这是网上很难找到的)* @author qi**/
public class TouchImageView extends ImageView {float x_down = 0;float y_down = 0;PointF start = new PointF();PointF mid = new PointF();float oldDist = 1f;float oldRotation = 0;float nowRotation = 0;Matrix matrix;Matrix matrix1 = new Matrix();Matrix savedMatrix = new Matrix();private static final int NONE = 0;private static final int DRAG = 1;private static final int ZOOM = 2;int mode = NONE;boolean matrixCheck = false;float widthScreen;float heightScreen;float widthImg;float heightImg;Bitmap bitmap;public TouchImageView(Activity activity,String url) {super(activity);Drawable drawable = DrawableCache.getInstance().loadDrawable(activity, url, 400, null,new ImageCallback() {public void imageLoaded(Drawable imageDrawable, String url) {//此处不需要处理}});BitmapDrawable bd = (BitmapDrawable)drawable; if(bd!=null){bitmap = bd.getBitmap(); }if (bitmap == null) {return;}DisplayMetrics dm = new DisplayMetrics();activity.getWindowManager().getDefaultDisplay().getMetrics(dm);widthScreen = dm.widthPixels;heightScreen = dm.heightPixels;widthImg = bitmap.getWidth();heightImg = bitmap.getHeight();float scaleX = widthScreen/widthImg;float scaleY = heightScreen/heightImg;//     float scale ;
//      if(scaleX>scaleY){
//          scale = scaleY;
//      }else{
//          scale = scaleX;
//      }scale = scaleX < scaleY ? scaleX : scaleY;  if (scale < 1 && 1 / scale < bigScale) {  bigScale = (float) (1 / scale + 0.5);  } matrix = new Matrix();subX=(widthScreen-widthImg*scale)/2;subY=(heightScreen-heightImg*scale)/2;matrix.postScale(scale, scale);matrix.postTranslate(subX, subY);// 平移matrix.postRotate(360, widthScreen/2, heightScreen/2);// 旋轉}protected void onDraw(Canvas canvas) {if (bitmap == null) {return;}// 去除锯齿毛边canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG| Paint.FILTER_BITMAP_FLAG));//matrix.reset();canvas.save();canvas.drawBitmap(bitmap, matrix, null);//Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}//Matrix{[1.0, 0.0, 210.33707][0.0, 1.0, 140.651][0.0, 0.0, 1.0]}//Matrix{[1.0, 0.0, 232.17975][0.0, 1.0, 135.71112][0.0, 0.0, 1.0]}//PointF(512.08984, 766.87354)canvas.restore();}long lastClickTime = 0; // 单击时间  public boolean onTouchEvent(MotionEvent event) {switch (event.getAction() & MotionEvent.ACTION_MASK) {case MotionEvent.ACTION_DOWN:mode = DRAG;x_down = event.getX();y_down = event.getY();if (event.getPointerCount() == 1) {  // 如果两次点击时间间隔小于一定值,则默认为双击事件  if (event.getEventTime() - lastClickTime < 300) {  changeSize(x_down, y_down);  } else if (isBig) {  mode = DRAG;  }  }  savedMatrix.set(matrix);lastClickTime = event.getEventTime();break;case MotionEvent.ACTION_POINTER_DOWN:mode = ZOOM;oldDist = spacing(event);oldRotation = rotation(event);savedMatrix.set(matrix);midPoint(mid, event);break;case MotionEvent.ACTION_MOVE:if (mode == ZOOM) {matrix1.set(savedMatrix);nowRotation = rotation(event);float rotation = nowRotation - oldRotation;float newDist = spacing(event);float scale = newDist / oldDist;matrix1.postScale(scale, scale, mid.x, mid.y);// 縮放matrix1.postRotate(rotation, mid.x, mid.y);// 旋轉matrixCheck = matrixCheck();if (matrixCheck == false) {matrix.set(matrix1);invalidate();}} else if ((mode == DRAG) && (isMoveX || isMoveY)) {matrix1.set(savedMatrix);matrix1.postTranslate(event.getX() - x_down, event.getY()- y_down);// 平移matrixCheck = matrixCheck();matrixCheck = matrixCheck();if (matrixCheck == false) {matrix.set(matrix1);invalidate();}}break;case MotionEvent.ACTION_UP:/*float rotation = Math.abs(nowRotation);if(rotation>=0&&rotation<=45){//rotation =90;}matrix.postRotate(rotation, mid.x, mid.y);// 旋轉invalidate();*/case MotionEvent.ACTION_POINTER_UP:mode = NONE;break;}return true;}Boolean isBig = false; // 是否是放大状态float scale; // 适合屏幕缩放倍数  float subX;float subY;float bigScale = 3f; // 默认放大倍数  float topHeight=0f; // 状态栏高度和标题栏高度  float limitX1;  float limitX2;  float limitY1;  float limitY2;Boolean isMoveX = true; // 是否允许在X轴拖动  Boolean isMoveY = true; // 是否允许在Y轴拖动  private void changeSize(float x, float y) {  if (isBig) {  // 如果处于最大状态,则还原  matrix.reset();  matrix.postScale(scale, scale);  matrix.postTranslate(subX, subY);  isBig = false; } else {  matrix.postScale(bigScale, bigScale); // 在原有矩阵后乘放大倍数  float transX = -((bigScale - 1) * x);  float transY = -((bigScale - 1) * (y - topHeight)); // (bigScale-1)(y-statusBarHeight-subY)+2*subY;  float currentWidth = widthImg * scale * bigScale; // 放大后图片大小  float currentHeight = heightImg * scale * bigScale;  // 如果图片放大后超出屏幕范围处理  if (currentHeight > heightScreen) {  limitY1 = -(currentHeight - heightScreen); // 平移限制  limitY2 = 0;  isMoveY = true; // 允许在Y轴上拖动  float currentSubY = bigScale * subY; // 当前平移距离  // 平移后,内容区域上部有空白处理办法  if (-transY < currentSubY) {  transY = -currentSubY;  }  // 平移后,内容区域下部有空白处理办法  if (currentSubY + transY < limitY1) {  transY = -(currentHeight + currentSubY - heightScreen);  }  } else {  // 如果图片放大后没有超出屏幕范围处理,则不允许拖动  isMoveY = false;  }  if (currentWidth > widthScreen) {  limitX1 = -(currentWidth - widthScreen);  limitX2 = 0;  isMoveX = true;  float currentSubX = bigScale * subX;  if (-transX < currentSubX) {  transX = -currentSubX;  }  if (currentSubX + transX < limitX1) {  transX = -(currentWidth + currentSubX - widthScreen);  }  } else {  isMoveX = false;  }  matrix.postTranslate(transX, transY);  isBig = true;  }  this.setImageMatrix(matrix);
//        if (mCustomMethod != null) {
//            mCustomMethod.customMethod(isBig);
//        }  } private boolean matrixCheck() {float[] f = new float[9];matrix1.getValues(f);// 图片4个顶点的坐标float x1 = f[0] * 0 + f[1] * 0 + f[2];float y1 = f[3] * 0 + f[4] * 0 + f[5];float x2 = f[0] * bitmap.getWidth() + f[1] * 0 + f[2];float y2 = f[3] * bitmap.getWidth() + f[4] * 0 + f[5];float x3 = f[0] * 0 + f[1] * bitmap.getHeight() + f[2];float y3 = f[3] * 0 + f[4] * bitmap.getHeight() + f[5];float x4 = f[0] * bitmap.getWidth() + f[1] * bitmap.getHeight()+ f[2];float y4 = f[3] * bitmap.getWidth() + f[4] * bitmap.getHeight()+ f[5];// 图片现宽度double width = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));// 缩放比率判断if (width < widthScreen / 3 || width > widthScreen * 3) {return true;}// 出界判断if ((x1 < widthScreen / 3 && x2 < widthScreen / 3&& x3 < widthScreen / 3 && x4 < widthScreen / 3)|| (x1 > widthScreen * 2 / 3 && x2 > widthScreen * 2 / 3&& x3 > widthScreen * 2 / 3 && x4 > widthScreen * 2 / 3)|| (y1 < heightScreen / 3 && y2 < heightScreen / 3&& y3 < heightScreen / 3 && y4 < heightScreen / 3)|| (y1 > heightScreen * 2 / 3 && y2 > heightScreen * 2 / 3&& y3 > heightScreen * 2 / 3 && y4 > heightScreen * 2 / 3)) {return true;}return false;}// 触碰两点间距离private float spacing(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);}// 取手势中心点private void midPoint(PointF point, MotionEvent event) {float x = event.getX(0) + event.getX(1);float y = event.getY(0) + event.getY(1);point.set(x / 2, y / 2);}// 取旋转角度private float rotation(MotionEvent event) {double delta_x = (event.getX(0) - event.getX(1));double delta_y = (event.getY(0) - event.getY(1));double radians = Math.atan2(delta_y, delta_x);return (float) Math.toDegrees(radians);}// 将移动,缩放以及旋转后的图层保存为新图片// 本例中沒有用到該方法,需要保存圖片的可以參考/*public Bitmap CreatNewPhoto() {Bitmap bitmap = Bitmap.createBitmap(widthScreen, heightScreen,Config.ARGB_8888); // 背景图片Canvas canvas = new Canvas(bitmap); // 新建画布canvas.drawBitmap(bitmap, matrix, null); // 画图canvas.save(Canvas.ALL_SAVE_FLAG); // 保存画布canvas.restore();return bitmap;}*/}
<img alt="大笑" src="http://static.blog.csdn.net/xheditor/xheditor_emot/default/laugh.gif" />

使用方法:

可以完全当成ImageView 来使用。

一般使用时聊天内容或者图库点击查看图片时,

imageView = new TouchImageView(this,url);LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);imageView.setLayoutParams(params);setContentView(imageView);

大多这样用,点击全屏查看一个图片。。。
非常之简单。。。分享给大家使用。

漏掉了一个类,这里补上:

DrawableCache:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Proxy.Type;
import java.net.SocketAddress;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;import com.inwhoop.xbzhjypt.main.app.MyApplication;
import com.inwhoop.xbzhjypt.main.util.StringUtils;public class DrawableCache {static private DrawableCache cache;// 用于Chche内容的存储的mapprivate Hashtable<String,MySoftRef> hashRefs;// 垃圾Reference的队列(所引用的对象已经被回收,则将该引用存入队列中)private ReferenceQueue<Drawable> q;private ExecutorService executor;private Map<String,List<Handler>> RequestList = new HashMap<String,List<Handler>>();/*** 继承SoftReference,使得每一个实例都具有可识别的标识。*/private class MySoftRef extends SoftReference<Drawable> {private String _key = "";public MySoftRef(Drawable db, ReferenceQueue<Drawable> q, String key) {super(db, q);_key = key;}}/*** 初始化容器和线程池*/private DrawableCache() {hashRefs = new Hashtable<String,MySoftRef>();q = new ReferenceQueue<Drawable>();executor = Executors.newFixedThreadPool(10);}/*** 取得缓存器实例*/public static DrawableCache getInstance() {if (cache == null) {cache = new DrawableCache();}return cache;}/*** 以软引用的方式对一个Bitmap对象的实例进行引用并保存该引用*/private void addCacheBitmap(Drawable db, String key) {cleanCache();// 每次加入Bitmap时清除垃圾引用MySoftRef ref = new MySoftRef(db, q, key);hashRefs.put(key, ref);}/*** 取得Bitmap,以《URL》名称为key*/private Drawable getDrawableFromCache(String key, Context context) {Drawable db = null;if (hashRefs.containsKey(key)) {MySoftRef ref = (MySoftRef) hashRefs.get(key);db = (Drawable) ref.get();}return db;}private void cleanCache() {MySoftRef ref = null;while ((ref = (MySoftRef) q.poll()) != null) {hashRefs.remove(ref._key);}}/*** 清除Cache内的全部内容,可以随意调用*/public void clearCache() {cleanCache();hashRefs.clear();System.gc();System.runFinalization();}/*** 请求图片的主方法!!!*/public Drawable loadDrawable(final Context context, final String imageUrl, final Integer toSize,final Integer threadPriority, final ImageCallback imageCallback) {if (imageUrl == null)return null;// 缓存中是否有该Bitmap实例的软引用,如果有,从软引用中取得Drawable drawable = getDrawableFromCache(imageUrl, context);if (drawable != null && drawable instanceof BitmapDrawable && ((BitmapDrawable) drawable).getBitmap() != null) {return drawable;}// 从URL中截取文件名String fileName = null;try {fileName = URLEncoder.encode(imageUrl, "UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}final File file;// 判断可用来存储的位置if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {File imageDir = MyApplication.getInstance().getAppPathFile("img");isExist(imageDir);file = new File(imageDir, fileName);} elsefile = new File(context.getCacheDir(), fileName);// 下载图片到手机上if (!file.isDirectory() && file.exists()) {drawable = getDrawable(file.getAbsolutePath(), toSize);if (drawable != null && drawable instanceof BitmapDrawable&& ((BitmapDrawable) drawable).getBitmap() != null) {addCacheBitmap(drawable, imageUrl);return drawable;}}final Handler handler = new Handler() {public void handleMessage(Message message) {imageCallback.imageLoaded((Drawable) message.obj, imageUrl);}};if (RequestList.containsKey(imageUrl)) {RequestList.get(imageUrl).add(handler);} else {RequestList.put(imageUrl, new ArrayList<Handler>());RequestList.get(imageUrl).add(handler);// 如果没有软引用,或者从软引用中得到的实例是null,则新起一个线程,并保存对这个图片的软引用executor.execute(new Runnable() {@Overridepublic void run() {if (threadPriority != null) {Thread.currentThread().setPriority(threadPriority.intValue());}Drawable drawable = loadImageFromUrl(context, imageUrl, file, toSize);addCacheBitmap(drawable, imageUrl);List<Handler> listHandler = RequestList.remove(imageUrl);for (Handler callbackHandler : listHandler) {Message message = callbackHandler.obtainMessage(0, drawable);callbackHandler.sendMessage(message);}listHandler.clear();}});}return null;}/*** 下载并保存图片* * @param toSize*/public Drawable loadImageFromUrl(Context context, String imageUrl, File file, Integer toSize) {Drawable drawable = null;try {FileOutputStream fos = new FileOutputStream(file);HttpURLConnection conn = null;URL url = new URL(imageUrl);if (!MyApplication.getInstance().isWifi() && StringUtils.isNotEmpty(android.net.Proxy.getDefaultHost())) {Type type = Type.HTTP;SocketAddress sa = new InetSocketAddress(android.net.Proxy.getDefaultHost(),android.net.Proxy.getDefaultPort());Proxy proxy = new Proxy(type, sa);conn = (HttpURLConnection) url.openConnection(proxy);} else {conn = (HttpURLConnection) url.openConnection();}conn.connect();int responseCode = conn.getResponseCode();InputStream is = conn.getInputStream();int data = is.read();while (data != -1) {fos.write(data);data = is.read();}fos.flush();fos.close();is.close();drawable = getDrawable(file.toString(), toSize);} catch (Exception e) {// 出现任何异常都会删除文件file.delete();}return drawable;}private Drawable getDrawable(String sourceFileName, Integer toSize) {try {if (toSize == null) {return Drawable.createFromPath(sourceFileName);} else {Bitmap bitmap = BitmapConvert.resizeBitmap(sourceFileName, toSize);return new BitmapDrawable(bitmap);}} catch (FileNotFoundException e) {e.printStackTrace();}return null;}/*** 判断文件夹是否存在,如果不存在则创建文件夹*/public static void isExist(File imageDir) {File file = imageDir;if (!file.exists())file.mkdirs();}public interface ImageCallback {public void imageLoaded(Drawable imageDrawable, String imageUrl);}/*** 从网络中获取图片,以流的形式返回* @return*/public static InputStream getImageViewInputStream(String URL_PATH) throws IOException {InputStream inputStream = null;URL url = new URL(URL_PATH);                    //服务器地址if (url != null) {//打开连接HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();httpURLConnection.setConnectTimeout(3000);//设置网络连接超时的时间为3秒httpURLConnection.setRequestMethod("GET");        //设置请求方法为GEThttpURLConnection.setDoInput(true);                //打开输入流int responseCode = httpURLConnection.getResponseCode();    // 获取服务器响应值if (responseCode == HttpURLConnection.HTTP_OK) {        //正常连接inputStream = httpURLConnection.getInputStream();        //获取输入流}}return inputStream;}
}

另外本人一篇简单的自定义view类可以参考

http://blog.csdn.net/gfg156196/article/details/49863401

本例demo已经上传GitHub:

https://github.com/yugu88/webRTC_Library

自定义ImageView 实现双击放大缩小还原,无极缩小和旋转及拖动(多机型测试很稳定)相关推荐

  1. android imageview点击图片放大缩小,Android实现ImageView图片双击放大及缩小

    病人肝癌肿瘤治疗前9.0*8.8cm,通过一疗程服药治疗缩小到8.0*7.3cm. 肝肿瘤9.0*8.8cm 肝肿瘤缩小到8.0*7.3cm 河南偃师任某某乙肝癌肿瘤治疗前6.7*9.3cm,通过一疗 ...

  2. Android自定义ImageView(二)——实现双击放大与缩小图片

    效果图: 首先设置图片依据控件的大小来显示在ImageVeiw中 也就是当图片的宽与高小于控件的宽与高的时候,默认不进行对图片进行放大的操作,但是会将图片居中显示,当然使用的时候可以使用自定义的属性i ...

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

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 转自:h ...

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

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

  5. Android imageview 双击放大缩小手势放大缩小自由滑动

    public class ZoomImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener {pri ...

  6. Android图片查看支持双击放大缩小、多点触摸(多机型测试,长期使用很稳定)

    该模块主要实现了放大和原大两个级别的缩放. 另外功能更加强大的一个类见本人另一篇博客 http://blog.csdn.net/gfg156196/article/details/49741233#r ...

  7. (四)双击放大与缩小图片

    自定义ZoomImageView实现到这里,基本上完成一大半了.在上一篇又给它添加了自由移动的功能.如果你没读过,可以点击下面的链接: http://www.cnblogs.com/fuly55087 ...

  8. 用开源项目PhotoView实现图片的双指缩放和双击放大缩小

    项目地址:https://github.com/chrisbanes/PhotoView 用开源项目有个好处,一是实现简单,二是bug少.那么我们就来说下这个项目能够实现的效果: 1.单个图片的双指缩 ...

  9. Android 自定义图片点击放大、缩小

    @SuppressLint("AppCompatCustomView") public class ZoomImageView extends ImageView implemen ...

最新文章

  1. Linux那些事儿之我是Sysfs(2)linux设备底层模型
  2. 技术12期:如何设计rowkey使hbase更快更好用【大数据-全解析】
  3. java request获取文件_request获取路径方式
  4. 3款动态网页时间时钟HTML5源码
  5. python学习---简介
  6. 「老家」山西凤凰城,说话饮食都像极了西安,人称“最不像山西的城市”
  7. CDN的安全防护功能
  8. 前端如何提示自己的技术水平
  9. 土方工程量计算表格excel_土方量调配表(Excel公式版)
  10. 如何使用qtp检查网页中显示的文字颜色为指定的颜色
  11. Python 爬取必应翻译
  12. 新中大如何修改服务器地址,新中大GE10.0安装配置手册
  13. html 手机端原型,Axure教程:移动端原型如何适配不同分辨率的手机?
  14. 华三交换机如何进入配置_h3c交换机配置telnet配置教程
  15. 【JavaSE8 高级编程 多线程】多线程入门级解析 2019_7_27
  16. 梦想,因坚持而绽放——答大学生的兴趣与行动
  17. html5 显示k线图,canvas绘图,html5 k线图,股票行情图
  18. 吃土豆 递归分制算法(浪费时间)
  19. 陕西邮电职业技术学院计算机系怎么样,陕西邮电职业技术学院的办学实力怎么样?...
  20. SpringCloud调用接口流程

热门文章

  1. BZOJ 2442: [Usaco2011 Open]修剪草坪 单调队列
  2. 【CV论文阅读】 Fast RCNN + SGD笔记
  3. button属性,居然才发现
  4. 《ext江湖》第8章继承-代码片段
  5. 转:ps aux指令詳解
  6. 工作组模式下SQL Server 2008 R2 数据库镜像
  7. SQL-92标准 中文翻译——定义、记号和约定 (定义)
  8. java linkedlist和arraylist添加元素时性能比较
  9. Python并发编程:多线程-死锁现象与递归锁
  10. 在ubuntu16下安装virtualenv+virtualenvwrapper