最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android App中實現(xiàn)可以雙擊放大和縮小圖片功能的實例

 更新時間:2016年03月19日 16:13:43   投稿:goldensun  
這篇文章主要介紹了Android App中實現(xiàn)可以雙擊放大和縮小圖片功能的實例,文中的例子不能做到逐級放大但可以做到邊界控制和以觸摸點為中心進行放大,需要的朋友可以參考下

先來看一個很簡單的核心圖片縮放方法:

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); 
} 

注意要比例設置正確否則可能會內存溢出,比如曾經使用圖片縮放時遇到這么個問題:

java.lang.IllegalArgumentException: bitmap size exceeds 32bits

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

好了,下面真正來看一下這個實現(xiàn)了放大和原大兩個級別的縮放的模塊。
功能有:

  • 以觸摸點為中心放大(這個是網上其他的代碼沒有的)
  • 邊界控制(這個是網上其他的代碼沒有的)
  • 雙擊放大或縮?。ㄖ饕紤]到電阻屏)
  • 多點觸摸放大和縮小

這個模塊已經通過了測試,并且用戶也使用有一段時間了,是屬于比較穩(wěn)定的了。

下面貼上代碼及使用方法(沒有寫測試項目,大家見諒):

ImageControl 類似一個用戶自定義的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; // 雙擊時間間隔 
  static final int DOUBLE_POINT_DISTANCE = 10; // 兩點放大兩點間最小間距 
  static final int NONE = 0; 
  static final int DRAG = 1; // 拖動操作 
  static final int ZOOM = 2; // 放大縮小操作 
  private int mode = NONE; // 當前模式 
 
  float bigScale = 3f; // 默認放大倍數(shù) 
  Boolean isBig = false; // 是否是放大狀態(tài) 
  long lastClickTime = 0; // 單擊時間 
  float startDistance; // 多點觸摸兩點距離 
  float endDistance; // 多點觸摸兩點距離 
 
  float topHeight; // 狀態(tài)欄高度和標題欄高度 
  Bitmap primaryBitmap = null; 
 
  float contentW; // 屏幕內容區(qū)寬度 
  float contentH; // 屏幕內容區(qū)高度 
 
  float primaryW; // 原圖寬度 
  float primaryH; // 原圖高度 
 
  float scale; // 適合屏幕縮放倍數(shù) 
  Boolean isMoveX = true; // 是否允許在X軸拖動 
  Boolean isMoveY = true; // 是否允許在Y軸拖動 
  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 
   *      內容區(qū)域寬度 
   * @param contentH 
   *      內容區(qū)域高度 
   * @param topHeight 
   *      狀態(tài)欄高度和標題欄高度之和 
   */ 
  public void imageInit(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) { 
      // 如果兩次點擊時間間隔小于一定值,則默認為雙擊事件 
      if (event.getEventTime() - lastClickTime < DOUBLE_CLICK_TIME_SPACE) { 
        changeSize(startX, startY); 
      } else if (isBig) { 
        mode = DRAG; 
      } 
    } 
 
    lastClickTime = event.getEventTime(); 
  } 
 
  /** 
   * 非第一個點按下操作 
   * 
   * @param event 
   */ 
  public void mousePointDown(MotionEvent event) { 
    startDistance = getDistance(event); 
    if (startDistance > DOUBLE_POINT_DISTANCE) { 
      mode = ZOOM; 
    } else { 
      mode = NONE; 
    } 
  } 
 
  /** 
   * 移動操作 
   * 
   * @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; 
        } 
      } 
    } 
  } 
 
  /** 
   * 鼠標抬起事件 
   */ 
  public void mouseUp() { 
    mode = NONE; 
  } 
 
  /** 
   * 圖片放大縮小 
   * 
   * @param x 
   *      點擊點X坐標 
   * @param y 
   *      點擊點Y坐標 
   */ 
  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軸上拖動 
        float currentSubY = bigScale * subY; // 當前平移距離 
        // 平移后,內容區(qū)域上部有空白處理辦法 
        if (-transY < currentSubY) { 
          transY = -currentSubY; 
        } 
        // 平移后,內容區(qū)域下部有空白處理辦法 
        if (currentSubY + transY < limitY1) { 
          transY = -(currentHeight + currentSubY - contentH); 
        } 
      } else { 
        // 如果圖片放大后沒有超出屏幕范圍處理,則不允許拖動 
        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; 
  } 
 
  /** 
   * 獲取兩點間的距離 
   * 
   * @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 這個用于測試的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_image_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_imageview_imageControl1); 
    llTitle = (LinearLayout) findViewById(id.common_imageview_llTitle); 
    tvTitle = (TextView) findViewById(id.common_imageview_title); 
  } 
 
  private void init() { 
    tvTitle.setText("圖片測試"); 
    // 這里可以為imgcontrol的圖片路徑動態(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.imageInit(bmp, screenW, screenH, statusBarHeight, 
          new ICustomMethod() { 
            
            @Override 
            public void customMethod(Boolean currentStatus) { 
              // 當圖片處于放大或縮小狀態(tài)時,控制標題是否顯示 
              if (currentStatus) { 
                llTitle.setVisibility(View.GONE); 
              } else { 
                llTitle.setVisibility(View.VISIBLE); 
              } 
            } 
          }); 
    } 
    else 
    { 
      Toast.makeText(ImageViewActivity.this, "圖片加載失敗,請稍候再試!", Toast.LENGTH_SHORT) 
          .show(); 
    } 
 
  } 
 
  @Override 
  public boolean onTouchEvent(MotionEvent event) { 
    switch (event.getAction() & MotionEvent.ACTION_MASK) { 
    case MotionEvent.ACTION_DOWN: 
      imgControl.mouseDown(event);       
      break; 
 
    /** 
     * 非第一個點按下 
     */ 
    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); 
  } 
} 

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


common_image_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_imageview_imageControl1" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:src="@drawable/ic_launcher" /> 
 
  <LinearLayout 
    android:id="@+id/common_imageview_llTitle" 
    style="@style/reportTitle1" 
    android:layout_alignParentLeft="true" 
    android:layout_alignParentTop="true" > 
 
    <TextView 
      android:id="@+id/common_imageview_title" 
      style="@style/title2" 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:layout_weight="1" 
      android:text="報告" /> 
  </LinearLayout> 
 
</RelativeLayout> 

相關文章

  • IOS開發(fā)向右滑動返回前一個頁面功能(demo)

    IOS開發(fā)向右滑動返回前一個頁面功能(demo)

    本文給大家介紹使用android實現(xiàn)向右滑動返回一個頁面的功能,大家都知道在ios7中,蘋果的原生態(tài)應用幾乎都能夠通過向右滑動來返回到前一個頁面,這樣可以避免用戶在單手操作時用大拇指去點擊那個遙遠的返回鍵,下面小編就給帶來了實現(xiàn)代碼,有需要的朋友可以參考下
    2016-06-06
  • Kotlin?RecyclerView滾動控件詳解

    Kotlin?RecyclerView滾動控件詳解

    RecyclerView是Android一個更強大的控件,其不僅可以實現(xiàn)和ListView同樣的效果,還有優(yōu)化了ListView中的各種不足。其可以實現(xiàn)數(shù)據縱向滾動,也可以實現(xiàn)橫向滾動(ListView做不到橫向滾動)。接下來講解RecyclerView的用法
    2022-12-12
  • Android使用Retrofit上傳文件功能

    Android使用Retrofit上傳文件功能

    這篇文章主要為大家詳細介紹了Android使用Retrofit上傳文件,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 基于AnDroid FrameLayout的使用詳解

    基于AnDroid FrameLayout的使用詳解

    本篇文章是對AnDroid FrameLayout的使用進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • Android檢測手機多點觸摸點數(shù)的方法

    Android檢測手機多點觸摸點數(shù)的方法

    這篇文章主要為大家詳細介紹了Android檢測手機多點觸摸點數(shù)的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Android Studio中一套代碼多渠道打包的實現(xiàn)方法

    Android Studio中一套代碼多渠道打包的實現(xiàn)方法

    這篇文章主要介紹了Android Studio中一套代碼多渠道打包的實現(xiàn)方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2020-05-05
  • Android提高之使用NDK把彩圖轉換灰度圖的方法

    Android提高之使用NDK把彩圖轉換灰度圖的方法

    這篇文章主要介紹了Android使用NDK把彩圖轉換灰度圖的方法,在Android項目開發(fā)中有一定的實用價值,需要的朋友可以參考下
    2014-08-08
  • Android?數(shù)據壓縮淺析

    Android?數(shù)據壓縮淺析

    這篇文章主要為大家介紹了Android?數(shù)據壓縮方法淺析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • android 設置全屏的兩種方法

    android 設置全屏的兩種方法

    現(xiàn)在android的每一個項目都會需要設置為全屏,現(xiàn)在介紹兩種設置為全屏的方式
    2014-05-05
  • Android開發(fā)解決popupWindow重疊報錯問題

    Android開發(fā)解決popupWindow重疊報錯問題

    今天小編就為大家分享一篇關于Android開發(fā)解決popupWindow重疊報錯問題的文章,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-10-10

最新評論

贵德县| 太和县| 洪江市| 龙泉市| 巴楚县| 牡丹江市| 邵阳县| 崇州市| 太白县| 黔东| 尚义县| 宣武区| 象山县| 嘉兴市| 彩票| 江孜县| 仁布县| 南昌县| 营口市| 屯留县| 城固县| 遵义县| 邹平县| 五大连池市| 宜川县| 冕宁县| 万州区| 静海县| 宣威市| 万载县| 兴安盟| 隆子县| 任丘市| 资源县| 榆树市| 宜兰市| 喜德县| 丰原市| 香河县| 通州市| 云浮市|