編輯:關於android開發
基於View類實現自定義View –MyImageView類。在使用View的Activity類中完成OnTouchListener接口,實現對MotionEvent事件的監聽與處理,常見的MotionEvent事件如下:
ACTION_DOWN事件,記錄平移開始點
ACTION_UP事件,結束平移事件處理
ACTION_MOVE事件,記錄平移點,計算與開始點距離,實現Bitmap平移,在多點觸控時候,計算兩點之間的距離,實現圖像放大
ACTION_POINTER_DOWN事件,計算兩點之間的距離,作為初始距離,實現圖像手勢放大時候使用。
ACTION_POINTER_UP事件,結束兩點觸控放大圖像處理
setMovePoint()設置圖像平移的移動點坐標,然後集合開始點位置,計算它們之間的距離,從而得到Bitmap對象需要平移的兩個參數值sx、sy。其中還包括保證圖像不會越過View邊界的檢查代碼。
savePreviousResult()保存當前的平移數據,下次可以繼續在次基礎上平移Bitmap對象。
zoomIn()根據兩個點之間的歐幾裡德距離,通過初始距離比較,得到放大比例,實現Bitmap在View對象上的放大
Matrix中關於放大與平移的API
Matrix.postScale方法與Matrix.postTranslate方法可以不改變Bitmap對象本身實現平移與放大。
二:代碼實現
自定義View類使用xml布局如下:
自定義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);
}
}
}
Activity類中實現對View的OnTouchListener監聽與MotionEvent事件處理的代碼如下:
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;
}
}
三:運行效果如下

Android studio圖片ERROR: 9-patch image xx .9.png malformed
Android studio圖片ERROR: 9-patch image xx .9.png malformed Android studio 圖片錯誤 9-patc
自定義加載loading view動畫組件的使用。,loadingview
自定義加載loading view動畫組件的使用。,loadingview在github上找的一個有點酷炫的loading動畫https://github.com/Fic
解析網絡json數據,模擬美團界面顯示。,json
解析網絡json數據,模擬美團界面顯示。,json 1 <?xml version=1.0 encoding=UTF-8?> 2 <RelativeL
RecyclerView和PullToRefreshListView的對比,recyclerview
RecyclerView和PullToRefreshListView的對比,recyclerview項目中上拉刷新和下拉加載一直都是比較常見的;以前一般都是重寫ListV