Android 는 viewPager 에서 두 손가락 으로 그림 크기 를 조정 하고 두 번 클릭 하여 그림 크기 를 조정 합 니 다.

우 리 는 이 문 제 를 이미지 뷰 어 라 고 부 릅 시다.그것 의 주요 기능 은 다음 과 같 습 니 다.
1.그림 크기 조정 을 더 블 클릭 합 니 다.
2.두 손가락 으로 그림 크기 를 조정 합 니 다.
3.한 손가락 으로 그림 을 끌 어 당 긴 다.
이 그림 뷰 어 는 다음 과 같은 기술 을 고려 해 야 합 니 다.
1.그림 크기 조정 을 더 블 클릭:
1.만약 에 그림 의 높이 가 화면의 높이 보다 훨씬 작다 면 그림 을 화면 높이 와 똑 같이 확대 하고 그렇지 않 으 면 특정한 배 수 를 확대 한다.
2.이 배수 에 도 달 했 는 지 여 부 를 어떻게 판단 하여 크기 조정 을 중단 합 니까?
3.판단 이 끝나 고 확대 가 중 단 된 후에 그림 은 이 배수 가 필요 로 하 는 크기 를 초과 할 수 있 습 니 다.어떻게 우리 의 목표 크기 로 돌아 갈 수 있 습 니까?
4.판단 이 끝나 고 축소 가 중 단 된 후에 그림 의 너비 가 화면 너비 보다 작 을 수 있 습 니 다.양쪽 에 공백 을 남 겼 는데 어떻게 원래 의 크기 로 초기 화 할 수 있 습 니까?
두 손가락 크기 조정 그림:
1.두 손가락 크기 를 조정 하고 특정한 배 수 를 확대 하여 정지 합 니 다.
2.이 배수 에 도 달 했 는 지 여 부 를 어떻게 판단 합 니까?
3.확대 가 멈 춘 후에 그림 은 이 배수 에 필요 한 크기 를 초과 하고 우리 의 목표 크기 로 어떻게 돌아 갈 수 있 습 니까?
4.축소 가 멈 춘 후에 그림 의 너비 가 화면 너비 보다 작 을 수도 있 고 양쪽 에 공백 을 남 겼 을 수도 있 습 니 다.어떻게 원래 의 크기 로 초기 화 할 수 있 습 니까?
3.한 손가락 으로 끌 기:
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 를 사용 하기 때문에 먼저 scale Type 을 matrix 로 설정 해 야 합 니 다.
손짓 으로 더 블 클릭 행 위 를 판단 하 다.온 터치 에 넣 는 거 잊 지 마 세 요.

if (mGestureDetector.onTouchEvent(event))
   return true;
단지 와 다 지 터치 제 어 를 판단 하면 onTouch 에서 판단 하고 이벤트.getAction()&MotionEvent.ACTIONMASK 가 판단 한다.

//      ,  ,  
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 의 크기 를 통 해 단지 인지 양지 인지 판단 한다.
하지만 안 드 로 이 드 자신 에 게 bug 가 있다 는 슬 픈 일이 있 습 니 다.테스트 를 통 해 두 손가락 이 그림 을 교환 할 때 프로그램 이 반 짝 거 리 며 이상 이 발생 합 니 다:pointIndex out of range.안 드 로 이 드 자체 버그 입 니 다.개인 적 으로 가장 좋 은 해결 방법 은 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];
 }
checkRestcale()의 코드 는 다음 과 같 습 니 다.현재 크기 조정 단계 가 초기 크기 조정 단계 보다 작은 지 판단 하기 위해 서 입 니 다.

 /**
  *         
  *
  * @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];
 }
checkBorder AndCenter WhenScale()의 코드 는 다음 과 같 습 니 다.그렇지 않 으 면 그림 크기 를 조정 한 후 위치 가 달라 집 니 다.

/**
  *     ,           
  */
 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;
  }
 }
checkRestcale()의 코드 가 위 에 있 습 니 다.oldMatrix 는 최초의 Matrix 입 니 다.
여기 서 아직 끝나 지 않 았 습 니 다.Imageview 의 Scale Type 을 Matrix 로 설정 하면 그림 이 화면 에 맞 게 자동 으로 크기 를 조정 하지 않 고 화면 중간 에 있 지 않 습 니 다.따라서 사용자 정의 ImageView 는 View TreeObserver.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 에서 두 손가락 으로 그림 을 축소 하고 두 손가락 으로 그림 을 축소 하 는 것 은 한 손가락 으로 그림 을 끌 어 당 기 는 실현 방향 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 메 시 지 를 남 겨 주세요.작은 편집자 가 신속하게 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기