Android中实现Bitmap在自定义View中的放大与拖动
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如下:
<RelativeLayoutxmlns: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.MyImageViewandroid:id="@+id/myView"android:layout_width="fill_parent"android:layout_height="fill_parent"android:text="@string/hello_world"/></RelativeLayout>
自定义View类的实现代码如下:
packagecom.example.matrixdemo;importandroid.content.Context;importandroid.graphics.Bitmap;importandroid.graphics.Canvas;importandroid.graphics.Color;importandroid.graphics.Matrix;importandroid.graphics.Paint;importandroid.graphics.Paint.Style;importandroid.graphics.Point;importandroid.graphics.Rect;importandroid.util.AttributeSet;importandroid.view.View;publicclassMyImageViewextendsView{privatePaintmPaint;privateBitmapbitmap;privateMatrixmatrix;//平移开始点与移动点privatePointstartPoint;privatePointmovePoint;privatefloatinitDistance;//记录当前平移距离privateintsx;privateintsy;//保存平移状态privateintoldsx;privateintoldsy;//scalerateprivatefloatwidthRate;privatefloatheightRate;publicMyImageView(Contextcontext){super(context);}publicMyImageView(Contextcontext,AttributeSetattrs){super(context,attrs);}publicvoidsetBitmap(Bitmapbitmap){this.bitmap=bitmap;}privatevoidinitParameters(){//初始化画笔mPaint=newPaint();mPaint.setColor(Color.BLACK);matrix=newMatrix();if(bitmap!=null){floatiw=bitmap.getWidth();floatih=bitmap.getHeight();floatwidth=this.getWidth();floatheight=this.getHeight();//初始放缩比率widthRate=width/iw;heightRate=height/ih;}sx=0;sy=0;oldsx=0;oldsy=0;}publicvoidsetStartPoint(PointstartPoint){this.startPoint=startPoint;}publicvoidsetInitDistance(floatinitDistance){this.initDistance=initDistance;}publicvoidzoomIn(floatdistance){floatrate=distance/this.initDistance;floatiw=bitmap.getWidth();floatih=bitmap.getHeight();floatwidth=this.getWidth();floatheight=this.getHeight();//getscaleratewidthRate=(width/iw)*rate;heightRate=(height/ih)*rate;//makeitsameasviewsizefloatiwr=(width/iw);floatihr=(height/ih);if(iwr>=widthRate){widthRate=(width/iw);}if(ihr>=heightRate){heightRate=(height/ih);}//gotocenteroldsx=(int)((width-widthRate*iw)/2);oldsy=(int)((height-heightRate*ih)/2);}publicvoidsetMovePoint(PointmovePoint){this.movePoint=movePoint;sx=this.movePoint.x-this.startPoint.x;sy=this.movePoint.y-this.startPoint.y;floatiw=bitmap.getWidth();floatih=bitmap.getHeight();//检测边缘intdeltax=(int)((widthRate*iw)-this.getWidth());intdeltay=(int)((heightRate*ih)-this.getHeight());if((sx+this.oldsx)>=0){this.oldsx=0;sx=0;}elseif((sx+this.oldsx)<=-deltax){this.oldsx=-deltax;sx=0;}if((sy+this.oldsy)>=0){this.oldsy=0;this.sy=0;}elseif((sy+this.oldsy)<=-deltay){this.oldsy=-deltay;this.sy=0;}floatwidth=this.getWidth();//初始放缩比率floatiwr=width/iw;if(iwr==widthRate){sx=0;sy=0;oldsx=0;oldsy=0;}}publicvoidsavePreviousResult(){this.oldsx=this.sx+this.oldsx;this.oldsy=this.sy+this.oldsy;//zerosx=0;sy=0;}@OverrideprotectedvoidonDraw(Canvascanvas){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{//fillrectRectrect=newRect(0,0,getWidth(),getHeight());mPaint.setAntiAlias(true);mPaint.setColor(Color.BLACK);mPaint.setStyle(Style.FILL_AND_STROKE);canvas.drawRect(rect,mPaint);}}}
MainActivity的代码如下:
packagecom.example.matrixdemo;importandroid.app.Activity;importandroid.graphics.Bitmap;importandroid.graphics.BitmapFactory;importandroid.graphics.Point;importandroid.os.Bundle;importandroid.util.Log;importandroid.view.Menu;importandroid.view.MotionEvent;importandroid.view.View;importandroid.view.View.OnTouchListener;publicclassMainActivityextendsActivityimplementsOnTouchListener{publicstaticfinalintSCALE_MODE=4;publicstaticfinalintTRANSLATION_MODE=2;publicstaticfinalintNULL_MODE=1;privateMyImageViewmyView;privateintmode;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);startMyImageView();}privatevoidstartMyImageView(){myView=(MyImageView)this.findViewById(R.id.myView);Bitmapbitmap=BitmapFactory.decodeResource(this.getResources(),R.drawable.flower_001);myView.setBitmap(bitmap);myView.setOnTouchListener(this);myView.invalidate();}@OverridepublicbooleanonCreateOptionsMenu(Menumenu){getMenuInflater().inflate(R.menu.main,menu);returntrue;}@OverridepublicbooleanonTouch(Viewview,MotionEventevent){Log.i("touchevent","touchx="+event.getX());switch(MotionEvent.ACTION_MASK&event.getAction()){caseMotionEvent.ACTION_DOWN:mode=TRANSLATION_MODE;myView.setStartPoint(newPoint((int)event.getX(),(int)event.getY()));break;caseMotionEvent.ACTION_POINTER_UP:caseMotionEvent.ACTION_OUTSIDE:caseMotionEvent.ACTION_UP:mode=NULL_MODE;myView.savePreviousResult();break;caseMotionEvent.ACTION_POINTER_DOWN:mode=SCALE_MODE;myView.setInitDistance(calculateDistance(event));break;caseMotionEvent.ACTION_MOVE:if(mode==SCALE_MODE){floatdis=calculateDistance(event);myView.zoomIn(dis);}elseif(mode==TRANSLATION_MODE){myView.setMovePoint(newPoint((int)event.getX(),(int)event.getY()));}else{Log.i("unknowmodetag","donothing......");}break;}myView.invalidate();returntrue;}privatefloatcalculateDistance(MotionEventevent){floatdx=event.getX(0)-event.getX(1);floatdy=event.getY(0)-event.getY(1);floatdistance=(float)Math.sqrt(dx*dx+dy*dy);returndistance;}}
运行截图如下:
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。