【问题标题】:View Pager + ImageView +Pinch Zoom + RotationView Pager + ImageView +Pinch Zoom + Rotation
【发布时间】:2014-01-23 11:52:26
【问题描述】:

我想在 Imageview 上实现 Pinch Zoom,在 View Pager 中类似于 Default Android Gallery。我在 GitHub 上找到了多个来源,但缩放和滑动仅适用于第一张图片。

我尝试过的:

1.) TouchImageView

2.) PhotoView

3.) Android Touch Gallery

以上所有链接都适用于单个图像视图。但是当涉及到 View 寻呼机中的图像时,它们会出现一些故障,并且仅适用于 View Pager 中的第一张图像。当我们在视图寻呼机中滚动到第 3 个第 4 个图像时,如果图像被缩放,则拖动功能无法按预期工作。

如果有人知道这样做的好图书馆,请给我他们的链接。

【问题讨论】:

    标签: android imageview android-viewpager pinchzoom


    【解决方案1】:

    编辑 2:示例代码已推送到 TouchImageView 的主分支。这是link to the example activitylink to the ExtendedViewPager


    编辑:添加了将示例链接适配到 TouchImageView 的代码。注意:您将需要最新的代码,该代码当前位于 dev 分支中。将来,这将包含在 v1.2.0 中。如果 TouchImageView 覆盖 canScrollHorizo​​ntally,你知道你有最新的代码。

    第 1 步:扩展 ViewPager 并覆盖 canScroll 以调用 canScrollHorizo​​ntallyFroyo。

    public class ExtendedViewPager extends ViewPager {
    
    public ExtendedViewPager(Context context) {
        super(context);
    }
    
    public ExtendedViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    @Override
    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
        if (v instanceof TouchImageView) {
            return ((TouchImageView) v).canScrollHorizontallyFroyo(-dx);
        } else {
            return super.canScroll(v, checkV, dx, x, y);
        }
    }
    
    }
    

    第二步:修改TouchImageView,添加canScrollHorizo​​ntallyFroyo:

    public boolean canScrollHorizontallyFroyo(int direction) {
        return canScrollHorizontally(direction);
    }
    

    第 3 步:您的活动

    public class TouchImageViewActivity extends Activity {
    
    @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            ExtendedViewPager mViewPager = (ExtendedViewPager) findViewById(R.id.view_pager);
            setContentView(mViewPager);
            mViewPager.setAdapter(new TouchImageAdapter());
        }
    
        static class TouchImageAdapter extends PagerAdapter {
    
                private static int[] images = { R.drawable.img1, R.drawable.img2, R.drawable.img3 };
    
                @Override
                public int getCount() {
                        return images.length;
                }
    
                @Override
                public View instantiateItem(ViewGroup container, int position) {
                        TouchImageView img = new TouchImageView(container.getContext());
                        img.setImageResource(images[position]);
                        container.addView(img, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
                        return img;
                }
    
                @Override
                public void destroyItem(ViewGroup container, int position, Object object) {
                        container.removeView((View) object);
                }
    
                @Override
                public boolean isViewFromObject(View view, Object object) {
                        return view == object;
                }
    
        }
    }
    

    第四步: main.xml

    <com.example.touch.ExtendedViewPager 
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    

    TouchImageView 实际上是我的项目。我目前在dev branch 中有a fix 用于与ViewPagers 集成,它将在即将发布的版本中推送到master。不幸的是,此修复仅适用于 API 14 及更高版本,因为蜂窝和更早版本不调用 canScrollHorizontally。如果您需要支持较旧的 API,则需要在 ViewPager 中实施解决方法。 Here is an example.

    【讨论】:

    • 该解决方法对我不起作用..:(。如果我以更高的速度滚动它会将我移动到下一张幻灯片。
    • @AvtarGuleria 我的编辑帮助中是否包含其他解决方法?我知道我过去曾成功使用过它。
    • 否 第二个解决方法对我也不起作用。每当我水平滚动时,它只会将我移动到第二张幻灯片。但是,如果我垂直滚动或以水平以外的其他角度滚动它可以工作..所以,再次水平它不起作用...
    • 我正在尝试使用 canScrollHorizo​​ntally() 或答案中最后一个链接中的解决方案来实施您的解决方案,但它不起作用。 ViewPager 在水平滚动时总是移动到下一页。
    • 有人可以帮我如何使用此代码,以便我可以在 Pager 中显示多个图像,并使用按钮(已经可以使用)放大和缩小功能,但唯一的问题是使用 ViewPager谁能提供我最新的代码
    【解决方案2】:

    我用ImageViewZoom 库找到了很好的解决方案。 为了在 ViewPager 中滚动缩放图像,我创建了自己的 ViewPager:

    public class ExtendedViewPager extends ViewPager {
    
        public ExtendedViewPager(Context context) {
            super(context);
        }
    
        public ExtendedViewPager(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
            if (v instanceof ImageViewTouch) {
                return ((ImageViewTouch) v).canScroll(dx);
            } else {
                return super.canScroll(v, checkV, dx, x, y);
            }
        }
    }
    

    查看更多https://gist.github.com/atermenji/3781644

    【讨论】:

    • 在缩放和滑动视图寻呼机到下一个图像后,如果我滑动回上一个图像,该图像不会出现在原始位置
    • ViewPager 不会从内存中销毁以前的图像,因此当您向后移动时,ViewPager 只会显示具有已保存状态的对象。为了重置缩放,您可以使用 ImageViewTouch 的方法 resetDisplay 或任何其他适合您的方法。
    • 是的,我使用了@Master,但没有用。 stackoverflow.com/questions/25760505/…
    【解决方案3】:

    在对上述解决方案进行了几个小时的测试后,我终于找到了很棒的 Subsampling Scale Image View 库,它甚至可以与 Android 支持包中的标准 ViewPager 一起使用。

    【讨论】:

      【解决方案4】:

      我使用ImageViewZoom Library 的解决方案基于此自定义 ViewPager:

      public class ImageViewTouchViewPager extends ViewPager {
      
          public ImageViewTouchViewPager(Context context) {
              super(context);
          }
      
          public ImageViewTouchViewPager(Context context, AttributeSet attrs) {
              super(context, attrs);
          }
      
          @Override
          protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
              if (v instanceof ImageViewTouch) {
                  ImageViewTouch imageViewTouch = (ImageViewTouch)v;
                  if (imageViewTouch.getScale() == imageViewTouch.getMinScale()) {
                      return super.canScroll(v, checkV, dx, x, y);
                  }
                  return imageViewTouchCanScroll(imageViewTouch, dx);
              } else {
                  return super.canScroll(v, checkV, dx, x, y);
              }
          }
      
      
          /**
           * Determines whether the ImageViewTouch can be scrolled.
           *
           * @param direction - positive direction value means scroll from right to left,
           *                  negative value means scroll from left to right
           * @return true if there is some more place to scroll, false - otherwise.
           */
          private boolean imageViewTouchCanScroll(ImageViewTouch v, int direction){
              RectF bitmapRect = v.getBitmapRect();
              Rect imageViewRect = new Rect();
              getGlobalVisibleRect(imageViewRect);
      
              if (null == bitmapRect) {
                  return false;
              }
      
              if (direction < 0) {
                  return Math.abs(bitmapRect.right - imageViewRect.right) > 1.0f;
              }else {
                  return Math.abs(bitmapRect.left - imageViewRect.left) > 1.0f;
              }
      
          }
      }
      

      【讨论】:

        【解决方案5】:

        我更正了之前的解决方案。当 ImageViewTouch 为缩放模式时,您可以滚动页面。

        public class ImageViewTouchViewPager extends ViewPager {
        
        public ImageViewTouchViewPager(Context context) {
            super(context);
        }
        
        public ImageViewTouchViewPager(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
        
        @Override
        protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
            if (v instanceof ImageViewTouch) {
                ImageViewTouch imageViewTouch = (ImageViewTouch)v;
                return imageViewTouchCanScroll(imageViewTouch, dx);
            } else {
                return super.canScroll(v, checkV, dx, x, y);
            }
        }
        
        
        /**
         * Determines whether the ImageViewTouch can be scrolled.
         *
         * @param direction - positive direction value means scroll from right to left,
         *                  negative value means scroll from left to right
         * @return true if there is some more place to scroll, false - otherwise.
         */
        private boolean imageViewTouchCanScroll(ImageViewTouch imageViewTouch, int direction){
            int widthScreen = getWidthScreen();
        
            RectF bitmapRect = imageViewTouch.getBitmapRect();
            Rect imageViewRect = new Rect();
            getGlobalVisibleRect(imageViewRect);
        
            int widthBitmapViewTouch = (int)bitmapRect.width();
        
            if (null == bitmapRect) {
                return false;
            }
        
            if(widthBitmapViewTouch < widthScreen){
                return false;
            }
        
            if (direction < 0) {
                return Math.abs(bitmapRect.right - imageViewRect.right) > 1.0f;
            }else {
                return Math.abs(bitmapRect.left - imageViewRect.left) > 1.0f;
            }
        
        }
        
        private int getWidthScreen(){
            WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
            Display display = wm.getDefaultDisplay();
        
            Point size = new Point();
            display.getSize(size);
            return size.x;
        }
        

        }

        【讨论】:

          【解决方案6】:

          对于那些在图像处于缩放状态时努力禁用查看器并在图像处于原始状态时启用的人。正如迈克所回答的那样,我刚刚做了一些更改。

          import android.content.Context
          import android.util.AttributeSet
          import android.util.Log
          import android.view.MotionEvent
          import android.view.View
          import android.view.ViewGroup
          import androidx.viewpager.widget.ViewPager
          
          
          class DCExtendedViewPager : ViewPager {
          
          
              private val TAG = DCExtendedViewPager::class.java.simpleName
          
              private var onImageState: OnImageState? = null
          
              private var touchImageViewCustom: DCTouchImageViewLatest? = null
          
          
              var isScroll: Boolean = true
          
              interface OnImageState {
                  fun checkImageState(isImageInOriginalState: Boolean)
              }
          
          
              constructor(context: Context) : super(context)
          
              constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
          
          
              override fun canScroll(view: View, checkV: Boolean, dx: Int, x: Int, y: Int): Boolean {
                  return if (view is DCTouchImageViewLatest) {
                      //   touchImageView=view
                      // canScrollHorizontally is not supported for Api < 14. To get around this issue,
                      // ViewPager is extended and canScrollHorizontallyFroyo, a wrapper around
                      // canScrollHorizontally supporting Api >= 8, is called.
                      Log.e("ExtendedViewPager", "canScroll zoomedRect" + view.zoomedRect)
          
                      view.canScrollHorizontallyFroyo(-dx)
          
                  } else {
                      super.canScroll(view, checkV, dx, x, y)
                  }
              }
          
              override fun onTouchEvent(event: MotionEvent): Boolean {
                  Log.e(TAG, "onTouchEventenable" + isScroll)
                  return if (isScroll) {
                      super.onTouchEvent(event)
                  } else false
          
              }
          
              override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
          
                  Log.e(TAG, "onInterceptTouchEvent")
          
                  Log.e(TAG, "currenrLayoutView called")
                  val currenrLayoutView = getCurrentParentView()
                  getTouchImageViewInstance(currenrLayoutView!!)
          
                  return if (isScroll) {
                      super.onInterceptTouchEvent(event)
                  } else false
          
              }
          
          
              fun isViewPagerScrollValid(): Boolean {
          
                  Log.e(TAG, "getFocusedChild()" + focusedChild)
          
          
                  val currenrLayoutView = getCurrentParentView()
          
          
                  var zoomRect = getTouchImageViewInstance(currenrLayoutView!!)?.zoomedRect
                  var orgzoomRect = getTouchImageViewInstance(currenrLayoutView)?.originalRectF
          
          
                  Log.e(TAG, "onInterceptTouchEvent zoomRect" + zoomRect)
                  Log.e(TAG, "onInterceptTouchEvent orgzoomRect" + orgzoomRect)
                  Log.e(TAG, "onInterceptTouchEvent onImageState" + onImageState)
                  var scrollEnable = (zoomRect == orgzoomRect)
          
          
                  // postLater(getTouchImageViewInstance(currenrLayoutView!!)!!)
          
                  onImageState?.checkImageState(scrollEnable)
                  Log.e(TAG, "onInterceptTouchEvent" + scrollEnable)
          
          
                  return scrollEnable
          
              }
          
          
              fun setImageStateListner(onImageState: OnImageState) {
                  this.onImageState = onImageState
              }
          
          
              fun getTouchImageViewInstance(accessingView: View): DCTouchImageViewLatest? {
          
          
                  if (touchImageViewCustom == null) {
          
                      try {
                          for (index in 0 until (accessingView as ViewGroup).childCount) {
          
                              var nextChild = accessingView.getChildAt(index)
          
                              Log.e(TAG, "nextChild" + nextChild)
          
                              if (nextChild is ViewGroup) {
                                  getTouchImageViewInstance(nextChild)
                              } else if (nextChild is View) {
                                  if (nextChild is DCTouchImageViewLatest) {
                                      touchImageViewCustom = nextChild
                                      setListner()
                                      break
                                  }
                              }
                          }
          
                      } catch (ex: Exception) {
                          ex.printStackTrace()
                      }
          
          
                  }
          
          
                  Log.e(TAG, "getTouchImageViewInstance" + touchImageViewCustom)
          
                  return touchImageViewCustom
              }
          
              private fun setListner() {
          
                  touchImageViewCustom?.setOnDCTouchImageViewLatestListener(object : DCTouchImageViewLatest.OnDCTouchImageViewLatestListener {
                      override fun onMove() {
                          Log.e(TAG, "onMove Called")
                          isScroll = isViewPagerScrollValid()
                      }
          
                  })
          
              }
          
          
              //Call this method from onPageSelected of viewpager
              fun viewPageChanged() {
                  Log.e(TAG, "viewPageChanged called")
                  touchImageViewCustom = null
              }
          
          
              fun getCurrentParentView(): View? {
                  try {
                      Log.e(TAG, "getCurrentView called")
                      val currentItem = currentItem
                      for (i in 0 until childCount) {
                          val child = getChildAt(i)
                          val layoutParams = child.layoutParams as ViewPager.LayoutParams
          
                          val f = layoutParams.javaClass.getDeclaredField("position") //NoSuchFieldException
                          f.isAccessible = true
                          val position = f.get(layoutParams) as Int //IllegalAccessException
          
                          Log.e(TAG, "currentItem" + currentItem)
          
                          if (!layoutParams.isDecor && currentItem == position) {
                              Log.e(TAG, "getCurrentView" + child)
                              return child
                          }
                      }
                  } catch (e: NoSuchFieldException) {
                      Log.e(TAG, e.toString())
                  } catch (e: IllegalArgumentException) {
                      Log.e(TAG, e.toString())
                  } catch (e: IllegalAccessException) {
                      Log.e(TAG, e.toString())
                  }
          
                  return null
              }
          
          
          }
          

          在 TouchImageView 类中,从 setImageBitmap、setImageDrawable 和 setImageURI 调用 getOriginalRectF()。

           public RectF getOriginalRectF(){
          
                  Log.e(TAG,"getOriginalRectF called viewWidth"+viewWidth);
                  Log.e(TAG,"getOriginalRectF called viewHeight"+viewHeight);
          
                  if(originalRectF==null && viewHeight>0 && viewWidth>0){
                      if (mScaleType == ScaleType.FIT_XY) {
                          throw new UnsupportedOperationException("getZoomedRect() not supported with FIT_XY");
                      }
                      PointF topLeft = transformCoordTouchToBitmap(0, 0, true);
                      PointF bottomRight = transformCoordTouchToBitmap(viewWidth, viewHeight, true);
          
                      float w = getDrawableWidth(getDrawable());
                      float h = getDrawableHeight(getDrawable());
          
          
                      Log.e(TAG,"getOriginalRectF height"+h);
                      Log.e(TAG,"getOriginalRectF width"+w);
          
                      Log.e("getOriginalRectF","getZoomedRect topLeft"+topLeft.x +"-"+topLeft.y);
                      Log.e("getOriginalRectF","getZoomedRect bottomRight"+bottomRight.x +"-"+bottomRight.y);
          
          
                      originalRectF=new  RectF(topLeft.x / w, topLeft.y / h, bottomRight.x / w, bottomRight.y / h);
          
          
                  }
          
          
                  return originalRectF;
          
              }
          

          【讨论】:

            【解决方案7】:

            上述任何解决方案都不适合我。当我使用以下 ImageView 时,它对我有用:

            import android.animation.ValueAnimator;
            import android.annotation.SuppressLint;
            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;
            
            @SuppressLint("AppCompatCustomView")
            public class TouchImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener,View.OnTouchListener {
                private final static int SINGLE_TOUCH = 1; //Single point
                private final static int DOUBLE_TOUCH = 2; //Double finger
            
                //Multi-finger touch mode, single finger, double finger
                private int mode;
            
                //Distance between two finger touch points
                private float oldDist;
                private float newDist;
            
                /**
                 * Maximum zoom level
                 */
                private static final float MAX_SCALE = 5f;
                /**
                 * Double-click the zoom level
                 */
                private  float mDoubleClickScale = 2;
            
            
                /**
                 * Scales when initialization, if the picture is wide or higher than the screen, this value will be less than 0
                 */
                private float initScale = 1.0f;
                private boolean once = true;
                private RectF rectF;
            
                /**
                 * Double-click detection
                 */
                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 TouchImageView(Context context) {
                    this(context, null);
                }
            
                public TouchImageView(Context context, AttributeSet attrs) {
                    super(context, attrs);
                    super.setScaleType(ScaleType.MATRIX);
                    setOnTouchListener(this);
                    /**
                     * Double click to implement the picture to zoom
                     */
                    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(); //Get image boundaries
                    if (mGestureDetector.onTouchEvent(event))
                        return true;
            
                    switch (event.getAction() & event.getActionMasked()) {
                        case MotionEvent.ACTION_DOWN:
                            //If the boundary of the picture is overstelled, then intercept the event, not letting ViewPager processing
                            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) //Double finger zoom
                            {
                                getParent().requestDisallowInterceptTouchEvent(true);
                                newDist = calculateDist(event); //Calculate distance
                                Point point = getMiPoint(event); //Get the midpoint coordinates between the two-hand fingers
                                if (newDist > oldDist + 1) //Pixabay (add one to prevent jitter)
                                {
                                    changeViewSize(oldDist, newDist, point); //Enlarge reduction according to distance
                                    oldDist = newDist;
                                }
                                if (oldDist > newDist + 1) //Narrow
                                {
                                    changeViewSize(oldDist, newDist, point);
                                    oldDist = newDist;
                                }
                            }
                            if (mode == SINGLE_TOUCH) //Drag and drop
                            {
                                float dx = event.getRawX() - x;
                                float dy = event.getRawY() - y;
            
                                //If the boundary of the picture in the movement exceeds the screen, then intercept the event, do not let ViewPager processing
                                if (rectF.width() > getWidth() || rectF.height() > getHeight()) {
                                    getParent().requestDisallowInterceptTouchEvent(true);
                                }
                                //If you move the picture to the right, don't intercept the event, let the ViewPager process
                                if (rectF.left >= 0 && dx > 0)
                                    getParent().requestDisallowInterceptTouchEvent(false);
            
                                //If you move to the left, don't intercept the event, let ViewPager processing
                                if (rectF.right <= getWidth() && dx < 0)
                                    getParent().requestDisallowInterceptTouchEvent(false);
            
                                if (getDrawable() != null) {
                                    //If the image width or height does not exceed the screen, then it is forbidden to slide around or down.
                                    if (rectF.width() <= getWidth())
                                        dx = 0;
                                    if (rectF.height() < getHeight())
                                        dy = 0;
            
                                    //If the picture moves down to the end, don't let it continue to move
                                    if (rectF.top >= 0 && dy > 0)
                                        dy = 0;
                                    //If the picture moves up to the end, don't let it continue to move
                                    if (rectF.bottom <= getHeight() && dy < 0)
                                        dy = 0;
            
                                    //When the movement distance is greater than 1, it moves because Action_Move is relatively sensitive.
                                    //  The finger can only detect the jitter of the finger and let the picture 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;
                        //In Action_Move, the event is intercepted, sometimes Action_up can't trigger, so add Action_Cancel
                        case MotionEvent.ACTION_CANCEL:
                            backToPosition();
                            mode = 0;
                            break;
                        default:
                            break;
                    }
                    return true;
                }
            
                /**
                 * Calculate the distance between two finger touch points
                 */
                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);
                }
            
                /**
                 * If it is separated from the screen boundary, then the image boundary is combined with the screen boundary.
                 * If the finger moves quickly, the picture will have a blank distance after the picture is stopped, and then the judgment can no longer move,
                 * However, it has appeared before the next judgment can continue to move.
                 * So you need to reset
                 */
                private void backToPosition() {
                    if (rectF.left >= 0) { //Image Left boundary and screen from the screen
                        matrix.postTranslate(-rectF.left, 0);
                        setImageMatrix(matrix);
                    }
                    if (rectF.right <= getWidth()) { //Image Right Boundary and Screen Distance
                        matrix.postTranslate(getWidth() - rectF.right, 0);
                        setImageMatrix(matrix);
                    }
                    if (rectF.top >= 0) { //Image on the image and the screen from the screen
                        matrix.postTranslate(0, -rectF.top);
                        setImageMatrix(matrix);
                    }
                    if (rectF.bottom <= getHeight()) { //Image of the image and the screen
                        matrix.postTranslate(0, getHeight() - rectF.bottom);
                        setImageMatrix(matrix);
                    }
                }
            
            
                /**
                 * Get the zoom in the zoom of double finger zoom
                 *
                 * @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;
                }
            
                /**
                 * Double finger zoom picture
                 */
                private void changeViewSize(float oldDist, float newDist, Point mPoint) {
                    float scale = newDist / oldDist; //scaling ratio
            
                    matrix.postScale(scale, scale, mPoint.x, mPoint.y);
                    checkBorderAndCenterWhenScale();
                    setImageMatrix(matrix);
            
                    //Prevent reduction is less than the initial picture size, need to reset
                    reSetMatrix();
                    //If the zoom has been larger than the target multiple, stop, because it is possible to be exceeded, then directly zoom to the target size
                    if (getMatrixValueX() >= MAX_SCALE)
                    {
                        matrix.postScale(MAX_SCALE/getMatrixValueX(), MAX_SCALE/getMatrixValueX(), x, y);
                        checkBorderAndCenterWhenScale();
                        setImageMatrix(matrix);
                        return;
                    }
                }
            
                /**
                 * Double click to zoom pictures
                 */
                private void changeViewSize(MotionEvent e) {
            
                    //Get double-click coordinates
                    final float x = e.getX();
                    final float y = e.getY();
            
                    //If you are still zooming, you will return directly.
                    if (animator != null && animator.isRunning())
                        return;
            
                    //Judgment is a state in which it is amplified or reduced
                    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);
            
                            /**
                             * Control reduction range
                             * If it is already less than the initial size, then restore to the initial size, then stop
                             */
                            if (checkRestScale()) {
                                matrix.set(oldMatrix);
                                setImageMatrix(matrix);
                                return;
                            }
                            /**
                             * Control the range of amplification
                             * If the magnification of the target is already larger than the target, it is directly in the target magnification.
                             * Then stop
                             */
                            if (getMatrixValueX() >= mDoubleClickScale)
                            {
                                matrix.postScale(mDoubleClickScale/getMatrixValueX(), mDoubleClickScale/getMatrixValueX(), x, y);
                                checkBorderAndCenterWhenScale();
                                setImageMatrix(matrix);
                                return;
                            }
                        }
                    });
                }
            
                /**
                 * Judging whether the zoom level is changed
                 *
                 * @return  TRUE expressed the non-initial value, FALSE indicates the initial value.
                 */
                private boolean isZoomChanged() {
                    float[] values = new float[9];
                    getImageMatrix().getValues(values);
                    //Get the current X-axis scale level
                    float scale = values[Matrix.MSCALE_X];
                    //Get the X-axis scaling level of the template, both
                    oldMatrix.getValues(values);
                    return scale != values[Matrix.MSCALE_X];
                }
            
                /**
                 * Reset Matrix
                 */
                private void reSetMatrix() {
                    if (checkRestScale()) {
                        matrix.set(oldMatrix);
                        setImageMatrix(matrix);
                        return;
                    }
                }
            
                /**
                 * Setup double-click a large multiple
                 */
                private void setDoubleClickScale(RectF rectF)
                {
                    if(rectF.height()<getHeight()-100)
                    {
                        mDoubleClickScale=getHeight()/rectF.height();
                    }
                    else
                        mDoubleClickScale=2f;
                }
            
                /**
                 * Judging whether it needs to be reset
                 *
                 * @return  When the current zoom level is less than the template zoom level, reset
                 */
                private boolean checkRestScale() {
                    // TODO Auto-generated method stub
                    float[] values = new float[9];
                    getImageMatrix().getValues(values);
                    //Get the current X-axis scale level
                    float scale = values[Matrix.MSCALE_X];
                    //Get the X-axis scaling level of the template, both
                    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);
                    //Get the current X-axis scale level
                    float scale = values[Matrix.MSCALE_X];
                    //Get the X-axis scaling level of the template, both
                    oldMatrix.getValues(values);
                    return scale / values[Matrix.MSCALE_X];
                }
                /**
                 * When zooming, perform image display scope control
                 */
                private void checkBorderAndCenterWhenScale()
                {
            
                    RectF rect = getMatrixRectF();
                    float deltaX = 0;
                    float deltaY = 0;
            
                    int width = getWidth();
                    int height = getHeight();
            
                    //  Control range if wide or higher than the screen
                    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 the width or higher is less than the screen, let it hit
                    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);
                }
                /**
                 * Get the range of images according to the Matrix of the current picture
                 *
                 * @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); //If this is not this, the output of the following Log will be the same as the previous sentence.
                    }
                    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();
                        //  Get the width and high of the picture
                        int dw = d.getIntrinsicWidth();
                        int dh = d.getIntrinsicHeight();
                        float scale = 1.0f;
                        // If the image is wide or higher than the screen, zoom to the width or high of the screen.
                        if (dw > width && dh <= height)
                        {
                            scale = width * 1.0f / dw;
                        }
                        if (dh > height && dw <= width)
                        {
                            scale = height * 1.0f / dh;
                        }
                        //  If the width and high are greater than the screen, it will make it adapt to the screen size according to the proportion.
                        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);
                        //  Image Move to the screen center
                        setImageMatrix(matrix);
            
                        oldMatrix.set(getImageMatrix());
                        once = false;
            
                        RectF rectF=getMatrixRectF();
                        setDoubleClickScale(rectF);
            
                    }
                }
            }
            

            另外,我使用了下面的 ExtendedViewPager:

            import android.content.Context;
            import android.util.AttributeSet;
            import android.view.MotionEvent;
            import androidx.viewpager.widget.ViewPager;
            
            public class ExtendedViewPager extends ViewPager {
            
                public ExtendedViewPager(Context context) {
                    super(context);
                }
            
                public ExtendedViewPager(Context context, AttributeSet attrs) {
                    super(context, attrs);
                }
            
                @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;
                }
            
            
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-06-20
              • 1970-01-01
              • 1970-01-01
              • 2015-11-14
              • 2019-11-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多