2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 自定义ImageView 实现双击放大缩小还原 无极缩小和旋转及拖动(多机型测试很稳定)

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

时间:2019-02-16 00:37:59

相关推荐

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

/*** 该模块主要实现了放大和原大两个级别的缩放。功能有: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./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 .HttpURLConnection;import .InetSocketAddress;import .Proxy;import .Proxy.Type;import .SocketAddress;import .URL;import .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(.Proxy.getDefaultHost())) {Type type = Type.HTTP;SocketAddress sa = new InetSocketAddress(.Proxy.getDefaultHost(),.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类可以参考

/gfg156196/article/details/49863401

本例demo已经上传GitHub:

/yugu88/webRTC_Library

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。