欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android通過多點(diǎn)觸控的方式對圖片進(jìn)行縮放的實(shí)例代碼

 更新時間:2018年05月11日 11:55:16   作者:guolin  
這篇文章主要介紹了Android通過多點(diǎn)觸控的方式對圖片進(jìn)行縮放的實(shí)例代碼,完成了點(diǎn)擊圖片就能瀏覽大圖的功能,并且在瀏覽大圖的時候還可以通過多點(diǎn)觸控的方式對圖片進(jìn)行縮放。

在上一篇文章中我?guī)е蠹乙黄饘?shí)現(xiàn)了Android瀑布流照片墻的效果,雖然這種效果很炫很酷,但其實(shí)還只能算是一個半成品,因?yàn)檎掌瑝χ兴械膱D片都是只能看不能點(diǎn)的。因此本篇文章中,我們就來對這一功能進(jìn)行完善,加入點(diǎn)擊圖片就能瀏覽大圖的功能,并且在瀏覽大圖的時候還可以通過多點(diǎn)觸控的方式對圖片進(jìn)行縮放。

如果你還沒有看過Android瀑布流照片墻實(shí)現(xiàn) 體驗(yàn)不規(guī)則排列的美感 這篇文章,請盡量先去閱讀完再來看本篇文章,因?yàn)檫@次的代碼完全是在上次的基礎(chǔ)上進(jìn)行開發(fā)的。

那我們現(xiàn)在就開始動手吧,首先打開上次的PhotoWallFallsDemo項目,在里面加入一個ZoomImageView類,這個類就是用于進(jìn)行大圖展示和多點(diǎn)觸控縮放的,代碼如下所示:

public class ZoomImageView extends View { 
 /** 
  * 初始化狀態(tài)常量 
  */ 
 public static final int STATUS_INIT = 1; 
 /** 
  * 圖片放大狀態(tài)常量 
  */ 
 public static final int STATUS_ZOOM_OUT = 2; 
 /** 
  * 圖片縮小狀態(tài)常量 
  */ 
 public static final int STATUS_ZOOM_IN = 3; 
 /** 
  * 圖片拖動狀態(tài)常量 
  */ 
 public static final int STATUS_MOVE = 4; 
 /** 
  * 用于對圖片進(jìn)行移動和縮放變換的矩陣 
  */ 
 private Matrix matrix = new Matrix(); 
 /** 
  * 待展示的Bitmap對象 
  */ 
 private Bitmap sourceBitmap; 
 /** 
  * 記錄當(dāng)前操作的狀態(tài),可選值為STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN和STATUS_MOVE 
  */ 
 private int currentStatus; 
 /** 
  * ZoomImageView控件的寬度 
  */ 
 private int width; 
 /** 
  * ZoomImageView控件的高度 
  */ 
 private int height; 
 /** 
  * 記錄兩指同時放在屏幕上時,中心點(diǎn)的橫坐標(biāo)值 
  */ 
 private float centerPointX; 
 /** 
  * 記錄兩指同時放在屏幕上時,中心點(diǎn)的縱坐標(biāo)值 
  */ 
 private float centerPointY; 
 /** 
  * 記錄當(dāng)前圖片的寬度,圖片被縮放時,這個值會一起變動 
  */ 
 private float currentBitmapWidth; 
 /** 
  * 記錄當(dāng)前圖片的高度,圖片被縮放時,這個值會一起變動 
  */ 
 private float currentBitmapHeight; 
 /** 
  * 記錄上次手指移動時的橫坐標(biāo) 
  */ 
 private float lastXMove = -1; 
 /** 
  * 記錄上次手指移動時的縱坐標(biāo) 
  */ 
 private float lastYMove = -1; 
 /** 
  * 記錄手指在橫坐標(biāo)方向上的移動距離 
  */ 
 private float movedDistanceX; 
 /** 
  * 記錄手指在縱坐標(biāo)方向上的移動距離 
  */ 
 private float movedDistanceY; 
 /** 
  * 記錄圖片在矩陣上的橫向偏移值 
  */ 
 private float totalTranslateX; 
 /** 
  * 記錄圖片在矩陣上的縱向偏移值 
  */ 
 private float totalTranslateY; 
 /** 
  * 記錄圖片在矩陣上的總縮放比例 
  */ 
 private float totalRatio; 
 /** 
  * 記錄手指移動的距離所造成的縮放比例 
  */ 
 private float scaledRatio; 
 /** 
  * 記錄圖片初始化時的縮放比例 
  */ 
 private float initRatio; 
 /** 
  * 記錄上次兩指之間的距離 
  */ 
 private double lastFingerDis; 
 /** 
  * ZoomImageView構(gòu)造函數(shù),將當(dāng)前操作狀態(tài)設(shè)為STATUS_INIT。 
  * 
  * @param context 
  * @param attrs 
  */ 
 public ZoomImageView(Context context, AttributeSet attrs) { 
  super(context, attrs); 
  currentStatus = STATUS_INIT; 
 } 
 /** 
  * 將待展示的圖片設(shè)置進(jìn)來。 
  * 
  * @param bitmap 
  *   待展示的Bitmap對象 
  */ 
 public void setImageBitmap(Bitmap bitmap) { 
  sourceBitmap = bitmap; 
  invalidate(); 
 } 
 @Override 
 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 
  super.onLayout(changed, left, top, right, bottom); 
  if (changed) { 
   // 分別獲取到ZoomImageView的寬度和高度 
   width = getWidth(); 
   height = getHeight(); 
  } 
 } 
 @Override 
 public boolean onTouchEvent(MotionEvent event) { 
  switch (event.getActionMasked()) { 
  case MotionEvent.ACTION_POINTER_DOWN: 
   if (event.getPointerCount() == 2) { 
    // 當(dāng)有兩個手指按在屏幕上時,計算兩指之間的距離 
    lastFingerDis = distanceBetweenFingers(event); 
   } 
   break; 
  case MotionEvent.ACTION_MOVE: 
   if (event.getPointerCount() == 1) { 
    // 只有單指按在屏幕上移動時,為拖動狀態(tài) 
    float xMove = event.getX(); 
    float yMove = event.getY(); 
    if (lastXMove == -1 && lastYMove == -1) { 
     lastXMove = xMove; 
     lastYMove = yMove; 
    } 
    currentStatus = STATUS_MOVE; 
    movedDistanceX = xMove - lastXMove; 
    movedDistanceY = yMove - lastYMove; 
    // 進(jìn)行邊界檢查,不允許將圖片拖出邊界 
    if (totalTranslateX + movedDistanceX > 0) { 
     movedDistanceX = 0; 
    } else if (width - (totalTranslateX + movedDistanceX) > currentBitmapWidth) { 
     movedDistanceX = 0; 
    } 
    if (totalTranslateY + movedDistanceY > 0) { 
     movedDistanceY = 0; 
    } else if (height - (totalTranslateY + movedDistanceY) > currentBitmapHeight) { 
     movedDistanceY = 0; 
    } 
    // 調(diào)用onDraw()方法繪制圖片 
    invalidate(); 
    lastXMove = xMove; 
    lastYMove = yMove; 
   } else if (event.getPointerCount() == 2) { 
    // 有兩個手指按在屏幕上移動時,為縮放狀態(tài) 
    centerPointBetweenFingers(event); 
    double fingerDis = distanceBetweenFingers(event); 
    if (fingerDis > lastFingerDis) { 
     currentStatus = STATUS_ZOOM_OUT; 
    } else { 
     currentStatus = STATUS_ZOOM_IN; 
    } 
    // 進(jìn)行縮放倍數(shù)檢查,最大只允許將圖片放大4倍,最小可以縮小到初始化比例 
    if ((currentStatus == STATUS_ZOOM_OUT && totalRatio < 4 * initRatio) 
      || (currentStatus == STATUS_ZOOM_IN && totalRatio > initRatio)) { 
     scaledRatio = (float) (fingerDis / lastFingerDis); 
     totalRatio = totalRatio * scaledRatio; 
     if (totalRatio > 4 * initRatio) { 
      totalRatio = 4 * initRatio; 
     } else if (totalRatio < initRatio) { 
      totalRatio = initRatio; 
     } 
     // 調(diào)用onDraw()方法繪制圖片 
     invalidate(); 
     lastFingerDis = fingerDis; 
    } 
   } 
   break; 
  case MotionEvent.ACTION_POINTER_UP: 
   if (event.getPointerCount() == 2) { 
    // 手指離開屏幕時將臨時值還原 
    lastXMove = -1; 
    lastYMove = -1; 
   } 
   break; 
  case MotionEvent.ACTION_UP: 
   // 手指離開屏幕時將臨時值還原 
   lastXMove = -1; 
   lastYMove = -1; 
   break; 
  default: 
   break; 
  } 
  return true; 
 } 
 /** 
  * 根據(jù)currentStatus的值來決定對圖片進(jìn)行什么樣的繪制操作。 
  */ 
 @Override 
 protected void onDraw(Canvas canvas) { 
  super.onDraw(canvas); 
  switch (currentStatus) { 
  case STATUS_ZOOM_OUT: 
  case STATUS_ZOOM_IN: 
   zoom(canvas); 
   break; 
  case STATUS_MOVE: 
   move(canvas); 
   break; 
  case STATUS_INIT: 
   initBitmap(canvas); 
  default: 
   canvas.drawBitmap(sourceBitmap, matrix, null); 
   break; 
  } 
 } 
 /** 
  * 對圖片進(jìn)行縮放處理。 
  * 
  * @param canvas 
  */ 
 private void zoom(Canvas canvas) { 
  matrix.reset(); 
  // 將圖片按總縮放比例進(jìn)行縮放 
  matrix.postScale(totalRatio, totalRatio); 
  float scaledWidth = sourceBitmap.getWidth() * totalRatio; 
  float scaledHeight = sourceBitmap.getHeight() * totalRatio; 
  float translateX = 0f; 
  float translateY = 0f; 
  // 如果當(dāng)前圖片寬度小于屏幕寬度,則按屏幕中心的橫坐標(biāo)進(jìn)行水平縮放。否則按兩指的中心點(diǎn)的橫坐標(biāo)進(jìn)行水平縮放 
  if (currentBitmapWidth < width) { 
   translateX = (width - scaledWidth) / 2f; 
  } else { 
   translateX = totalTranslateX * scaledRatio + centerPointX * (1 - scaledRatio); 
   // 進(jìn)行邊界檢查,保證圖片縮放后在水平方向上不會偏移出屏幕 
   if (translateX > 0) { 
    translateX = 0; 
   } else if (width - translateX > scaledWidth) { 
    translateX = width - scaledWidth; 
   } 
  } 
  // 如果當(dāng)前圖片高度小于屏幕高度,則按屏幕中心的縱坐標(biāo)進(jìn)行垂直縮放。否則按兩指的中心點(diǎn)的縱坐標(biāo)進(jìn)行垂直縮放 
  if (currentBitmapHeight < height) { 
   translateY = (height - scaledHeight) / 2f; 
  } else { 
   translateY = totalTranslateY * scaledRatio + centerPointY * (1 - scaledRatio); 
   // 進(jìn)行邊界檢查,保證圖片縮放后在垂直方向上不會偏移出屏幕 
   if (translateY > 0) { 
    translateY = 0; 
   } else if (height - translateY > scaledHeight) { 
    translateY = height - scaledHeight; 
   } 
  } 
  // 縮放后對圖片進(jìn)行偏移,以保證縮放后中心點(diǎn)位置不變 
  matrix.postTranslate(translateX, translateY); 
  totalTranslateX = translateX; 
  totalTranslateY = translateY; 
  currentBitmapWidth = scaledWidth; 
  currentBitmapHeight = scaledHeight; 
  canvas.drawBitmap(sourceBitmap, matrix, null); 
 } 
 /** 
  * 對圖片進(jìn)行平移處理 
  * 
  * @param canvas 
  */ 
 private void move(Canvas canvas) { 
  matrix.reset(); 
  // 根據(jù)手指移動的距離計算出總偏移值 
  float translateX = totalTranslateX + movedDistanceX; 
  float translateY = totalTranslateY + movedDistanceY; 
  // 先按照已有的縮放比例對圖片進(jìn)行縮放 
  matrix.postScale(totalRatio, totalRatio); 
  // 再根據(jù)移動距離進(jìn)行偏移 
  matrix.postTranslate(translateX, translateY); 
  totalTranslateX = translateX; 
  totalTranslateY = translateY; 
  canvas.drawBitmap(sourceBitmap, matrix, null); 
 } 
 /** 
  * 對圖片進(jìn)行初始化操作,包括讓圖片居中,以及當(dāng)圖片大于屏幕寬高時對圖片進(jìn)行壓縮。 
  * 
  * @param canvas 
  */ 
 private void initBitmap(Canvas canvas) { 
  if (sourceBitmap != null) { 
   matrix.reset(); 
   int bitmapWidth = sourceBitmap.getWidth(); 
   int bitmapHeight = sourceBitmap.getHeight(); 
   if (bitmapWidth > width || bitmapHeight > height) { 
    if (bitmapWidth - width > bitmapHeight - height) { 
     // 當(dāng)圖片寬度大于屏幕寬度時,將圖片等比例壓縮,使它可以完全顯示出來 
     float ratio = width / (bitmapWidth * 1.0f); 
     matrix.postScale(ratio, ratio); 
     float translateY = (height - (bitmapHeight * ratio)) / 2f; 
     // 在縱坐標(biāo)方向上進(jìn)行偏移,以保證圖片居中顯示 
     matrix.postTranslate(0, translateY); 
     totalTranslateY = translateY; 
     totalRatio = initRatio = ratio; 
    } else { 
     // 當(dāng)圖片高度大于屏幕高度時,將圖片等比例壓縮,使它可以完全顯示出來 
     float ratio = height / (bitmapHeight * 1.0f); 
     matrix.postScale(ratio, ratio); 
     float translateX = (width - (bitmapWidth * ratio)) / 2f; 
     // 在橫坐標(biāo)方向上進(jìn)行偏移,以保證圖片居中顯示 
     matrix.postTranslate(translateX, 0); 
     totalTranslateX = translateX; 
     totalRatio = initRatio = ratio; 
    } 
    currentBitmapWidth = bitmapWidth * initRatio; 
    currentBitmapHeight = bitmapHeight * initRatio; 
   } else { 
    // 當(dāng)圖片的寬高都小于屏幕寬高時,直接讓圖片居中顯示 
    float translateX = (width - sourceBitmap.getWidth()) / 2f; 
    float translateY = (height - sourceBitmap.getHeight()) / 2f; 
    matrix.postTranslate(translateX, translateY); 
    totalTranslateX = translateX; 
    totalTranslateY = translateY; 
    totalRatio = initRatio = 1f; 
    currentBitmapWidth = bitmapWidth; 
    currentBitmapHeight = bitmapHeight; 
   } 
   canvas.drawBitmap(sourceBitmap, matrix, null); 
  } 
 } 
 /** 
  * 計算兩個手指之間的距離。 
  * 
  * @param event 
  * @return 兩個手指之間的距離 
  */ 
 private double distanceBetweenFingers(MotionEvent event) { 
  float disX = Math.abs(event.getX(0) - event.getX(1)); 
  float disY = Math.abs(event.getY(0) - event.getY(1)); 
  return Math.sqrt(disX * disX + disY * disY); 
 } 
 /** 
  * 計算兩個手指之間中心點(diǎn)的坐標(biāo)。 
  * 
  * @param event 
  */ 
 private void centerPointBetweenFingers(MotionEvent event) { 
  float xPoint0 = event.getX(0); 
  float yPoint0 = event.getY(0); 
  float xPoint1 = event.getX(1); 
  float yPoint1 = event.getY(1); 
  centerPointX = (xPoint0 + xPoint1) / 2; 
  centerPointY = (yPoint0 + yPoint1) / 2; 
 } 
} 

由于這個類是整個多點(diǎn)觸控縮放功能最核心的一個類,我在這里給大家詳細(xì)的講解一下。首先在ZoomImageView里我們定義了四種狀態(tài),STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN和STATUS_MOVE,這四個狀態(tài)分別代表初始化、放大、縮小和移動這幾個動作,然后在構(gòu)造函數(shù)里我們將當(dāng)前狀態(tài)置為初始化狀態(tài)。接著我們可以調(diào)用setImageBitmap()方法把要顯示的圖片對象傳進(jìn)去,這個方法會invalidate一下當(dāng)前的View,因此onDraw()方法就會得到執(zhí)行。然后在onDraw()方法里判斷出當(dāng)前的狀態(tài)是初始化狀態(tài),所以就會調(diào)用initBitmap()方法進(jìn)行初始化操作。

那我們就來看一下initBitmap()方法,在這個方法中首先對圖片的大小進(jìn)行了判斷,如果圖片的寬和高都是小于屏幕的寬和高的,則直接將這張圖片進(jìn)行偏移,讓它能夠居中顯示在屏幕上。如果圖片的寬度大于屏幕的寬度,或者圖片的高度大于屏幕的高度,則將圖片進(jìn)行等比例壓縮,讓圖片的的寬或高正好等同于屏幕的寬或高,保證在初始化狀態(tài)下圖片一定能完整地顯示出來。這里所有的偏移和縮放操作都是通過矩陣來完成的,我們把要縮放和偏移的值都存放在矩陣中,然后在繪制圖片的時候傳入這個矩陣對象就可以了。

圖片初始化完成之后,就可以對圖片進(jìn)行縮放處理了。這里在onTouchEvent()方法來對點(diǎn)擊事件進(jìn)行判斷,如果發(fā)現(xiàn)有兩個手指同時按在屏幕上(使用event.getPointerCount()判斷)就將當(dāng)前狀態(tài)置為縮放狀態(tài),并調(diào)用distanceBetweenFingers()來得到兩指之間的距離,以計算出縮放比例。然后invalidate一下,就會在onDraw()方法中就會調(diào)用zoom()方法。之后就在這個方法里根據(jù)當(dāng)前的縮放比例以及中心點(diǎn)的位置對圖片進(jìn)行縮放和偏移,具體的邏輯大家請仔細(xì)閱讀代碼,注釋已經(jīng)寫得非常清楚。

然后當(dāng)只有一個手指按在屏幕上時,就把當(dāng)前狀態(tài)置為移動狀態(tài),之后會對手指的移動距離進(jìn)行計算,并處理了邊界檢查的工作,以防止圖片偏移出屏幕。然后invalidate一下當(dāng)前的view,又會進(jìn)入到onDraw()方法中,這里判斷出當(dāng)前是移動狀態(tài),于是會調(diào)用move()方法。move()方法中的代碼非常簡單,就是根據(jù)手指移動的距離對圖片進(jìn)行偏移就可以了。

介紹完了ZoomImageView,然后我們新建一個布局image_details.xml,在布局中直接引用創(chuàng)建好的ZoomImageView:

<?xml version="1.0" encoding="utf-8"?> 
<com.example.photowallfallsdemo.ZoomImageView xmlns:android="http://schemas.android.com/apk/res/android" 
 android:id="@+id/zoom_image_view" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:background="#000000" > 
</com.example.photowallfallsdemo.ZoomImageView> 

接著創(chuàng)建一個Activity,在這個Activity中來加載image_details布局。新建ImageDetailsActivity,代碼如下所示:

public class ImageDetailsActivity extends Activity { 
 private ZoomImageView zoomImageView; 
 @Override 
 protected void onCreate(Bundle savedInstanceState) { 
  super.onCreate(savedInstanceState); 
  requestWindowFeature(Window.FEATURE_NO_TITLE); 
  setContentView(R.layout.image_details); 
  zoomImageView = (ZoomImageView) findViewById(R.id.zoom_image_view); 
  String imagePath = getIntent().getStringExtra("image_path"); 
  Bitmap bitmap = BitmapFactory.decodeFile(imagePath); 
  zoomImageView.setImageBitmap(bitmap); 
 } 
} 

可以看到,首先我們獲取到了ZoomImageView的實(shí)例,然后又通過Intent得到了需要展示的圖片路徑,接著使用BitmapFactory將路徑下的圖片加載到內(nèi)存中,然后調(diào)用ZoomImageView的setImageBitmap()方法將圖片傳入,就可以讓這張圖片展示出來了。

接下來我們需要考慮的,就是如何在照片墻上給圖片增加點(diǎn)擊事件,讓它能夠啟動ImageDetailsActivity了。其實(shí)這也很簡單,只需要在動態(tài)添加圖片的時候給每個ImageView的實(shí)例注冊一下點(diǎn)擊事件就好了,修改MyScrollView中addImage()方法的代碼,如下所示:

private void addImage(Bitmap bitmap, int imageWidth, int imageHeight) { 
 LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(imageWidth, 
   imageHeight); 
 if (mImageView != null) { 
  mImageView.setImageBitmap(bitmap); 
 } else { 
  ImageView imageView = new ImageView(getContext()); 
  imageView.setLayoutParams(params); 
  imageView.setImageBitmap(bitmap); 
  imageView.setScaleType(ScaleType.FIT_XY); 
  imageView.setPadding(5, 5, 5, 5); 
  imageView.setTag(R.string.image_url, mImageUrl); 
  imageView.setOnClickListener(new OnClickListener() { 
   @Override 
   public void onClick(View v) { 
    Intent intent = new Intent(getContext(), ImageDetailsActivity.class); 
    intent.putExtra("image_path", getImagePath(mImageUrl)); 
    getContext().startActivity(intent); 
   } 
  }); 
  findColumnToAdd(imageView, imageHeight).addView(imageView); 
  imageViewList.add(imageView); 
 } 
}

可以看到,這里我們調(diào)用了ImageView的setOnClickListener()方法來給圖片增加點(diǎn)擊事件,當(dāng)用戶點(diǎn)擊了照片墻中的任意圖片時,就會啟動ImageDetailsActivity,并將圖片的路徑傳遞過去。

由于我們添加了一個新的Activity,別忘了在AndroidManifest.xml文件里注冊一下:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
 package="com.example.photowallfallsdemo" 
 android:versionCode="1" 
 android:versionName="1.0" > 
 <uses-sdk 
  android:minSdkVersion="14" 
  android:targetSdkVersion="17" /> 
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
 <uses-permission android:name="android.permission.INTERNET" /> 
 <application 
  android:allowBackup="true" 
  android:icon="@drawable/ic_launcher" 
  android:label="@string/app_name" 
  android:theme="@style/AppTheme" > 
  <activity 
   android:name="com.example.photowallfallsdemo.MainActivity" 
   android:label="@string/app_name" > 
   <intent-filter> 
    <action android:name="android.intent.action.MAIN" /> 
    <category android:name="android.intent.category.LAUNCHER" /> 
   </intent-filter> 
  </activity> 
  <activity android:name="com.example.photowallfallsdemo.ImageDetailsActivity" > 
  </activity> 
 </application> 
</manifest> 

這樣所有的編碼工作就已經(jīng)完成了,現(xiàn)在我們運(yùn)行一下程序,又會看到熟悉的照片墻界面,點(diǎn)擊任意一張圖片會進(jìn)入到相應(yīng)的大圖界面,并且可以通過多點(diǎn)觸控的方式對圖片進(jìn)行縮放,放大后還可以通過單指來移動圖片,如下圖所示。

好了,今天的講解到此結(jié)束,有疑問的朋友請在下面留言。

源碼下載,請點(diǎn)擊這里
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論