欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 运维知识 > Android >内容正文

Android

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

发布时间:2025/6/15 Android 44 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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布局如下:

[html] view plaincopy
  • <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实现代码如下:

    [java] view plaincopy
  • 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(00, getWidth(), getHeight());  
  •             mPaint.setAntiAlias(true);  
  •             mPaint.setColor(Color.BLACK);  
  •             mPaint.setStyle(Style.FILL_AND_STROKE);  
  •             canvas.drawRect(rect, mPaint);  
  •         }  
  •     }  
  • }  
  • Activity类中实现对View的OnTouchListener监听与MotionEvent事件处理的代码如下:

    [java] view plaincopy
  • 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中实现Bitmap在自定义View中的放大与拖动的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。