自定义ImageView 实现双击放大缩小还原,无极缩小和旋转及拖动(多机型测试很稳定)
生活随笔
收集整理的這篇文章主要介紹了
自定义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.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 实现双击放大缩小还原,无极缩小和旋转及拖动(多机型测试很稳定)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GitHub控件之BadgeView(数
- 下一篇: Android自定义控件之仿汽车之家下拉