自定义viewpager与自定义imageview实现图片显示

自定义放大缩小imageview


import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;

/**
 * @ClassName: MatrixImageView
 * @Description:  带放大、缩小、移动效果的ImageView
 *
 */
public class MatrixImageView extends ImageView{
   public final static String TAG="MatrixImageView";
   private GestureDetector mGestureDetector;
   /**  模板Matrix,用以初始化 */
   private  Matrix mMatrix=new Matrix();
   /**  图片长度*/
   private float mImageWidth;
   /**  图片高度 */
   private float mImageHeight;
   /**  原始缩放级别 */
   private float mScale
         ;
   private OnMovingListener moveListener;
   private OnSingleTapListener singleTapListener;

   public MatrixImageView(Context context, AttributeSet attrs) {
      super(context, attrs);
      MatrixTouchListener mListener=new MatrixTouchListener();
      setOnTouchListener(mListener);
      mGestureDetector=new GestureDetector(getContext(), new GestureListener(mListener));
      //背景设置为balck
      setBackgroundColor(Color.BLACK);
      //将缩放类型设置为CENTER_INSIDE,表示把图片居中显示,并且宽高最大值为控件宽高
      setScaleType(ScaleType.FIT_CENTER);
   }
   public MatrixImageView(Context context) {
      super(context, null);
      MatrixTouchListener mListener=new MatrixTouchListener();
      setOnTouchListener(mListener);
      mGestureDetector=new GestureDetector(getContext(), new GestureListener(mListener));
      //背景设置为balck
      setBackgroundColor(Color.BLACK);
      //将缩放类型设置为CENTER_INSIDE,表示把图片居中显示,并且宽高最大值为控件宽高
      setScaleType(ScaleType.FIT_CENTER);
   }
   public void setOnMovingListener(OnMovingListener listener){
      moveListener=listener;
   }
   public void setOnSingleTapListener(OnSingleTapListener onSingleTapListener) {
      this.singleTapListener = onSingleTapListener;
   }
   @Override
   public void setImageBitmap(Bitmap bm) {
      // TODO Auto-generated method stub
      super.setImageBitmap(bm);
      //大小为0 表示当前控件大小未测量  设置监听函数  在绘制前赋值
      if(getWidth()==0){
         ViewTreeObserver vto = getViewTreeObserver();
         vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
         {
            public boolean onPreDraw()
            {
               initData();
               //赋值结束后,移除该监听函数
               MatrixImageView.this.getViewTreeObserver().removeOnPreDrawListener(this);
               return true;
            }
         });
      }else {
         initData();
      }
   }

   /**
    *   初始化模板Matrix和图片的其他数据
    */
   private void initData() {
      //设置完图片后,获取该图片的坐标变换矩阵
      mMatrix.set(getImageMatrix());
      float[] values=new float[9];
      mMatrix.getValues(values);
      //图片宽度为屏幕宽度除缩放倍数
      mImageWidth=getWidth()/values[Matrix.MSCALE_X];
      mImageHeight=(getHeight()-values[Matrix.MTRANS_Y]*2)/values[Matrix.MSCALE_Y];
      mScale=values[Matrix.MSCALE_X];
   }

   public class MatrixTouchListener implements OnTouchListener{
      /** 拖拉照片模式 */
      private static final int MODE_DRAG = 1;
      /** 放大缩小照片模式 */
      private static final int MODE_ZOOM = 2;
      /**  不支持Matrix */
      private static final int MODE_UNABLE=3;
      /**   最大缩放级别*/
      float mMaxScale=6;
      /**   双击时的缩放级别*/
      float mDobleClickScale=2;
      private int mMode = 0;// 
      /**  缩放开始时的手指间距 */
      private float mStartDis;
      /**   当前Matrix*/
      private Matrix mCurrentMatrix = new Matrix();

      /** 用于记录开始时候的坐标位置 */

      /** 和ViewPager交互相关,判断当前是否可以左移、右移  */
      boolean mLeftDragable;
      boolean mRightDragable;
      /**  是否第一次移动 */
      boolean mFirstMove=false;
      private PointF mStartPoint = new PointF();
      @Override
      public boolean onTouch(View v, MotionEvent event) {
         // TODO Auto-generated method stub
         switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
               //设置拖动模式
               mMode=MODE_DRAG;
               mStartPoint.set(event.getX(), event.getY());
               isMatrixEnable();
               startDrag();
               checkDragable();
               break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
               reSetMatrix();
               stopDrag();
               break;
            case MotionEvent.ACTION_MOVE:
               if (mMode == MODE_ZOOM) {
                  setZoomMatrix(event);
               }else if (mMode==MODE_DRAG) {
                  setDragMatrix(event);
               }else {
                  stopDrag();
               }
               break;
            case MotionEvent.ACTION_POINTER_DOWN:
               if(mMode==MODE_UNABLE) return true;
               mMode=MODE_ZOOM;
               mStartDis = distance(event);
               break;
            case MotionEvent.ACTION_POINTER_UP:

               break;
            default:
               break;
         }
         return mGestureDetector.onTouchEvent(event);
      }

      /**
       *   子控件开始进入移动状态,令ViewPager无法拦截对子控件的Touch事件
       */
      private void startDrag(){
         if(moveListener!=null) moveListener.startDrag();

      }
      /**
       *   子控件开始停止移动状态,ViewPager将拦截对子控件的Touch事件
       */
      private void stopDrag(){
         if(moveListener!=null) moveListener.stopDrag();
      }

      /**
       *   根据当前图片左右边缘设置可拖拽状态
       */
      private void checkDragable() {
         mLeftDragable=true;
         mRightDragable=true;
         mFirstMove=true;
         float[] values=new float[9];
         getImageMatrix().getValues(values);
         //图片左边缘离开左边界,表示不可右移
         if(values[Matrix.MTRANS_X]>=0)
            mRightDragable=false;
         //图片右边缘离开右边界,表示不可左移
         if((mImageWidth)*values[Matrix.MSCALE_X]+values[Matrix.MTRANS_X]<=getWidth()){
            mLeftDragable=false;
         }
      }

      /**
       *  设置拖拽状态下的Matrix
       *  @param event
       */
      public void setDragMatrix(MotionEvent event) {
         if(isZoomChanged()){
            float dx = event.getX() - mStartPoint.x; // 得到x轴的移动距离
            float dy = event.getY() - mStartPoint.y; // 得到x轴的移动距离
            //避免和双击冲突,大于10f才算是拖动
            if(Math.sqrt(dx*dx+dy*dy)>10f){
               mStartPoint.set(event.getX(), event.getY());
               //在当前基础上移动
               mCurrentMatrix.set(getImageMatrix());
               float[] values=new float[9];
               mCurrentMatrix.getValues(values);
               dy=checkDyBound(values,dy);
               dx=checkDxBound(values,dx,dy);

               mCurrentMatrix.postTranslate(dx, dy);
               setImageMatrix(mCurrentMatrix);
            }
         }else {
            stopDrag();
         }
      }

      /**
       *  判断缩放级别是否是改变过
       *  @return   true表示非初始值,false表示初始值
       */
      private boolean isZoomChanged() {
         float[] values=new float[9];
         getImageMatrix().getValues(values);
         //获取当前X轴缩放级别
         float scale=values[Matrix.MSCALE_X];
         //获取模板的X轴缩放级别,两者做比较
         return scale!=mScale;
      }

      /**
       *  和当前矩阵对比,检验dy,使图像移动后不会超出ImageView边界
       *  @param values
       *  @param dy
       *  @return
       */
      private float checkDyBound(float[] values, float dy) {
         float height=getHeight();
         if(mImageHeight*values[Matrix.MSCALE_Y]<height)
            return 0;
         if(values[Matrix.MTRANS_Y]+dy>0)
            dy=-values[Matrix.MTRANS_Y];
         else if(values[Matrix.MTRANS_Y]+dy<-(mImageHeight*values[Matrix.MSCALE_Y]-height))
            dy=-(mImageHeight*values[Matrix.MSCALE_Y]-height)-values[Matrix.MTRANS_Y];
         return dy;
      }

      /**
       *  和当前矩阵对比,检验dx,使图像移动后不会超出ImageView边界
       *  @param values
       *  @param dx
       *  @return
       */
      private float checkDxBound(float[] values,float dx,float dy) {
         float width=getWidth();
         if(!mLeftDragable&&dx<0){
            //加入和y轴的对比,表示在监听到垂直方向的手势时不切换Item
            if(Math.abs(dx)*0.4f>Math.abs(dy)&&mFirstMove){
               stopDrag();
            }
            return 0;
         }
         if(!mRightDragable&&dx>0){
            //加入和y轴的对比,表示在监听到垂直方向的手势时不切换Item
            if(Math.abs(dx)*0.4f>Math.abs(dy)&&mFirstMove){
               stopDrag();
            }
            return 0;
         }
         mLeftDragable=true;
         mRightDragable=true;
         if(mFirstMove) mFirstMove=false;
         if(mImageWidth*values[Matrix.MSCALE_X]<width){
            return 0;

         }
         if(values[Matrix.MTRANS_X]+dx>0){
            dx=-values[Matrix.MTRANS_X];
         }
         else if(values[Matrix.MTRANS_X]+dx<-(mImageWidth*values[Matrix.MSCALE_X]-width)){
            dx=-(mImageWidth*values[Matrix.MSCALE_X]-width)-values[Matrix.MTRANS_X];
         }
         return dx;
      }

      /**
       *  设置缩放Matrix
       *  @param event
       */
      private void setZoomMatrix(MotionEvent event) {
         //只有同时触屏两个点的时候才执行
         if(event.getPointerCount()<2) return;
         float endDis = distance(event);// 结束距离
         if (endDis > 10f) { // 两个手指并拢在一起的时候像素大于10
            float scale = endDis / mStartDis;// 得到缩放倍数
            mStartDis=endDis;//重置距离
            mCurrentMatrix.set(getImageMatrix());//初始化Matrix
            float[] values=new float[9];
            mCurrentMatrix.getValues(values);
            scale = checkMaxScale(scale, values);
            PointF centerF=getCenter(scale,values);
            mCurrentMatrix.postScale(scale, scale,centerF.x,centerF.y);
            setImageMatrix(mCurrentMatrix);
         }
      }

      /**
       *  获取缩放的中心点。
       *  @param scale
       *  @param values
       *  @return
       */
      private PointF getCenter(float scale,float[] values) {
         //缩放级别小于原始缩放级别时或者为放大状态时,返回ImageView中心点作为缩放中心点
         if(scale*values[Matrix.MSCALE_X]<mScale||scale>=1){
            return new PointF(getWidth()/2,getHeight()/2);
         }
         float cx=getWidth()/2;
         float cy=getHeight()/2;
         //以ImageView中心点为缩放中心,判断缩放后的图片左边缘是否会离开ImageView左边缘,是的话以左边缘为X轴中心
         if((getWidth()/2-values[Matrix.MTRANS_X])*scale<getWidth()/2)
            cx=0;
         //判断缩放后的右边缘是否会离开ImageView右边缘,是的话以右边缘为X轴中心
         if((mImageWidth*values[Matrix.MSCALE_X]+values[Matrix.MTRANS_X])*scale<getWidth())
            cx=getWidth();
         return new PointF(cx,cy);
      }

      /**
       *  检验scale,使图像缩放后不会超出最大倍数
       *  @param scale
       *  @param values
       *  @return
       */
      private float checkMaxScale(float scale, float[] values) {
         if(scale*values[Matrix.MSCALE_X]>mMaxScale)
            scale=mMaxScale/values[Matrix.MSCALE_X];
         return scale;
      }

      /**
       *   重置Matrix
       */
      private void reSetMatrix() {
         if(checkRest()){
            mCurrentMatrix.set(mMatrix);
            setImageMatrix(mCurrentMatrix);
         }else {
            //判断Y轴是否需要更正
            float[] values=new float[9];
            getImageMatrix().getValues(values);
            float height=mImageHeight*values[Matrix.MSCALE_Y];
            if(height<getHeight()){
               //在图片真实高度小于容器高度时,Y轴居中,Y轴理想偏移量为两者高度差/2,
               float topMargin=(getHeight()-height)/2;
               if(topMargin!=values[Matrix.MTRANS_Y]){
                  mCurrentMatrix.set(getImageMatrix());
                  mCurrentMatrix.postTranslate(0, topMargin-values[Matrix.MTRANS_Y]);
                  setImageMatrix(mCurrentMatrix);
               }
            }
         }
      }

      /**
       *  判断是否需要重置
       *  @return  当前缩放级别小于模板缩放级别时,重置 
       */
      private boolean checkRest() {
         // TODO Auto-generated method stub
         float[] values=new float[9];
         getImageMatrix().getValues(values);
         //获取当前X轴缩放级别
         float scale=values[Matrix.MSCALE_X];
         //获取模板的X轴缩放级别,两者做比较
         return scale<mScale;
      }

      /**
       *  判断是否支持Matrix
       */
      private void isMatrixEnable() {
         //当加载出错时,不可缩放
         if(getScaleType()!=ScaleType.CENTER){
            setScaleType(ScaleType.MATRIX);
         }else {
            mMode=MODE_UNABLE;//设置为不支持手势
         }
      }

      /**
       *  计算两个手指间的距离
       *  @param event
       *  @return
       */
      private float distance(MotionEvent event) {
         float dx = event.getX(1) - event.getX(0);
         float dy = event.getY(1) - event.getY(0);
         /** 使用勾股定理返回两点之间的距离 */
         return (float) Math.sqrt(dx * dx + dy * dy);
      }

      /**
       *   双击时触发
       */
      public void onDoubleClick(){
         float scale=isZoomChanged()?1:mDobleClickScale;
         mCurrentMatrix.set(mMatrix);//初始化Matrix
         mCurrentMatrix.postScale(scale, scale,getWidth()/2,getHeight()/2);
         setImageMatrix(mCurrentMatrix);
      }
   }


   private class  GestureListener extends SimpleOnGestureListener{
      private final MatrixTouchListener listener;
      public GestureListener(MatrixTouchListener listener) {
         this.listener=listener;
      }
      @Override
      public boolean onDown(MotionEvent e) {
         //捕获Down事件
         return true;
      }
      @Override
      public boolean onDoubleTap(MotionEvent e) {
         //触发双击事件
         listener.onDoubleClick();
         return true;
      }
      @Override
      public boolean onSingleTapUp(MotionEvent e) {
         // TODO Auto-generated method stub
         return super.onSingleTapUp(e);
      }

      @Override
      public void onLongPress(MotionEvent e) {
         // TODO Auto-generated method stub
         super.onLongPress(e);
      }

      @Override
      public boolean onScroll(MotionEvent e1, MotionEvent e2,
                        float distanceX, float distanceY) {
         return super.onScroll(e1, e2, distanceX, distanceY);
      }

      @Override
      public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                        float velocityY) {
         return super.onFling(e1, e2, velocityX, velocityY);
      }

      @Override
      public void onShowPress(MotionEvent e) {
         // TODO Auto-generated method stub
         super.onShowPress(e);
      }

      @Override
      public boolean onDoubleTapEvent(MotionEvent e) {
         // TODO Auto-generated method stub
         return super.onDoubleTapEvent(e);
      }

      @Override
      public boolean onSingleTapConfirmed(MotionEvent e) {
         if(singleTapListener!=null) singleTapListener.onSingleTap();
         return super.onSingleTapConfirmed(e);
      }

   }
   /**
    * @ClassName: OnChildMovingListener
    * @Description:  MatrixImageView移动监听接口,用以组织ViewPager对Move操作的拦截
    *
    */
   public interface OnMovingListener{
      public void  startDrag();
      public void  stopDrag();
   }

   /**
    * @ClassName: OnSingleTapListener
    * @Description:  监听ViewPager屏幕单击事件,本质是监听子控件MatrixImageView的单击事件
    *
    */
   public interface OnSingleTapListener{
      public void onSingleTap();
   }


自定义viewpager


import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;


/**
 * @author LinJ
 * @ClassName: AlbumViewPager
 * @Description: 自定义viewpager  优化了事件拦截
 */
public class AlbumViewPager extends ViewPager implements MatrixImageView.OnMovingListener {
    public final static String TAG = "AlbumViewPager";


    /**
     * 当前子控件是否处理拖动状态
     */
    private boolean mChildIsBeingDragged = false;


    public AlbumViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent arg0) {
        if (mChildIsBeingDragged)
            return false;
        return super.onInterceptTouchEvent(arg0);
    }

    @Override
    public void startDrag() {
        mChildIsBeingDragged = true;
    }


    @Override
    public void stopDrag() {
        mChildIsBeingDragged = false;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值