国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android 在viewPager中雙指縮放圖片雙擊縮放圖片單指拖拽圖片的實現思路

2019-10-23 18:29:08
字體:
來源:轉載
供稿:網友

我們就把這個問題叫做圖片查看器吧,它的主要功能有:

1、雙擊縮放圖片。

2、 雙指縮放圖片。

3、單指拖拽圖片。

為此這個圖片查看器需要考慮以下的技術點:

一、雙擊縮放圖片:

1、如果圖片高度比屏幕的高度小得多,那么就將圖片放大到高度與屏幕高度相等,否則就放大一個特定的倍數。

2、如何判斷是否到達這個倍數來停止縮放。

3、判斷完且停止放大后,圖片可能已經超出了這個倍數需要的大小,如何回歸到我們的目標大小。

4、判斷完且停止縮小后,圖片寬度可能已經小于屏幕寬度,在兩邊留下了空白,如何重置為原來的大小。

二、雙指縮放圖片:

1、雙指縮放,放大一個特定的倍數停止。

2、如何判斷是否到達這個倍數。

3、放大停止后,圖片可能已經超出了這個倍數需要的大小,如何回歸到我們的目標大小。

4、縮小停止后,圖片寬度可能已經小于屏幕寬度,在兩邊留下了空白,如何重置為原來的大小。

三、單指拖拽:

1、當圖片寬度小于或等于屏幕寬度的時候,禁止左右移動,當圖片的高度小于屏幕高度的時候,禁止上下移動。

2、移動圖片時,如果圖片的一邊已經與屏幕之間有了空白,松手后恢復,讓圖片的這一邊與屏幕邊界重合。

四、

如何判斷是雙擊,還是多指觸控,還是單指。

五、

如何解決與viewPager的滑動沖突,當圖片已經滑動到盡頭無法滑動時,此時viewPager應該攔截事件。

我們逐一來解決:

public class MyImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener,View.OnTouchListener { public MyImageView(Context context, AttributeSet attrs) {  super(context, attrs);  super.setScaleType(ScaleType.MATRIX);  setOnTouchListener(this);  /**   * 雙擊實現圖片放大縮小   */  mGestureDetector = new GestureDetector(context,    new GestureDetector.SimpleOnGestureListener() {     @Override     public boolean onDoubleTap(MotionEvent e) {      changeViewSize(e);      return true;     }    }); }

在這里縮放圖片是用matrix,因此首先要設置scaleType為matrix。
用手勢判斷雙擊行為。不要忘了在onTouch里面加上

if (mGestureDetector.onTouchEvent(event))   return true;

判斷單指與多指觸控,則在onTouch里面判斷,要用 event.getAction() & MotionEvent.ACTION_MASK來判斷。

//多指觸控模式,單指,雙指private int mode;private final static int SINGLE_TOUCH = 1; //單指private final static int DOUBLE_TOUCH = 2; //雙指@Override public boolean onTouch(View view, MotionEvent event) {  rectF = getMatrixRectF();  if (mGestureDetector.onTouchEvent(event))   return true;  switch (event.getAction() & event.getActionMasked()) {   case MotionEvent.ACTION_DOWN:    mode = SINGLE_TOUCH;    break;   case MotionEvent.ACTION_MOVE:    if (mode >= DOUBLE_TOUCH) //雙指縮放    {    }    if (mode == SINGLE_TOUCH) //單指拖拽    {    }    break;   case MotionEvent.ACTION_POINTER_DOWN:    mode += 1;break;   case MotionEvent.ACTION_POINTER_UP:    mode -= 1;    break;   case MotionEvent.ACTION_UP:    mode = 0;    break;   //在ACTION_MOVE中,事件被攔截了之后,有時候ACTION_UP無法觸發,所以加上了ACTION_CANCEL   case MotionEvent.ACTION_CANCEL:    mode = 0;    break;   default:    break;  }  return true; }

有如下事件使我們要用到的:

MotionEvent.ACTION_DOWN:在第一個點被按下時觸發

MotionEvent.ACTION_UP:當屏幕上唯一的點被放開時觸發

MotionEvent.ACTION_POINTER_DOWN:當屏幕上已經有一個點被按住,此時再按下其他點時觸發。

MotionEvent.ACTION_POINTER_UP:當屏幕上有多個點被按住,松開其中一個點時觸發(即非最后一個點被放開時)。

MotionEvent.ACTION_MOVE:當有點在屏幕上移動時觸發。值得注意的是,由于它的靈敏度很高,而我們的手指又不可能完全靜止(即使我們感覺不到移動,但其實我們的手指也在不停地抖動),所以實際的情況是,基本上只要有點在屏幕上,此事件就會一直不停地被觸發。

在ACTION_MOVE中通過mode的大小來判斷是單指還是雙指。

不過有一個令人傷心的事情,Android自己有一個bug。經過測試發現雙指交換觸碰圖片的時候,程序會閃退,出現異常:pointIndex out of range。這是Android自己的bug。個人覺得最好得解決方法是自定義一個viewPager,然后在里面重寫:onTouchEvent,onInterceptTouchEvent,然后捕獲異常。

@Override public boolean onTouchEvent(MotionEvent ev) {  try {   return super.onTouchEvent(ev);  } catch (IllegalArgumentException ex) {   ex.printStackTrace();  }  return false; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) {  try {   return super.onInterceptTouchEvent(ev);  } catch (IllegalArgumentException ex) {   ex.printStackTrace();  }  return false; }

這樣程序就不會閃退了。

我們來看看雙擊放大的的代碼:  

 /**  * 雙擊縮放圖片  */ private void changeViewSize(MotionEvent e) {  //獲取雙擊的坐標  final float x = e.getX();  final float y = e.getY();  //如果此時還在縮放那就直接返回  if (animator != null && animator.isRunning())   return;  //判斷是處于放大還是縮小的狀態  if (!isZoomChanged()) {   animator = ValueAnimator.ofFloat(1.0f, 2.0f);  } else {   animator = ValueAnimator.ofFloat(1.0f, 0.0f);  }  animator.setTarget(this);  animator.setDuration(500);  animator.setInterpolator(new DecelerateInterpolator());  animator.start();  animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {   @Override   public void onAnimationUpdate(ValueAnimator valueAnimator) {    Float value = (Float) animator.getAnimatedValue();    matrix.postScale(value, value, x, y);    checkBorderAndCenterWhenScale(); //在縮放后讓圖片居中    setImageMatrix(matrix);    /**     * 控制縮小的范圍     * 如果已經小于初始大小,那么恢復到初始大小,然后停止     */    if (checkRestScale()) {     matrix.set(oldMatrix); //oldMatrix為最原始的matrix     setImageMatrix(matrix);     return;    }    /**     * 控制放大的范圍     * 如果已經大于目標的放大倍數,那么直接置為目標的放大倍數     * 然后停止     */    if (getMatrixValueX() >= mDoubleClickScale)    {     matrix.postScale(mDoubleClickScale/getMatrixValueX(), mDoubleClickScale/getMatrixValueX(), x, y);     checkBorderAndCenterWhenScale();     setImageMatrix(matrix);     return;    }   }  }); }

判斷處于放大還是縮小狀態的代碼:(不是初始值就說明是處于放大狀態)

 /**  * 判斷縮放級別是否是改變過  *  * @return true表示非初始值, false表示初始值  */ private boolean isZoomChanged() {  float[] values = new float[9];  getImageMatrix().getValues(values);  //獲取當前X軸縮放級別  float scale = values[Matrix.MSCALE_X];  //獲取初始時候的X軸縮放級別,兩者做比較  oldMatrix.getValues(values);  return scale != values[Matrix.MSCALE_X]; }

getMatrixValue()的代碼如下,是為了取得當前的放大倍數,相對于一開始的圖片來說

 private float getMatrixValueX() {  // TODO Auto-generated method stub  float[] values = new float[9];  getImageMatrix().getValues(values);  //獲取當前X軸縮放級別  float scale = values[Matrix.MSCALE_X];  //獲取原始Matrix的X軸縮放級別  oldMatrix.getValues(values);  //返回放大的倍數  return scale / values[Matrix.MSCALE_X]; }

checkRestScale()的代碼如下,主要是為了判斷當前的縮放級別是否小于最初始的縮放級別。

 /**  * 判斷是否需要重置  *  * @return 當前縮放級別小于原始縮放級別時,重置  */ private boolean checkRestScale() {  // TODO Auto-generated method stub  float[] values = new float[9];  getImageMatrix().getValues(values);  //獲取當前X軸縮放級別  float scale = values[Matrix.MSCALE_X];  //獲取原始的X軸縮放級別,兩者做比較  oldMatrix.getValues(values);  return scale < values[Matrix.MSCALE_X]; }

checkBorderAndCenterWhenScale()的代碼如下,否則android/235508.html">圖片縮放后位置會發生變化。

/**  * 在縮放時,進行圖片顯示范圍的控制  */ private void checkBorderAndCenterWhenScale() {  RectF rect = getMatrixRectF();  float deltaX = 0;  float deltaY = 0;  int width = getWidth();  int height = getHeight();  // 如果寬或高大于屏幕,則控制范圍  if (rect.width() >= width)  {   if (rect.left > 0)   {    deltaX = -rect.left;   }   if (rect.right < width)   {    deltaX = width - rect.right;   }  }  if (rect.height() >= height)  {   if (rect.top > 0)   {    deltaY = -rect.top;   }   if (rect.bottom < height)   {    deltaY = height - rect.bottom;   }  }  // 如果寬或高小于屏幕,則讓其居中  if (rect.width() < width)  {   deltaX = width * 0.5f - rect.right + 0.5f * rect.width();  }  if (rect.height() < height)  {   deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height();  }  matrix.postTranslate(deltaX, deltaY);  setImageMatrix(matrix); }

接下看看雙指縮放和單指拖拽:

@Override public boolean onTouch(View view, MotionEvent event) {  rectF = getMatrixRectF(); //獲取圖片邊界范圍  if (mGestureDetector.onTouchEvent(event))   return true;  switch (event.getAction() & event.getActionMasked()) {   case MotionEvent.ACTION_DOWN:    //如果放大后圖片的邊界超出了屏幕,那么就攔截事件,不讓viewPager處理    if (rectF.width() > getWidth() || rectF.height() > getHeight()) {     getParent().requestDisallowInterceptTouchEvent(true);    }    mode = SINGLE_TOUCH;    x = (int) event.getRawX();    y = (int) event.getRawY();    break;   case MotionEvent.ACTION_MOVE:    if (mode >= DOUBLE_TOUCH) //雙指縮放    {     getParent().requestDisallowInterceptTouchEvent(true);     newDist = calculateDist(event); //計算距離     Point point = getMiPoint(event); //獲取兩手指間的中點坐標     if (newDist > oldDist + 1) //放大(加一是為了防止抖動)     {      changeViewSize(oldDist, newDist, point); //根據距離實現放大縮小      oldDist = newDist;     }     if (oldDist > newDist + 1) //縮小     {      changeViewSize(oldDist, newDist, point);      oldDist = newDist;     }    }    if (mode == SINGLE_TOUCH) //單指拖拽    {     float dx = event.getRawX() - x;     float dy = event.getRawY() - y;     //如果移動過程中圖片的邊界超出了屏幕,那么就攔截事件,不讓viewPager處理     if (rectF.width() > getWidth() || rectF.height() > getHeight()) {      getParent().requestDisallowInterceptTouchEvent(true);     }     //如果向右移動圖片到了盡頭,那么就不要攔截事件,讓viewPager處理     if (rectF.left >= 0 && dx > 0)      getParent().requestDisallowInterceptTouchEvent(false);     //如果向左移動到了盡頭,那么就不要攔截事件,讓viewPager處理     if (rectF.right <= getWidth() && dx < 0)      getParent().requestDisallowInterceptTouchEvent(false);     if (getDrawable() != null) {      //如果圖片寬度或高度沒有超出屏幕,那么就禁止左右或上下滑動      if (rectF.width() <= getWidth())       dx = 0;      if (rectF.height() < getHeight())       dy = 0;      //如果圖片向下移動到了盡頭,不讓它繼續移動      if (rectF.top >= 0 && dy > 0)       dy = 0;      //如果圖片向上移動到了盡頭,不讓它繼續移動      if (rectF.bottom <= getHeight() && dy < 0)       dy = 0;      //當移動距離大于1的時候再移動,因為ACTION_MOVE比較靈敏,      // 手指即使只是放在上面,依然能夠檢測到手指的抖動,然后讓圖片移動。      if (Math.abs(dx) > 1 || Math.abs(dy) > 1)       matrix.postTranslate(dx, dy);      setImageMatrix(matrix);     }    }    x = (int) event.getRawX();    y = (int) event.getRawY();    break;   case MotionEvent.ACTION_POINTER_DOWN:    mode += 1;    oldDist = calculateDist(event); break;   case MotionEvent.ACTION_POINTER_UP:    mode -= 1;    break;   case MotionEvent.ACTION_UP:    backToPosition();    mode = 0;    break;   //在ACTION_MOVE中,事件被攔截了之后,有時候ACTION_UP無法觸發,所以加上了ACTION_CANCEL   case MotionEvent.ACTION_CANCEL:    backToPosition();    mode = 0;    break;   default:    break;  }  return true; }

首先先來看一個方法,根據圖片的matrix獲得圖片的邊界范圍,這個范圍映射在rect上。(這個范圍檢測是用在單指拖拽上的)

/**  * 根據當前圖片的Matrix獲得圖片的范圍  *  * @return  */ private RectF getMatrixRectF() {  RectF rect = new RectF();  Drawable d = getDrawable();  if (null != d)  {   rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());   matrix.mapRect(rect);   }  Log.e("aaaa",""+rect.bottom+" "+rect.left+" "+rect.right+" "+rect.top);  return rect; }

rect.bottom:圖片下邊界的縱坐標

rect.left:圖片左邊界的橫坐標

rect.right:圖片右邊界的橫坐標

rect.top:圖片上邊界的縱坐標

rectF.width():圖片寬度

rectF.height():圖片高度

需要注意的是Matrix對圖片的操作都是操作ImageView里面的bitmap,ImageView是沒有變化的,上面所說的屏幕邊界其實ImageView的邊界,getWidth(),getHeight()是ImageView的寬和高。

方法 backToPosition()主要是實現單指拖拽的技術點2,當手指快速劃過去的時候,在檢測到無法繼續滑動前圖片邊界與屏幕邊界已經出現了距離,所以松開手指的時候要復位,讓圖片邊界與屏幕邊界重合。

/**  * 若是在移動后圖片的邊界脫離屏幕邊界,那么就讓圖片邊界與屏幕邊界重合  * 若手指快速移動,停止后會出現圖片距離屏幕有一段空白距離,然后經過判斷不能再移動,  * 但是在進行下一次判斷是否可以繼續移動之前就已經出現了。  * 所以需要復位  */ private void backToPosition() {  if (rectF.left >= 0) { //圖片左邊界與屏幕出現距離   matrix.postTranslate(-rectF.left, 0);   setImageMatrix(matrix);  }  if (rectF.right <= getWidth()) { //圖片右邊界與屏幕出現距離   matrix.postTranslate(getWidth() - rectF.right, 0);   setImageMatrix(matrix);  }  if (rectF.top >= 0) { //圖片上邊界與屏幕出現距離   matrix.postTranslate(0, -rectF.top);   setImageMatrix(matrix);  }  if (rectF.bottom <= getHeight()) { //圖片下邊界與屏幕出現距離   matrix.postTranslate(0, getHeight() - rectF.bottom);   setImageMatrix(matrix);  } }

獲取兩手指間的中點坐標

 /**  * 獲取雙指縮放時候的縮放中點  *  * @return  */ private Point getMiPoint(MotionEvent event) {  float x = event.getX(0) + event.getX(1);  float y = event.getY(0) + event.getY(1);  mPoint.set((int) x / 2, (int) y / 2);  return mPoint; }

計算兩指觸摸點的距離

/**  * 計算兩指觸摸點之間的距離  */ private float calculateDist(MotionEvent event) {  float x = event.getX(0) - event.getX(1);  float y = event.getY(0) - event.getY(1);  return (float) Math.sqrt(x * x + y * y); }

雙指縮放圖片

/**  * 雙指縮放圖片  */ private void changeViewSize(float oldDist, float newDist, Point mPoint) {  float scale = newDist / oldDist; //縮放比例  matrix.postScale(scale, scale, mPoint.x, mPoint.y);  checkBorderAndCenterWhenScale();  setImageMatrix(matrix);  //防止縮小的時候小于初始的圖片大小,需要重置  reSetMatrix();  //如果縮放已經大于目標倍數,停止,因為有可能已經超出,那么就直接縮放到目標大小  if (getMatrixValueX() >= MAX_SCALE)   {   matrix.postScale(MAX_SCALE/getMatrixValueX(), MAX_SCALE/getMatrixValueX(), x, y);   checkBorderAndCenterWhenScale();   setImageMatrix(matrix);   return;  } }

reSetMatrix()的代碼如下:

 /**  * 重置Matrix  */ private void reSetMatrix() {  if (checkRestScale()) {   matrix.set(oldMatrix);   setImageMatrix(matrix);   return;  } }

checkRestScale()的代碼在上面已經給出了。oldMatrix為最初始的Matrix。

到這里還沒有結束,設置Imageview的ScaleType為Matrix,那么圖片不會主動縮放到適應屏幕,也不會處于屏幕中間,因此我們的自定義ImageView需要繼承ViewTreeObserver.OnGlobalLayoutListener

@Override protected void onAttachedToWindow() {  super.onAttachedToWindow();  getViewTreeObserver().addOnGlobalLayoutListener(this); }
@Override public void onGlobalLayout() {  if (once)  {   Drawable d = getDrawable();   if (d == null)    return;   Log.e("TAG", d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight());   int width = getWidth();   int height = getHeight();   // 拿到圖片的寬和高   int dw = d.getIntrinsicWidth();   int dh = d.getIntrinsicHeight();   float scale = 1.0f;   // 如果圖片的寬或者高大于屏幕,則縮放至屏幕的寬或者高   if (dw > width && dh <= height)   {    scale = width * 1.0f / dw;   }   if (dh > height && dw <= width)   {    scale = height * 1.0f / dh;   }   // 如果寬和高都大于屏幕,則讓其按按比例適應屏幕大小   if (dw > width && dh > height)   {    scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);   }   initScale = scale;   Log.e("TAG", "initScale = " + initScale);   matrix.postTranslate((width - dw) / 2, (height - dh) / 2);   matrix.postScale(scale, scale, getWidth() / 2,     getHeight() / 2);   // 圖片移動至屏幕中心   setImageMatrix(matrix);   oldMatrix.set(getImageMatrix());   once = false;   RectF rectF=getMatrixRectF();   setDoubleClickScale(rectF);  } } // 拿到圖片的寬和高 int dw = d.getIntrinsicWidth(); int dh = d.getIntrinsicHeight();

拿到的圖片寬和高是bitmap的真實高度。

初始的oldMatrix就是在這里設置的,然后作為初始模板,代表著圖片沒被動手改變的Matrix。至于方法 setDoubleClickScale(rectF);只是設置雙擊放大的倍數而已,如果圖片高度比屏幕的高度小得多,那么就將圖片放大到高度與屏幕高度相等,否則就放大一個特定的倍數。必須在這里設置,因為在這里取到的rectF才能反映原始圖片的邊界,因為這時候還沒有動手改變圖片。

 /**  * 設置雙擊放大的倍數  */ private void setDoubleClickScale(RectF rectF) {  if(rectF.height()<getHeight()-100)  {   mDoubleClickScale=getHeight()/rectF.height();  }  else   mDoubleClickScale=2f; }

到這里大概結束了,下面就貼出完整的代碼:

package com.example.tangzh.myimageview;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Matrix;import android.graphics.Point;import android.graphics.RectF;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.util.Log;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;import android.view.ViewTreeObserver;import android.view.animation.DecelerateInterpolator;import android.widget.ImageView;/** * Created by TangZH on 2017/5/3. */public class MyImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener,View.OnTouchListener { private final static int SINGLE_TOUCH = 1; //單指 private final static int DOUBLE_TOUCH = 2; //雙指 //多指觸控模式,單指,雙指 private int mode; //兩指觸碰點之間的距離 private float oldDist; private float newDist; /**  * 最大縮放級別  */ private static final float MAX_SCALE = 5f; /**  * 雙擊時的縮放級別  */ private float mDoubleClickScale = 2; /**  * 初始化時的縮放比例,如果圖片寬或高大于屏幕,此值將小于0  */ private float initScale = 1.0f; private boolean once = true; private RectF rectF; /**  * 用于雙擊檢測  */ private GestureDetector mGestureDetector; private int x = 0; private int y = 0; private Point mPoint = new Point(); private final Matrix matrix = new Matrix(); private Matrix oldMatrix = new Matrix(); private ValueAnimator animator; public MyImageView(Context context) {  this(context, null); } public MyImageView(Context context, AttributeSet attrs) {  super(context, attrs);  super.setScaleType(ScaleType.MATRIX);  setOnTouchListener(this);  /**   * 雙擊實現圖片放大縮小   */  mGestureDetector = new GestureDetector(context,    new GestureDetector.SimpleOnGestureListener() {     @Override     public boolean onDoubleTap(MotionEvent e) {      changeViewSize(e);      return true;     }    }); } @Override public boolean onTouch(View view, MotionEvent event) {  rectF = getMatrixRectF(); //獲取圖片邊界范圍  if (mGestureDetector.onTouchEvent(event))   return true;  switch (event.getAction() & event.getActionMasked()) {   case MotionEvent.ACTION_DOWN:    //如果放大后圖片的邊界超出了屏幕,那么就攔截事件,不讓viewPager處理    if (rectF.width() > getWidth() || rectF.height() > getHeight()) {     getParent().requestDisallowInterceptTouchEvent(true);    }    mode = SINGLE_TOUCH;    x = (int) event.getRawX();    y = (int) event.getRawY();    break;   case MotionEvent.ACTION_MOVE:    if (mode >= DOUBLE_TOUCH) //雙指縮放    {     getParent().requestDisallowInterceptTouchEvent(true);     newDist = calculateDist(event); //計算距離     Point point = getMiPoint(event); //獲取兩手指間的中點坐標     if (newDist > oldDist + 1) //放大(加一是為了防止抖動)     {      changeViewSize(oldDist, newDist, point); //根據距離實現放大縮小      oldDist = newDist;     }     if (oldDist > newDist + 1) //縮小     {      changeViewSize(oldDist, newDist, point);      oldDist = newDist;     }    }    if (mode == SINGLE_TOUCH) //單指拖拽    {     float dx = event.getRawX() - x;     float dy = event.getRawY() - y;     //如果移動過程中圖片的邊界超出了屏幕,那么就攔截事件,不讓viewPager處理     if (rectF.width() > getWidth() || rectF.height() > getHeight()) {      getParent().requestDisallowInterceptTouchEvent(true);     }     //如果向右移動圖片到了盡頭,那么就不要攔截事件,讓viewPager處理     if (rectF.left >= 0 && dx > 0)      getParent().requestDisallowInterceptTouchEvent(false);     //如果向左移動到了盡頭,那么就不要攔截事件,讓viewPager處理     if (rectF.right <= getWidth() && dx < 0)      getParent().requestDisallowInterceptTouchEvent(false);     if (getDrawable() != null) {      //如果圖片寬度或高度沒有超出屏幕,那么就禁止左右或上下滑動      if (rectF.width() <= getWidth())       dx = 0;      if (rectF.height() < getHeight())       dy = 0;      //如果圖片向下移動到了盡頭,不讓它繼續移動      if (rectF.top >= 0 && dy > 0)       dy = 0;      //如果圖片向上移動到了盡頭,不讓它繼續移動      if (rectF.bottom <= getHeight() && dy < 0)       dy = 0;      //當移動距離大于1的時候再移動,因為ACTION_MOVE比較靈敏,      // 手指即使只是放在上面,依然能夠檢測到手指的抖動,然后讓圖片移動。      if (Math.abs(dx) > 1 || Math.abs(dy) > 1)       matrix.postTranslate(dx, dy);      setImageMatrix(matrix);     }    }    x = (int) event.getRawX();    y = (int) event.getRawY();    break;   case MotionEvent.ACTION_POINTER_DOWN:    mode += 1;    oldDist = calculateDist(event);    Log.e("q", "" + "a");    Log.e(":::", "" + event.getPointerCount() + " " + event.getActionIndex() + " " + event.findPointerIndex(0));    break;   case MotionEvent.ACTION_POINTER_UP:    mode -= 1;    break;   case MotionEvent.ACTION_UP:    backToPosition();    mode = 0;    break;   //在ACTION_MOVE中,事件被攔截了之后,有時候ACTION_UP無法觸發,所以加上了ACTION_CANCEL   case MotionEvent.ACTION_CANCEL:    backToPosition();    mode = 0;    break;   default:    break;  }  return true; } /**  * 計算兩指觸摸點之間的距離  */ private float calculateDist(MotionEvent event) {  float x = event.getX(0) - event.getX(1);  float y = event.getY(0) - event.getY(1);  return (float) Math.sqrt(x * x + y * y); } @Override protected void onAttachedToWindow() {  super.onAttachedToWindow();  getViewTreeObserver().addOnGlobalLayoutListener(this); } /**  * 若是在移動后圖片的邊界脫離屏幕邊界,那么就讓圖片邊界與屏幕邊界重合  * 若手指快速移動,停止后會出現圖片距離屏幕有一段空白距離,然后經過判斷不能再移動,  * 但是在進行下一次判斷是否可以繼續移動之前就已經出現了。  * 所以需要復位  */ private void backToPosition() {  if (rectF.left >= 0) { //圖片左邊界與屏幕出現距離   matrix.postTranslate(-rectF.left, 0);   setImageMatrix(matrix);  }  if (rectF.right <= getWidth()) { //圖片右邊界與屏幕出現距離   matrix.postTranslate(getWidth() - rectF.right, 0);   setImageMatrix(matrix);  }  if (rectF.top >= 0) { //圖片上邊界與屏幕出現距離   matrix.postTranslate(0, -rectF.top);   setImageMatrix(matrix);  }  if (rectF.bottom <= getHeight()) { //圖片下邊界與屏幕出現距離   matrix.postTranslate(0, getHeight() - rectF.bottom);   setImageMatrix(matrix);  } } /**  * 獲取雙指縮放時候的縮放中點  *  * @return  */ private Point getMiPoint(MotionEvent event) {  float x = event.getX(0) + event.getX(1);  float y = event.getY(0) + event.getY(1);  mPoint.set((int) x / 2, (int) y / 2);  return mPoint; } /**  * 雙指縮放圖片  */ private void changeViewSize(float oldDist, float newDist, Point mPoint) {  float scale = newDist / oldDist; //縮放比例  matrix.postScale(scale, scale, mPoint.x, mPoint.y);  checkBorderAndCenterWhenScale();  setImageMatrix(matrix);  //防止縮小的時候小于初始的圖片大小,需要重置  reSetMatrix();  //如果縮放已經大于目標倍數,停止,因為有可能已經超出,那么就直接縮放到目標大小  if (getMatrixValueX() >= MAX_SCALE)  {   matrix.postScale(MAX_SCALE/getMatrixValueX(), MAX_SCALE/getMatrixValueX(), x, y);   checkBorderAndCenterWhenScale();   setImageMatrix(matrix);   return;  } } /**  * 雙擊縮放圖片  */ private void changeViewSize(MotionEvent e) {  //獲取雙擊的坐標  final float x = e.getX();  final float y = e.getY();  //如果此時還在縮放那就直接返回  if (animator != null && animator.isRunning())   return;  //判斷是處于放大還是縮小的狀態  if (!isZoomChanged()) {   animator = ValueAnimator.ofFloat(1.0f, 2.0f);  } else {   animator = ValueAnimator.ofFloat(1.0f, 0.0f);  }  animator.setTarget(this);  animator.setDuration(500);  animator.setInterpolator(new DecelerateInterpolator());  animator.start();  animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {   @Override   public void onAnimationUpdate(ValueAnimator valueAnimator) {    Float value = (Float) animator.getAnimatedValue();    matrix.postScale(value, value, x, y);    checkBorderAndCenterWhenScale();    setImageMatrix(matrix);    /**     * 控制縮小的范圍     * 如果已經小于初始大小,那么恢復到初始大小,然后停止     */    if (checkRestScale()) {     matrix.set(oldMatrix);     setImageMatrix(matrix);     return;    }    /**     * 控制放大的范圍     * 如果已經大于目標的放大倍數,那么直接置為目標的放大倍數     * 然后停止     */    if (getMatrixValueX() >= mDoubleClickScale)    {     matrix.postScale(mDoubleClickScale/getMatrixValueX(), mDoubleClickScale/getMatrixValueX(), x, y);     checkBorderAndCenterWhenScale();     setImageMatrix(matrix);     return;    }   }  }); } /**  * 判斷縮放級別是否是改變過  *  * @return true表示非初始值, false表示初始值  */ private boolean isZoomChanged() {  float[] values = new float[9];  getImageMatrix().getValues(values);  //獲取當前X軸縮放級別  float scale = values[Matrix.MSCALE_X];  //獲取模板的X軸縮放級別,兩者做比較  oldMatrix.getValues(values);  return scale != values[Matrix.MSCALE_X]; } /**  * 重置Matrix  */ private void reSetMatrix() {  if (checkRestScale()) {   matrix.set(oldMatrix);   setImageMatrix(matrix);   return;  } } /**  * 設置雙擊放大的倍數  */ private void setDoubleClickScale(RectF rectF) {  if(rectF.height()<getHeight()-100)  {   mDoubleClickScale=getHeight()/rectF.height();  }  else   mDoubleClickScale=2f; } /**  * 判斷是否需要重置  *  * @return 當前縮放級別小于模板縮放級別時,重置  */ private boolean checkRestScale() {  // TODO Auto-generated method stub  float[] values = new float[9];  getImageMatrix().getValues(values);  //獲取當前X軸縮放級別  float scale = values[Matrix.MSCALE_X];  //獲取模板的X軸縮放級別,兩者做比較  oldMatrix.getValues(values);  return scale < values[Matrix.MSCALE_X]; } private float getMatrixValueX() {  // TODO Auto-generated method stub  float[] values = new float[9];  getImageMatrix().getValues(values);  //獲取當前X軸縮放級別  float scale = values[Matrix.MSCALE_X];  //獲取模板的X軸縮放級別,兩者做比較  oldMatrix.getValues(values);  return scale / values[Matrix.MSCALE_X]; } /**  * 在縮放時,進行圖片顯示范圍的控制  */ private void checkBorderAndCenterWhenScale() {  RectF rect = getMatrixRectF();  float deltaX = 0;  float deltaY = 0;  int width = getWidth();  int height = getHeight();  // 如果寬或高大于屏幕,則控制范圍  if (rect.width() >= width)  {   if (rect.left > 0)   {    deltaX = -rect.left;   }   if (rect.right < width)   {    deltaX = width - rect.right;   }  }  if (rect.height() >= height)  {   if (rect.top > 0)   {    deltaY = -rect.top;   }   if (rect.bottom < height)   {    deltaY = height - rect.bottom;   }  }  // 如果寬或高小于屏幕,則讓其居中  if (rect.width() < width)  {   deltaX = width * 0.5f - rect.right + 0.5f * rect.width();  }  if (rect.height() < height)  {   deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height();  }  Log.e("TAG", "deltaX = " + deltaX + " , deltaY = " + deltaY);  matrix.postTranslate(deltaX, deltaY);  setImageMatrix(matrix); } /**  * 根據當前圖片的Matrix獲得圖片的范圍  *  * @return  */ private RectF getMatrixRectF() {  RectF rect = new RectF();  Drawable d = getDrawable();  if (null != d)  {   rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());   matrix.mapRect(rect); //如果沒有這個,那么下面Log的輸出將會與上一句的一樣。  }  Log.e("aaaa",""+rect.bottom+" "+rect.left+" "+rect.right+" "+rect.top);  return rect; } @Override public void onGlobalLayout() {  if (once)  {   Drawable d = getDrawable();   if (d == null)    return;   Log.e("TAG", d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight());   int width = getWidth();   int height = getHeight();   // 拿到圖片的寬和高   int dw = d.getIntrinsicWidth();   int dh = d.getIntrinsicHeight();   float scale = 1.0f;   // 如果圖片的寬或者高大于屏幕,則縮放至屏幕的寬或者高   if (dw > width && dh <= height)   {    scale = width * 1.0f / dw;   }   if (dh > height && dw <= width)   {    scale = height * 1.0f / dh;   }   // 如果寬和高都大于屏幕,則讓其按按比例適應屏幕大小   if (dw > width && dh > height)   {    scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);   }   initScale = scale;   Log.e("TAG", "initScale = " + initScale);   matrix.postTranslate((width - dw) / 2, (height - dh) / 2);   matrix.postScale(scale, scale, getWidth() / 2,     getHeight() / 2);   // 圖片移動至屏幕中心   setImageMatrix(matrix);   oldMatrix.set(getImageMatrix());   once = false;   RectF rectF=getMatrixRectF();   setDoubleClickScale(rectF);  } }}

唉,雖然已經寫完了,但是還有一個問題沒有解決,就是移動圖片到盡頭,這時候不要放手,往反方向移動,就會出現一個問題,圖片反方向的部分被遮擋,無法看到,然后移動的時候是直接切換圖片,而不再繼續移動圖片,這個問題的原因是:當你移動圖片到盡頭時,就把事件交給viewpager來處理了,即使再往反方向移動圖片,viewPager也一樣繼續攔截了事件。目前沒解決。

以上所述是小編給大家介紹的在viewPager中雙指縮放圖片雙擊縮放圖片單指拖拽圖片的實現思路,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VEVB武林網網站的支持!


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 福州市| 晋州市| 三江| 徐水县| 阳新县| 定边县| 嵊州市| 隆回县| 永济市| 万年县| 华安县| 沅陵县| 长子县| 马山县| 维西| 潮安县| 贵溪市| 广灵县| 治县。| 衡水市| 南雄市| 天等县| 综艺| 淮滨县| 武穴市| 宜宾县| 内丘县| 英山县| 怀宁县| 上饶市| 阳城县| 台山市| 桐庐县| 西乌珠穆沁旗| 兰溪市| 秀山| 江安县| 永仁县| 托克逊县| 苏尼特右旗| 大安市|