Android实现图片在屏幕内缩放和移动效果

发布时间:2019-08-08 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Android实现图片在屏幕内缩放和移动效果脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

通常我们遇到的图片缩放需求,都是图片基于屏幕自适应后,进行缩放和移动,且图片最小只能是自适应的大小。最近遇到一个需求,要求图片只能在屏幕内缩放和移动,不能超出屏幕。

一、需求

在屏幕中加载一张图片,图片可以手势缩放移动。但是图片最大只能缩放到屏幕大小,也只允许在屏幕内移动。可以从系统中读取图片(通过绝对路径),也可以从资文件中读取图片。

Android实现图片在屏幕内缩放和移动效果

二、自定义ZoomImageView

屏幕内手势缩放图片与普通的图片缩放相比,比较麻烦的是,需要计算图片的精确位置。不同于普通缩放的图片充满屏幕,屏内缩放的图片只占据屏幕的一部分,我们需要判断手指是否点在图片内,才能进行各种操作。

 /**  * 判断手指是否点在图片内(单指)  */  PRivate void isClickInImage(){  if (translationX <= mFirstX && mFirstX <= (translationX + @R_304_834@W)   && translationY <= mFirstY && mFirstY <= (translationY + currentH)){   isClickInImage = true;  }else {   isClickInImage = false;  }  }    /**  * 判断手指是否点在图片内(双指)  * 只要有一只手指在图片内就为true  * @param event  */  private void isClickInImage(MotionEvent event){  if (translationX <= event.getX(0) && event.getX(0) <= (translationX + currentW)   && translationY <= event.getY(0) && event.getY(0) <= (translationY + currentH)){   isClickInImage = true;  }else if (translationX <= event.getX(1) && event.getX(1) <= (translationX + currentW)   && translationY <= event.getY(1) && event.getY(1) <= (translationY + currentH)){   isClickInImage = true;  }else {   isClickInImage = false;  }  }

其他的各种操作,之于缩放,移动,边界检查等,和普通的图片缩放没有太多区别。完整代码如下:

 package com.uni.myapplication;   import andROId.content.Context; import android.graphics.BITmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View;   import java.io.File;   /**  * Created by newcboy on 2018/3/9.  */   public class ZoomImageView extends View {    public static final int IMAGE_MAX_SIZE = 1000;//加载图片允许的最大size,单位kb  private float minimal = 100.0f;    private float screenW;//屏幕度  private float screenH;//屏幕高度    //单指按下的坐标  private float mFirstX = 0.0f;  private float mFirstY = 0.0f;    //单指离开的坐标  private float lastMoveX =-1f;  private float lastMoveY =-1f;    //两指的中点坐标  private float centPointX;  private float centPointY;    //图片的绘制坐标  private float translationX = 0.0f;  private float translationY = 0.0f;    //图片的原始宽高  private float PrimaryW;  private float primaryH;    //图片当前宽高  private float currentW;  private float currentH;    private float scale = 1.0f;  private float maxScale, minScale;  private Bitmap bitmap;  private Matrix matrix;    private int MLocker = 0;  private float fingerDistance = 0.0f;    private boolean isLoaded = false;  private boolean isClickInImage = false;    public ZoomImageView(Context context, @Nullable AttributeSet attrs) {  suPEr(context, attrs);  }      /**  * 从资源文件中读取图片  * @param context  * @param imageid  */  public void setResourceBitmap(Context context, int imageId){  bitmap = BitmapFactory.decodeResource(context.getResources(), imageId);  isLoaded = true;  primaryW = bitmap.getWidth();  primaryH = bitmap.getHeight();  matrix = new Matrix();  }    /**  * 根据路径添加图片  * @param path  * @param scale  */  public void setImagePathBitmap(String path, float scale){  this.scale = scale;  setImageBitmap(path);  }    private void setImageBitmap(String path){  File file = new File(path);  if (file.exists()){   isLoaded = true;   bitmap = ImageLoadUtils.getImageLoadBitmap(path, IMAGE_MAX_SIZE);   primaryW = bitmap.getWidth();   primaryH = bitmap.getHeight();   matrix = new Matrix();  }else {   isLoaded = false;  }  }    @override  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  super.onLayout(changed, left, top, right, bottom);  if (changed){   screenW = getWidth();   screenH = getHeight();   translationX = (screenW - bitmap.getWidth() * scale)/ 2;   translationY = (screenH - bitmap.getHeight() * scale) / 2;   setMaXMinScale();  }  }    /**  *  */  private void setMaxMinScale(){  float xScale, yScale;    xScale = minimal / primaryW;  yScale = minimal / primaryH;  minScale = xScale > yScale &#63; xScale : yScale;    xScale = primaryW / screenW;  yScale = primaryH / screenH;  if (xScale > 1 || yScale > 1 ) {   if (xScale > yScale) {   maxScale = 1/xScale;   }else {   maxScale = 1/yScale;   }  }else {   if (xScale > yScale) {   maxScale = 1/xScale;   }else {   maxScale = 1/yScale;   }  }  if (isScaleError()){   reStoreAction();  }  }    @Override  public boolean onTouchEvent(MotionEvent event) {  if (!isLoaded){   return true;  }  switch (event.getActionMasked()){   case MotionEvent.ACTION_DOWN:   mFirstX = event.getX();   mFirstY = event.getY();   isClickInImage();   break;   case MotionEvent.ACTION_POINTER_DOWN:   fingerDistance = getFingerDistance(event);   isClickInImage(event);   break;   case MotionEvent.ACTION_MOVE:   float fingerNum = event.getPointerCount();   if (fingerNum == 1 && mLocker == 0 && isClickInImage){    movingAction(event);   }else if (fingerNum == 2 && isClickInImage){    zoomAction(event);   }   break;   case MotionEvent.ACTION_POINTER_UP:   mLocker = 1;   if (isScaleError()){    translationX = (event.getX(1) + event.getX(0)) / 2;    translationY = (event.getY(1) + event.getY(0)) / 2;   }   break;   case MotionEvent.ACTION_UP:   lastMoveX = -1;   lastMoveY = -1;   mLocker = 0;   if (isScaleError()){    restoreAction();   }   break;  }  return true;  }      /**  * 移动操作  * @param event  */  private void movingAction(MotionEvent event){  float moveX = event.getX();  float moveY = event.getY();  if (lastMoveX == -1 || lastMoveY == -1) {   lastMoveX = moveX;   lastMoveY = moveY;  }  float moveDistanceX = moveX - lastMoveX;  float moveDistanceY = moveY - lastMoveY;  translationX = translationX + moveDistanceX;  translationY = translationY + moveDistanceY;  lastMoveX = moveX;  lastMoveY = moveY;  invalidate();  }    /**  * 缩放操作  * @param event  */  private void zoomAction(MotionEvent event){  midPoint(event);  float currentDistance = getFingerDistance(event);  if (Math.abs(currentDistance - fingerDistance) > 1f) {   float moveScale = currentDistance / fingerDistance;   scale = scale * moveScale;   translationX = translationX * moveScale + centPointX * (1-moveScale);   translationY = translationY * moveScale + centPointY * (1-moveScale);   fingerDistance = currentDistance;   invalidate();  }  }    /**  * 图片恢复到指定大小  */  private void restoreAction(){  if (scale < minScale){   scale = minScale;  }else if (scale > maxScale){   scale = maxScale;  }  translationX = translationX - bitmap.getWidth()*scale / 2;  translationY = translationY - bitmap.getHeight()*scale / 2;  invalidate();  }      /**  * 判断手指是否点在图片内(单指)  */  private void isClickInImage(){  if (translationX <= mFirstX && mFirstX <= (translationX + currentW)   && translationY <= mFirstY && mFirstY <= (translationY + currentH)){   isClickInImage = true;  }else {   isClickInImage = false;  }  }    /**  * 判断手指是否点在图片内(双指)  * 只要有一只手指在图片内就为true  * @param event  */  private void isClickInImage(MotionEvent event){  if (translationX <= event.getX(0) && event.getX(0) <= (translationX + currentW)   && translationY <= event.getY(0) && event.getY(0) <= (translationY + currentH)){   isClickInImage = true;  }else if (translationX <= event.getX(1) && event.getX(1) <= (translationX + currentW)   && translationY <= event.getY(1) && event.getY(1) <= (translationY + currentH)){   isClickInImage = true;  }else {   isClickInImage = false;  }  }      /**  * 获取两指间的距离  * @param event  * @return  */  private float getFingerDistance(MotionEvent event){  float x = event.getX(1) - event.getX(0);  float y = event.getY(1) - event.getY(0);  return (float) Math.sqrt(x * x + y * y);  }    /**  * 判断图片大小是否符合要求  * @return  */  private boolean isScaleError(){  if (scale > maxScale   || scale < minScale){   return true;  }  return false;  }      /**  * 获取两指间的中点坐标  * @param event  */  private void midPoint(MotionEvent event){  centPointX = (event.getX(1) + event.getX(0))/2;  centPointY = (event.getY(1) + event.getY(0))/2;  }    @Override  protected void onDraw(Canvas canvas) {  super.onDraw(canvas);  if (isLoaded){   imageZoomView(canvas);  }  }    private void imageZoomView(Canvas canvas){  currentW = primaryW * scale;  currentH = primaryH * scale;  matrix.reset();  matrix.postScale(scale, scale);//x轴y轴缩放  peripheryJudge();  matrix.postTranslate(translationX, translationY);//中点坐标移动  canvas.drawBitmap(bitmap, matrix, null);  }    /**  * 图片边界检查  * (只在屏幕内)  */  private void peripheryJudge(){  if (translationX < 0){   translationX = 0;  }  if (translationY < 0){   translationY = 0;  }  if ((translationX + currentW) > screenW){   translationX = screenW - currentW;  }  if ((translationY + currentH) > screenH){   translationY = screenH - currentH;  }  }   }

实际上,用Bitmap绘制图片时,可以通过Paint设置图片透明度。

 Paint paint = new Paint(); paint.setStyle( Paint.Style.stroke); paint.setAlpha(150);

在setAlpha()中传入一个0~255的整数。数字越大,透明度越低。

然后在绘制图片时

 canvas.drawBitmap(bitmap, matrix, paint);

三、ImageLoadUtils图片加载类

这个类是对传入的图片进行压缩处理的类,在应用从系统中读取图片时用到。在写这个类时,发现一些和网上说法不一样的地方。

options.inSampleSize这个属性,网上的说法是必须是2的幂次方,但实际上,我的验证结果是所有的整数都可以。

这里采用的压缩方法是,获取系统剩余内存和图片大小,然后将图片压缩到合适的大小。

 package com.uni.myapplication;   import android.app.ActivityManager; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.net.Uri;   import java.io.File; import java.io.FileInputStream;   /**  * 图片加载工具类  *  * Created by newcboy on 2018/1/25.  */   public class ImageLoadUtils {    /**  * 原图加载,根据传入的指定图片大小。  * @param imagePath  * @param maxSize  * @return  */  public static Bitmap getImageLoadBitmap(String imagePath, int maxSize){  int fileSize = 1;  Bitmap bitmap = null;  int simpleSize = 1;  File file = new File(imagePath);  if (file.exists()) {   Uri imageUri = Uri.parse(imagePath);   try {   fileSize = (int) (getFileSize(file) / 1024);   } catch (Exception e) {   e.printStackTrace();   }   Options options = new Options();   if (fileSize > maxSize){   for (simpleSize = 2; fileSize>= maxSize; simpleSize++){    fileSize = fileSize / simpleSize;   }   }   options.inSampleSize = simpleSize;   bitmap = BitmapFactory.decodeFile(imageUri.getPath(), options);  }  return bitmap;  }      /**  * 获取指定文件的大小  * @param file  * @return  * @throws Exception  */  public static long getFileSize(File file) throws Exception{  if(file == null) {   return 0;  }  long size = 0;  if(file.exists()) {   FileInputStream mInputStream = new FileInputStream(file);   size = mInputStream.available();  }  return size;  }      /**  * 获取手机运行内存  * @param context  * @return  */  public static long gettotalMemorySize(Context context){  long size = 0;  ActivityManager activityManager = (ActivityManager) context.getSystemService(context.ACTIVITY_SERVICE);  ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo();//outInfo对象里面包含了内存相关的信息  activityManager.getMemoryInfo(outInfo);//把内存相关的信息传递到outInfo里面C++思想  //size = outInfo.totalMem; //总内存  size = outInfo.availMem; //剩余内存  return (size/1024/1024);  }   }

四、调用

使用方法和通常的控件差不多,只是多了一个设置图片的方法。

1.在布局文件中添加布局。

 <com.uni.myapplication.ZoomImageView  android:id="@+id/zoom_image_view"  android:layout_width="wrap_content"  android:layout_height="wrap_content" />

2.在代码中调用

 zoomImageView = (ZoomImageView) findViewById(R.id.zoom_image_view); zoomImageView.setImagePathBitmap(MainActivity.this, imagePath, 1.0f); zoomImageView.setResourceBitmap(MainActivity.this, R.mipmap.ic_launcher);

其中setImagePathBitmap()是从系统中读取图片加载的方法,setResourceBitmap()是从资源文件中读取图片的方法。
当然,从系统读取图片需要添加读写权限,这个不能忘了。而且6.0以上的系统需要动态获取权限。动态获取权限的方法这里就不介绍了,网上有很详细的说明。

五、最终效果

Android实现图片在屏幕内缩放和移动效果

android教程
脚本网站
android studio

脚本宝典总结

以上是脚本宝典为你收集整理的Android实现图片在屏幕内缩放和移动效果全部内容,希望文章能够帮你解决Android实现图片在屏幕内缩放和移动效果所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。