您好,登錄后才能下訂單哦!
Android中實現Bitmap在自定義View中的放大與拖動
一:基本實現思路
基于View類實現自定義View –MyImageView類。在使用View的Activity類中完成OnTouchListener接口,實現對自定義View的觸摸事件監聽
放大與拖動
基于單點觸控實現Bitmap對象在View上的拖動、并且檢測View的邊緣,防止拖動過界。基于兩個點觸控實現Bitmap對象在View上的放大、并且檢測放大倍數。基于Matrix對象實現對Bitmap在View上放大與平移變換
Bitmap對象在View中的更新與顯示
通過重載onDraw方法,使用canvas實現繪制Bitmap對象、通過view.invalidate()方法實現View的刷新。
MyImageView類的重要方法說明:
initParameters()初始化所有需要用到的參數
setStartPoint()設置圖像平移的開始點坐標
setMovePoint()設置圖像平移的移動點坐標,然后集合開始點位置,計算它們之間的距離,從而得到Bitmap對象需要平移的兩個參數值sx、sy。其中還包括保證圖像不會越過View邊界的檢查代碼。
savePreviousResult() 保存當前的平移數據,下次可以繼續在次基礎上平移Bitmap對象。
zoomIn()根據兩個點之間的歐幾里德距離,通過初始距離比較,得到放大比例,實現Bitmap在View對象上的放大
Matrix.postScale方法與Matrix.postTranslate方法可以不改變Bitmap對象本身實現平移與放大。
OnTouchListener支持以下的觸摸事件處理:
ACTION_DOWN事件,記錄平移開始點
ACTION_UP事件,結束平移事件處理
ACTION_MOVE事件,記錄平移點,計算與開始點距離,實現Bitmap平移,在多點觸控時候,計算兩點之間的距離,實現圖像放大
ACTION_POINTER_DOWN事件,計算兩點之間的距離,作為初始距離,實現圖像手勢放大時候使用。
ACTION_POINTER_UP事件,結束兩點觸控放大圖像處理
二:代碼實現
自定義View的在layout中的使用xml如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <com.example.matrixdemo.MyImageView android:id="@+id/myView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="@string/hello_world" /> </RelativeLayout>
自定義View類的實現代碼如下:
package com.example.matrixdemo; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Point; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; public class MyImageView extends View { private Paint mPaint; private Bitmap bitmap; private Matrix matrix; // 平移開始點與移動點 private Point startPoint; private Point movePoint; private float initDistance; // 記錄當前平移距離 private int sx; private int sy; // 保存平移狀態 private int oldsx; private int oldsy; // scale rate private float widthRate; private float heightRate; public MyImageView(Context context) { super(context); } public MyImageView(Context context, AttributeSet attrs) { super(context, attrs); } public void setBitmap(Bitmap bitmap) { this.bitmap = bitmap; } private void initParameters() { // 初始化畫筆 mPaint = new Paint(); mPaint.setColor(Color.BLACK); matrix = new Matrix(); if(bitmap != null) { float iw = bitmap.getWidth(); float ih = bitmap.getHeight(); float width = this.getWidth(); float height = this.getHeight(); // 初始放縮比率 widthRate = width / iw; heightRate = height / ih; } sx = 0; sy = 0; oldsx = 0; oldsy = 0; } public void setStartPoint(Point startPoint) { this.startPoint = startPoint; } public void setInitDistance(float initDistance) { this.initDistance = initDistance; } public void zoomIn(float distance) { float rate = distance / this.initDistance; float iw = bitmap.getWidth(); float ih = bitmap.getHeight(); float width = this.getWidth(); float height = this.getHeight(); // get scale rate widthRate = (width / iw ) * rate; heightRate = (height / ih) * rate; // make it same as view size float iwr = (width / iw ); float ihr = (height / ih); if(iwr >= widthRate) { widthRate = (width / iw ); } if(ihr >= heightRate) { heightRate = (height / ih); } // go to center oldsx = (int)((width - widthRate * iw) / 2); oldsy = (int)((height - heightRate * ih) / 2); } public void setMovePoint(Point movePoint) { this.movePoint = movePoint; sx = this.movePoint.x - this.startPoint.x; sy = this.movePoint.y - this.startPoint.y; float iw = bitmap.getWidth(); float ih = bitmap.getHeight(); // 檢測邊緣 int deltax = (int)((widthRate * iw) - this.getWidth()); int deltay = (int)((heightRate * ih) - this.getHeight()); if((sx + this.oldsx) >= 0) { this.oldsx = 0; sx = 0; } else if((sx + this.oldsx) <= -deltax) { this.oldsx = -deltax; sx = 0; } if((sy + this.oldsy) >= 0) { this.oldsy = 0; this.sy = 0; } else if((sy + this.oldsy) <= -deltay) { this.oldsy = -deltay; this.sy = 0; } float width = this.getWidth(); // 初始放縮比率 float iwr = width / iw; if(iwr == widthRate) { sx = 0; sy = 0; oldsx = 0; oldsy = 0; } } public void savePreviousResult() { this.oldsx = this.sx + this.oldsx; this.oldsy = this.sy + this.oldsy; // zero sx = 0; sy = 0; } @Override protected void onDraw(Canvas canvas) { if(matrix == null) { initParameters(); } if(bitmap != null) { matrix.reset(); matrix.postScale(widthRate, heightRate); matrix.postTranslate(oldsx+sx, oldsy + sy); canvas.drawBitmap(bitmap, matrix, mPaint); } else { // fill rect Rect rect = new Rect(0, 0, getWidth(), getHeight()); mPaint.setAntiAlias(true); mPaint.setColor(Color.BLACK); mPaint.setStyle(Style.FILL_AND_STROKE); canvas.drawRect(rect, mPaint); } } }
MainActivity的代碼如下:
package com.example.matrixdemo; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Point; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; public class MainActivity extends Activity implements OnTouchListener { public static final int SCALE_MODE = 4; public static final int TRANSLATION_MODE = 2; public static final int NULL_MODE = 1; private MyImageView myView; private int mode; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startMyImageView(); } private void startMyImageView() { myView = (MyImageView) this.findViewById(R.id.myView); Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.flower_001); myView.setBitmap(bitmap); myView.setOnTouchListener(this); myView.invalidate(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onTouch(View view, MotionEvent event) { Log.i("touch event","touch x = " + event.getX()); switch (MotionEvent.ACTION_MASK & event.getAction()) { case MotionEvent.ACTION_DOWN: mode = TRANSLATION_MODE; myView.setStartPoint(new Point((int)event.getX(), (int)event.getY())); break; case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_OUTSIDE: case MotionEvent.ACTION_UP: mode = NULL_MODE; myView.savePreviousResult(); break; case MotionEvent.ACTION_POINTER_DOWN: mode = SCALE_MODE; myView.setInitDistance(calculateDistance(event)); break; case MotionEvent.ACTION_MOVE: if(mode == SCALE_MODE) { float dis = calculateDistance(event); myView.zoomIn(dis); } else if(mode == TRANSLATION_MODE) { myView.setMovePoint(new Point((int)event.getX(), (int)event.getY())); } else { Log.i("unknow mode tag","do nothing......"); } break; } myView.invalidate(); return true; } private float calculateDistance(MotionEvent event) { float dx = event.getX(0) - event.getX(1); float dy = event.getY(0) - event.getY(1); float distance = (float)Math.sqrt(dx*dx + dy*dy); return distance; } }
運行截圖如下:
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。