溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

安卓 App雙擊放大和縮小圖片功能

發(fā)布時(shí)間:2020-06-14 17:46:57 來(lái)源:網(wǎng)絡(luò) 閱讀:534 作者:woshiyipizhu 欄目:移動(dòng)開(kāi)發(fā)

直接上代碼:


public static Bitmap scale(Bitmap bitmap, float scaleWidth, float scaleHeight) {

  int width = bitmap.getWidth();

  int height = bitmap.getHeight();

  Matrix matrix = new Matrix();

  matrix.postScale(scaleWidth, scaleHeight);

  Log.i(TAG, "scaleWidth:"+ scaleWidth +", scaleHeight:"+ scaleHeight);

  return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);

}

注意要比例設(shè)置正確否則可能會(huì)內(nèi)存溢出,比如曾經(jīng)使用圖片縮放時(shí)遇到這么個(gè)問(wèn)題:



1

java.lang.IllegalArgumentException: bitmap size exceeds 32bits

后來(lái)一行行查代碼,發(fā)現(xiàn)原來(lái)是 scale 的比例計(jì)算錯(cuò)誤,將原圖給放大了 20 多倍,導(dǎo)致內(nèi)存溢出所致,重新修改比例值后就正常了。


好了,下面真正來(lái)看一下這個(gè)實(shí)現(xiàn)了放大和原大兩個(gè)級(jí)別的縮放的模塊。

功能有:


以觸摸點(diǎn)為中心放大(這個(gè)是網(wǎng)上其他的代碼沒(méi)有的)

邊界控制(這個(gè)是網(wǎng)上其他的代碼沒(méi)有的)

雙擊放大或縮?。ㄖ饕紤]到電阻屏)

多點(diǎn)觸摸放大和縮小

這個(gè)模塊已經(jīng)通過(guò)了測(cè)試,并且用戶也使用有一段時(shí)間了,是屬于比較穩(wěn)定的了。


下面貼上QANDA.REN代碼及使用方法(沒(méi)有寫(xiě)測(cè)試項(xiàng)目,大家見(jiàn)諒):


ImageControl 類(lèi)似一個(gè)用戶自定義的ImageView控件。用法將在下面的代碼中貼出。



import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.Matrix;

import android.util.AttributeSet;

import android.util.FloatMath;

import android.view.MotionEvent;

import android.widget.ImageView;

  

public class ImageControl extends ImageView {

  public ImageControl(Context context) {

    super(context);

    // TODO Auto-generated constructor stub

  }

  

  public ImageControl(Context context, AttributeSet attrs) {

    super(context, attrs);

    // TODO Auto-generated constructor stub

  }

  

  public ImageControl(Context context, AttributeSet attrs, int defStyle) {

    super(context, attrs, defStyle);

    // TODO Auto-generated constructor stub

  }

  

  // ImageView img;

  Matrix imgMatrix = null; // 定義圖片的變換矩陣

  

  static final int DOUBLE_CLICK_TIME_SPACE = 300; // 雙擊時(shí)間間隔

  static final int DOUBLE_POINT_DISTANCE = 10; // 兩點(diǎn)放大兩點(diǎn)間最小間距

  static final int NONE = 0;

  static final int DRAG = 1; // 拖動(dòng)操作

  static final int ZOOM = 2; // 放大縮小操作

  private int mode = NONE; // 當(dāng)前模式

  

  float bigScale = 3f; // 默認(rèn)放大倍數(shù)

  Boolean isBig = false; // 是否是放大狀態(tài)

  long lastClickTime = 0; // 單擊時(shí)間

  float startDistance; // 多點(diǎn)觸摸兩點(diǎn)距離

  float endDistance; // 多點(diǎn)觸摸兩點(diǎn)距離

  

  float topHeight; // 狀態(tài)欄高度和標(biāo)題欄高度

  Bitmap primaryBitmap = null;

  

  float contentW; // 屏幕內(nèi)容區(qū)寬度

  float contentH; // 屏幕內(nèi)容區(qū)高度

  

  float primaryW; // 原圖寬度

  float primaryH; // 原圖高度

  

  float scale; // 適合屏幕縮放倍數(shù)

  Boolean isMoveX = true; // 是否允許在X軸拖動(dòng)

  Boolean isMoveY = true; // 是否允許在Y軸拖動(dòng)

  float startX;

  float startY;

  float endX;

  float endY;

  float subX;

  float subY;

  float limitX1;

  float limitX2;

  float limitY1;

  float limitY2;

  ICustomMethod mCustomMethod = null;

  

  /**

   * 初始化圖片

   *

   * @param bitmap

   *      要顯示的圖片

   * @param contentW

   *      內(nèi)容區(qū)域?qū)挾?/p>

   * @param contentH

   *      內(nèi)容區(qū)域高度

   * @param topHeight

   *      狀態(tài)欄高度和標(biāo)題欄高度之和

   */

  public void p_w_picpathInit(Bitmap bitmap, int contentW, int contentH,

      int topHeight, ICustomMethod iCustomMethod) {

    this.primaryBitmap = bitmap;

    this.contentW = contentW;

    this.contentH = contentH;

    this.topHeight = topHeight;

    mCustomMethod = iCustomMethod;

    primaryW = primaryBitmap.getWidth();

    primaryH = primaryBitmap.getHeight();

    float scaleX = (float) contentW / primaryW;

    float scaleY = (float) contentH / primaryH;

    scale = scaleX < scaleY ? scaleX : scaleY;

    if (scale < 1 && 1 / scale < bigScale) {

      bigScale = (float) (1 / scale + 0.5);

    }

  

    imgMatrix = new Matrix();

    subX = (contentW - primaryW * scale) / 2;

    subY = (contentH - primaryH * scale) / 2;

    this.setImageBitmap(primaryBitmap);

    this.setScaleType(ScaleType.MATRIX);

    imgMatrix.postScale(scale, scale);

    imgMatrix.postTranslate(subX, subY);

    this.setImageMatrix(imgMatrix);

  }

  

  /**

   * 按下操作

   *

   * @param event

   */

  public void mouseDown(MotionEvent event) {

    mode = NONE;

    startX = event.getRawX();

    startY = event.getRawY();

    if (event.getPointerCount() == 1) {

      // 如果兩次點(diǎn)擊時(shí)間間隔小于一定值,則默認(rèn)為雙擊事件

      if (event.getEventTime() - lastClickTime < DOUBLE_CLICK_TIME_SPACE) {

        changeSize(startX, startY);

      } else if (isBig) {

        mode = DRAG;

      }

    }

  

    lastClickTime = event.getEventTime();

  }

  

  /**

   * 非第一個(gè)點(diǎn)按下操作

   *

   * @param event

   */

  public void mousePointDown(MotionEvent event) {

    startDistance = getDistance(event);

    if (startDistance > DOUBLE_POINT_DISTANCE) {

      mode = ZOOM;

    } else {

      mode = NONE;

    }

  }

  

  /**

   * 移動(dòng)操作

   *

   * @param event

   */

  public void mouseMove(MotionEvent event) {

    if ((mode == DRAG) && (isMoveX || isMoveY)) {

      float[] XY = getTranslateXY(imgMatrix);

      float transX = 0;

      float transY = 0;

      if (isMoveX) {

        endX = event.getRawX();

        transX = endX - startX;

        if ((XY[0] + transX) <= limitX1) {

          transX = limitX1 - XY[0];

        }

        if ((XY[0] + transX) >= limitX2) {

          transX = limitX2 - XY[0];

        }

      }

      if (isMoveY) {

        endY = event.getRawY();

        transY = endY - startY;

        if ((XY[1] + transY) <= limitY1) {

          transY = limitY1 - XY[1];

        }

        if ((XY[1] + transY) >= limitY2) {

          transY = limitY2 - XY[1];

        }

      }

  

      imgMatrix.postTranslate(transX, transY);

      startX = endX;

      startY = endY;

      this.setImageMatrix(imgMatrix);

    } else if (mode == ZOOM && event.getPointerCount() > 1) {

      endDistance = getDistance(event);

      float dif = endDistance - startDistance;

      if (Math.abs(endDistance - startDistance) > DOUBLE_POINT_DISTANCE) {

        if (isBig) {

          if (dif < 0) {

            changeSize(0, 0);

            mode = NONE;

          }

        } else if (dif > 0) {

          float x = event.getX(0) / 2 + event.getX(1) / 2;

          float y = event.getY(0) / 2 + event.getY(1) / 2;

          changeSize(x, y);

          mode = NONE;

        }

      }

    }

  }

  

  /**

   * 鼠標(biāo)抬起事件

   */

  public void mouseUp() {

    mode = NONE;

  }

  

  /**

   * 圖片放大縮小

   *

   * @param x

   *      點(diǎn)擊點(diǎn)X坐標(biāo)

   * @param y

   *      點(diǎn)擊點(diǎn)Y坐標(biāo)

   */

  private void changeSize(float x, float y) {

    if (isBig) {

      // 如果處于最大狀態(tài),則還原

      imgMatrix.reset();

      imgMatrix.postScale(scale, scale);

      imgMatrix.postTranslate(subX, subY);

      isBig = false;

    } else {

      imgMatrix.postScale(bigScale, bigScale); // 在原有矩陣后乘放大倍數(shù)

      float transX = -((bigScale - 1) * x);

      float transY = -((bigScale - 1) * (y - topHeight)); // (bigScale-1)(y-statusBarHeight-subY)+2*subY;

      float currentWidth = primaryW * scale * bigScale; // 放大后圖片大小

      float currentHeight = primaryH * scale * bigScale;

      // 如果圖片放大后超出屏幕范圍處理

      if (currentHeight > contentH) {

        limitY1 = -(currentHeight - contentH); // 平移限制

        limitY2 = 0;

        isMoveY = true; // 允許在Y軸上拖動(dòng)

        float currentSubY = bigScale * subY; // 當(dāng)前平移距離

        // 平移后,內(nèi)容區(qū)域上部有空白處理辦法

        if (-transY < currentSubY) {

          transY = -currentSubY;

        }

        // 平移后,內(nèi)容區(qū)域下部有空白處理辦法

        if (currentSubY + transY < limitY1) {

          transY = -(currentHeight + currentSubY - contentH);

        }

      } else {

        // 如果圖片放大后沒(méi)有超出屏幕范圍處理,則不允許拖動(dòng)

        isMoveY = false;

      }

  

      if (currentWidth > contentW) {

        limitX1 = -(currentWidth - contentW);

        limitX2 = 0;

        isMoveX = true;

        float currentSubX = bigScale * subX;

        if (-transX < currentSubX) {

          transX = -currentSubX;

        }

        if (currentSubX + transX < limitX1) {

          transX = -(currentWidth + currentSubX - contentW);

        }

      } else {

        isMoveX = false;

      }

  

      imgMatrix.postTranslate(transX, transY);

      isBig = true;

    }

  

    this.setImageMatrix(imgMatrix);

    if (mCustomMethod != null) {

      mCustomMethod.customMethod(isBig);

    }

  }

  

  /**

   * 獲取變換矩陣中X軸偏移量和Y軸偏移量

   *

   * @param matrix

   *      變換矩陣

   * @return

   */

  private float[] getTranslateXY(Matrix matrix) {

    float[] values = new float[9];

    matrix.getValues(values);

    float[] floats = new float[2];

    floats[0] = values[Matrix.MTRANS_X];

    floats[1] = values[Matrix.MTRANS_Y];

    return floats;

  }

  

  /**

   * 獲取兩點(diǎn)間的距離

   *

   * @param event

   * @return

   */

  private float getDistance(MotionEvent event) {

    float x = event.getX(0) - event.getX(1);

    float y = event.getY(0) - event.getY(1);

    return FloatMath.sqrt(x * x + y * y);

  }

  

  /**

   * @author Administrator 用戶自定義方法

   */

  public interface ICustomMethod {

    public void customMethod(Boolean currentStatus);

  }

}

 


ImageVewActivity 這個(gè)用于測(cè)試的Activity



import android.app.Activity;

import android.graphics.Bitmap;

import android.graphics.Rect;

import android.graphics.drawable.BitmapDrawable;

import android.os.Bundle;

import android.view.MotionEvent;

import android.view.View;

import android.widget.LinearLayout;

import android.widget.TextView;

import android.widget.Toast;

import ejiang.boiler.ImageControl.ICustomMethod;

import ejiang.boiler.R.id;

  

public class ImageViewActivity extends Activity {

  

  @Override

  protected void onCreate(Bundle savedInstanceState) {

    // TODO Auto-generated method stub

    super.onCreate(savedInstanceState);

    setContentView(R.layout.common_p_w_picpath_view);

    findView();

  }

  

  public void onWindowFocusChanged(boolean hasFocus) {

    super.onWindowFocusChanged(hasFocus);

    init();

  }

  

  ImageControl imgControl;

  LinearLayout llTitle;

  TextView tvTitle;

  

  private void findView() {

    imgControl = (ImageControl) findViewById(id.common_p_w_picpathview_p_w_picpathControl1);

    llTitle = (LinearLayout) findViewById(id.common_p_w_picpathview_llTitle);

    tvTitle = (TextView) findViewById(id.common_p_w_picpathview_title);

  }

  

  private void init() {

    tvTitle.setText("圖片測(cè)試");

    // 這里可以為imgcontrol的圖片路徑動(dòng)態(tài)賦值

    // ............

      

    Bitmap bmp;

    if (imgControl.getDrawingCache() != null) {

      bmp = Bitmap.createBitmap(imgControl.getDrawingCache());

    } else {

      bmp = ((BitmapDrawable) imgControl.getDrawable()).getBitmap();

    }

    Rect frame = new Rect();

    getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);

    int statusBarHeight = frame.top;

    int screenW = this.getWindowManager().getDefaultDisplay().getWidth();

    int screenH = this.getWindowManager().getDefaultDisplay().getHeight()

        - statusBarHeight;

    if (bmp != null) {

      imgControl.p_w_picpathInit(bmp, screenW, screenH, statusBarHeight,

          new ICustomMethod() {

             

            @Override

            public void customMethod(Boolean currentStatus) {

              // 當(dāng)圖片處于放大或縮小狀態(tài)時(shí),控制標(biāo)題是否顯示

              if (currentStatus) {

                llTitle.setVisibility(View.GONE);

              } else {

                llTitle.setVisibility(View.VISIBLE);

              }

            }

          });

    }

    else

    {

      Toast.makeText(ImageViewActivity.this, "圖片加載失敗,請(qǐng)稍候再試!", Toast.LENGTH_SHORT)

          .show();

    }

  

  }

  

  @Override

  public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction() & MotionEvent.ACTION_MASK) {

    case MotionEvent.ACTION_DOWN:

      imgControl.mouseDown(event);      

      break;

  

    /**

     * 非第一個(gè)點(diǎn)按下

     */

    case MotionEvent.ACTION_POINTER_DOWN:

      

        imgControl.mousePointDown(event);

      

      break;

    case MotionEvent.ACTION_MOVE:

        imgControl.mouseMove(event);

        

      break;

  

    case MotionEvent.ACTION_UP:

      imgControl.mouseUp();

      break;

  

    }

  

    return super.onTouchEvent(event);

  }

}

        在上面的代碼中,需要注意兩點(diǎn)。一Activity中要重寫(xiě)onTouchEvent方法,將觸摸事件傳遞到ImageControl,這點(diǎn)類(lèi)似于WPF中的路由事件機(jī)制。二初始化imgControl即imgControl.p_w_picpathInit,注意其中的參數(shù)。最后一個(gè)參數(shù)類(lèi)似于C#中的委托,我這里使用接口來(lái)實(shí)現(xiàn),在放大縮小的切換時(shí)要執(zhí)行的操作都卸載這個(gè)方法中。



common_p_w_picpath_view.xml  布局文件



<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

  android:id="@+id/rl"

  android:layout_width="fill_parent"

  android:layout_height="fill_parent" >

  

  <ejiang.boiler.ImageControl

    android:id="@+id/common_p_w_picpathview_p_w_picpathControl1"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:src="@drawable/ic_launcher" />

  

  <LinearLayout

    android:id="@+id/common_p_w_picpathview_llTitle"

   

    android:layout_alignParentLeft="true"

    android:layout_alignParentTop="true" >

  

    <TextView

      android:id="@+id/common_p_w_picpathview_title"

     

      android:layout_width="fill_parent"

      android:layout_height="wrap_content"

      android:layout_weight="1"

      android:text="報(bào)告" />

  </LinearLayout>

  

</RelativeLayout> 


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI