Android中实现Bitmap在自定义View中的放大与拖动

一基本实现思路:

基于View类实现自定义View –MyImageView类。在使用View的Activity类中完成OnTouchListener接口,实现对MotionEvent事件的监听与处理,常见的MotionEvent事件如下:

ACTION_DOWN事件,记录平移开始点ACTION_UP事件,结束平移事件处理ACTION_MOVE事件,记录平移点,计算与开始点距离,实现Bitmap平移,在多点触控时候,计算两点之间的距离,实现图像放大ACTION_POINTER_DOWN事件,计算两点之间的距离,作为初始距离,实现图像手势放大时候使用。ACTION_POINTER_UP事件,结束两点触控放大图像处理

放大与拖动基于单点触控实现Bitmap对象在View上的拖动、并且检测View的边缘,防止拖动过界。基于两个点触控实现Bitmap对象在View上的放大、并且检测放大倍数。基于Matrix对象实现对Bitmap在View上放大与平移变换,Matrix对象是android中实现图像几何变换的矩阵,,支持平移、放大、缩小、错切、旋转等常见操作。Bitmap对象在View中的更新与显示通过重载onDraw方法,使用canvas实现绘制Bitmap对象、通过view.invalidate()方法实现View的刷新。MyImageView类的重要方法说明:initParameters()初始化所有需要用到的参数setStartPoint()设置图像平移的开始点坐标

setMovePoint()设置图像平移的移动点坐标,然后集合开始点位置,计算它们之间的距离,从而得到Bitmap对象需要平移的两个参数值sx、sy。其中还包括保证图像不会越过View边界的检查代码。

savePreviousResult()保存当前的平移数据,下次可以继续在次基础上平移Bitmap对象。

zoomIn()根据两个点之间的欧几里德距离,通过初始距离比较,得到放大比例,实现Bitmap在View对象上的放大

Matrix中关于放大与平移的API

Matrix.postScale方法与Matrix.postTranslate方法可以不改变Bitmap对象本身实现平移与放大。

二:代码实现

自定义View类使用xml布局如下:

<RelativeLayout xmlns:android=""xmlns: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.MyImageViewandroid: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 rateprivate 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 ratewidthRate = (width / iw ) * rate;heightRate = (height / ih) * rate;// make it same as view sizefloat iwr = (width / iw );float ihr = (height / ih);if(iwr >= widthRate){widthRate = (width / iw );}if(ihr >= heightRate){heightRate = (height / ih);}// go to centeroldsx = (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;// zerosx = 0;sy = 0;}@Overrideprotected 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 rectRect 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;@Overrideprotected 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();}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic 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中实现Bitmap在自定义View中的放大与拖动

相关文章:

你感兴趣的文章:

标签云: