將以下代碼寫到MulitPointTouchListener.java中,然后對你相應(yīng)的圖片進(jìn)行OnTouchListener。
創(chuàng)新互聯(lián)公司是一家專業(yè)提供汕城企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站制作、網(wǎng)站建設(shè)、HTML5、小程序制作等業(yè)務(wù)。10年已為汕城眾多企業(yè)、政府機構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)的建站公司優(yōu)惠進(jìn)行中。
例如:imageView.setOnTouchListener(new MulitPointTouchListener ());
在xml中要將ImageView的縮放格式改成Matrix
例如:android:scaleType="matrix"
就可以實現(xiàn)android界面整體縮放
下面是MulitPointTouchListener.java代碼:public class MulitPointTouchListener implements OnTouchListener { private static final String TAG = "Touch"; // These matrices will be used to move and zoom image Matrix matrix = new Matrix(); Matrix savedMatrix = new Matrix(); // We can be in one of these 3 states static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; int mode = NONE; // Remember some things for zooming PointF start = new PointF(); PointF mid = new PointF(); float oldDist = 1f; @Override public boolean onTouch(View v, MotionEvent event) { ImageView view = (ImageView) v; // Log.e("view_width", // view.getImageMatrix()..toString()+"*"+v.getWidth()); // Dump touch event to log dumpEvent(event); // Handle touch events here... switch (event.getAction() MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: matrix.set(view.getImageMatrix()); savedMatrix.set(matrix); start.set(event.getX(), event.getY()); //Log.d(TAG, "mode=DRAG"); mode = DRAG; //Log.d(TAG, "mode=NONE"); break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); //Log.d(TAG, "oldDist=" + oldDist); if (oldDist 10f) { savedMatrix.set(matrix); midPoint(mid, event); mode = ZOOM; //Log.d(TAG, "mode=ZOOM"); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: mode = NONE; //Log.e("view.getWidth", view.getWidth() + ""); //Log.e("view.getHeight", view.getHeight() + ""); break; case MotionEvent.ACTION_MOVE: if (mode == DRAG) { // ... matrix.set(savedMatrix); matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); } else if (mode == ZOOM) { float newDist = spacing(event); //Log.d(TAG, "newDist=" + newDist); if (newDist 10f) { matrix.set(savedMatrix); float scale = newDist / oldDist; matrix.postScale(scale, scale, mid.x, mid.y); } } break; } view.setImageMatrix(matrix); return true; // indicate event was handled } private void dumpEvent(MotionEvent event) { String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE", "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" }; StringBuilder sb = new StringBuilder(); int action = event.getAction(); int actionCode = action MotionEvent.ACTION_MASK; sb.append("event ACTION_").append(names[actionCode]); if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP) { sb.append("(pid ").append( action MotionEvent.ACTION_POINTER_ID_SHIFT); sb.append(")"); } sb.append("["); for (int i = 0; i event.getPointerCount(); i++) { sb.append("#").append(i); sb.append("(pid ").append(event.getPointerId(i)); sb.append(")=").append((int) event.getX(i)); sb.append(",").append((int) event.getY(i)); if (i + 1 event.getPointerCount()) sb.append(";"); } sb.append("]"); //Log.d(TAG, sb.toString()); } 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); } }
先上效果圖
源碼
單點拖動圖片對圖片進(jìn)行平移操作。雙手縮放圖片大小和旋轉(zhuǎn)圖片到一定的角度。圖片縮放的時候 不能大于最大的縮放因子和小于最小的縮放因子。大于最大縮放因子或者小于最小縮放因子需要對圖像進(jìn)行回彈。圖片旋轉(zhuǎn)的角度只能為90度的倍數(shù),不滿足90度要進(jìn)行回彈。圖片回彈要一個漸變的效果。
大體思路: 首先,Android中提供了Matrix類可以對圖像進(jìn)行處理。其次,要顯示一張圖片最容易想到的就是ImageView。回彈要求漸變的過程,可以通過屬性動畫進(jìn)行設(shè)置。所以大體的思路是:繼承ImageView,重寫onTouchEvent()方法,判斷事件類型,在對應(yīng)的事件使用Matrix對圖像進(jìn)行變換。
Matrix是一個已經(jīng)封裝好的矩陣,最重要的作用就是對坐標(biāo)點進(jìn)行變換。
舉個栗子:
1.某個點(x0,y0,1)通過單位矩陣E映射得到的點還是(x0,y0,1)。
3.點(x0,y0,1)通過矩陣T映射得到的點就會做如下的變換
可以看到點(x0,y0,1)經(jīng)過T矩陣在x軸方向上平移了dx,在y軸方向上平移了dy。
通過以上的變換可以得到具體的思路: 我們維護(hù)一個圖像對應(yīng)的矩陣mCurrentMatrix,該矩陣主要是對ImageView中的圖像的各個點進(jìn)行映射。ImageView在容器位置擺放完成之后,置mCurrentMatrix矩陣為單位矩陣。當(dāng)onTouchEvent()方法中觸發(fā)單點觸控并且手指進(jìn)行平移的時候,調(diào)用矩陣mCurrentMatrix的postTranslate(dx,dy),對mCurrentMatrix進(jìn)行變換。當(dāng)手指抬起,利用變換結(jié)束后的矩陣對圖像的各個點進(jìn)行映射,從而得到平移變換后的圖像。同理可得,在兩只手指進(jìn)行縮放旋轉(zhuǎn)的時候,我們對矩陣mCurrentMatrix進(jìn)行各種變換,當(dāng)縮放旋轉(zhuǎn)的事件結(jié)束再利用變換完的矩陣去映射圖像的各個點,從而得到縮放、旋轉(zhuǎn)后的圖像。
安卓自定義View進(jìn)階 - Matrix原理
安卓自定義View進(jìn)階 - Matrix詳解
首先理清事件的邏輯:
初始化圖像大小和位置
縮放圖像大小和控件大小自適應(yīng),平移圖像中心和控件中心重合
onTouchEvent()函數(shù)
平移操作
將圖像對應(yīng)的矩陣進(jìn)行變換。
縮放操作
mBoundRectF為記錄圖像邊界的矩形。縮放的時候選取圖像的中心進(jìn)行縮放。
旋轉(zhuǎn)操作
旋轉(zhuǎn)的時候旋轉(zhuǎn)的旋轉(zhuǎn)中心也是圖像的中心
圖像中各個點的映射
調(diào)用ImageView的setImageMatrix(Matrix matrix)會讓ImageView根據(jù)設(shè)置的matrix去重新繪制圖像。
更新圖像的矩形邊界
獲得圖像的矩形,并根據(jù)矩陣映射矩形各個點的坐標(biāo)。
縮放回彈
旋轉(zhuǎn)回彈
一些計算方法
要求圖像的變換是一個漸變的過程,很容易想到的就是屬性動畫。因為屬性動畫本身就是對值進(jìn)行不斷set的過程。而我們維護(hù)的矩陣也是一個值,所以很自然可以想到,如果得到回彈之前的矩陣的值以及回彈之后矩陣的值,就可以根據(jù)動畫監(jiān)聽器中動畫當(dāng)前的系數(shù)值去改變矩陣的值。
對animator對象設(shè)置完監(jiān)聽器之后,就可以在手指抬起的時候調(diào)用屬性動畫的start()方法開啟動畫。
自定義可平移、縮放、旋轉(zhuǎn)的控件主要點有兩個方面:一是onTouchEvent()中判斷平移、旋轉(zhuǎn)、縮放的觸發(fā)條件,平移位移量、縮放比例因子、旋轉(zhuǎn)角度的計算。二是Matrix矩陣的應(yīng)用。
android 縮放和壓縮圖片可以如下解釋:
壓縮圖片
這里簡單的將一個圖片文件轉(zhuǎn)換為 Bitmap ,并且在轉(zhuǎn)換的過程中對圖片質(zhì)量進(jìn)行簡單壓縮:
bitmap.compress(Bitmap.CompressFormat.JPEG, int quality, FileOutputStream fos);
注意這里的 quality 的范圍為 0~100 ,經(jīng)過測試如果這個值設(shè)置比較低的話圖片會非常不清晰, 基本不可用, 0~100 的值可以參考類似Photoshop之類輸出圖片時選擇的圖片質(zhì)量.
此方法只是單純對圖片質(zhì)量進(jìn)行處理, 并不會改變其大小, 如果需要改變圖片文件的大小, 最好是使用縮放, 這個可以在保證一定的圖片清晰度的情況下減少了圖片大小, 畢竟手機屏幕就那么點, 你把 2000px * 1000px 的圖片改為 500px * 250px 在手機用戶看來也不會有太嚴(yán)重的不適感, 而如果你只設(shè)置圖片的 quality 想來改變文件大小, 你最后會發(fā)現(xiàn)得到的是一個 2000px * 1000px 的幾個色塊.
縮放圖片
先提代碼看看:
[java] view plain copy
/**
* 保持長寬比縮小Bitmap
*
* @param bitmap
* @param maxWidth
* @param maxHeight
* @return
*/
public Bitmap resizeBitmap(Bitmap bitmap, int maxWidth, int maxHeight) {
int originWidth = bitmap.getWidth();
int originHeight = bitmap.getHeight();
// no need to resize
if (originWidth maxWidth originHeight maxHeight) {
return bitmap;
}
int width = originWidth;
int height = originHeight;
// 若圖片過寬, 則保持長寬比縮放圖片
if (originWidth maxWidth) {
width = maxWidth;
double i = originWidth * 1.0 / maxWidth;
height = (int) Math.floor(originHeight / i);
bitmap = Bitmap.createScaledBitmap(bitmap, width, height, false);
}
// 若圖片過長, 則從上端截取
if (height maxHeight) {
height = maxHeight;
bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
}
// Log.i(TAG, width + " width");
// Log.i(TAG, height + " height");
return bitmap;
}
這里演示是將圖片縮小到一個max范圍內(nèi), 而不是直接將變成硬性的變成某個尺寸的圖片, 因為一般來說這種設(shè)置max的方式符合大部分需要, 如果必須將圖片變成某個指定尺寸可以直接使用 Bitmap.createScaledBitmap 方法, 也是下面要介紹的.
此函數(shù)主要就是使用了 Bitmap 的兩個靜態(tài)方法, 一個是:
public static Bitmap createScaledBitmap (Bitmap src, int dstWidth, int dstHeight, boolean filter)
此方法就會把一個 Bitmap 圖片 縮放 成指定的尺寸.
題主是否想詢問“android屬性動畫平移和縮放疊加嗎”?不疊加。android的View動畫屬性是一步一步進(jìn)行的,先進(jìn)行平移,再進(jìn)行縮放比例,是兩個步驟,是不能疊加的。android動畫是通過控制view在一段時間間隔內(nèi)的屬性來達(dá)到動畫效果。
android界面實現(xiàn)整體縮放
代碼:
float basevectorX = 0.0f
float basevectorY = 0.0f
//浮點坐標(biāo) 左上角坐標(biāo)
float FfrogX = 0.0f;
float FfrogY = 0.0f;
//整形坐標(biāo) 左上角坐標(biāo)
int frogX = 0;
int frogY = 0;
Rect rect = new Rect();
FfrogX = FfrogX+basevectorX;
frogX = (int)FfrogX;
FfrogY = FfrogY+basevectorY;
frogY = (int) FfrogY;
rect.left= frogX;
rect.right= ScreenWidth-rect.left-Width; //640
rect.top= frogY; //480
rect.bottom= ScreenHeight-rect.top-Height; //480
((MarginLayoutParams) frogview.getLayoutParams()).setMargins(rect.left, rect.top, rect.right, rect.bottom);
//這個可以放 大縮小,和移動。
CenterX = rect.left + Width/2; //中心點X坐標(biāo) 用來判斷的 用于2d
CenterY = rect.top + Height/2; //中心點Y坐標(biāo) 用來判斷的 用于2d