关闭

[置顶] viewPager+photoView实现图片轮播和手势缩放功能 支持手势缩放的imageView 如何实现相册左右滑动和手势缩放 如何让图片自适应控件大小 photoView如何使用(上)

标签: 图片手势缩放viewpager和photoViewphotoview的使用imageview相册
1938人阅读 评论(1) 收藏 举报
分类:

       很多朋友都可能遇到这这个问题,实现一个支持手势缩放的图片轮播功能。就像我们的手机相册一样。而且有时候还需要让图片拉伸自动充满全屏。

       图片轮播我们自然而然,想到了viewPager+imageView来实现,但是想要实现手势缩放就遇到了很大的难度,imageView根本不支持缩放。


       那么打造支持手势缩放的imageView那肯定就需要自定义了,网上有很多这样的自定义view我们可以直接拿来用,可以有一个问题就是,这样的自定义imageView很多的手势操作会和ViewPager的手势操作冲突,那么我们怎样来解决这个问题了?


答案:用开源框架photoView

  • 支持单点/多点触摸,即时缩放图片;
  • 支持平滑滚动;
  • 在滑动父控件下能够运行良好;(例如:ViewPager)
  • 当用户的触点改变是可以触发通知
       当和ViewPager嵌套使用的时候,放大缩小会出现一个异常:IllegalArgumentException: pointerIndex out of range.
       这是Android ViewPager的一个BUG
       这里可以更改为HackyViewPager,它是继承的ViewPaer.

下面我们就来一步一步教大家如何使用photoViewHackyViewPager

1.创建一个类PhotoView,然后复制下面代码放到这个类中。

import uk.co.senab.photoview.IPhotoView;
import uk.co.senab.photoview.PhotoViewAttacher;
import uk.co.senab.photoview.PhotoViewAttacher.OnMatrixChangedListener;
import uk.co.senab.photoview.PhotoViewAttacher.OnPhotoTapListener;
import uk.co.senab.photoview.PhotoViewAttacher.OnViewTapListener;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.View.OnLongClickListener;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;

public class PhotoView extends ImageView implements IPhotoView {

    private final PhotoViewAttacher mAttacher;
    private ScaleType mPendingScaleType;

    public PhotoView(Context context) {
        this(context, null);
    }

    public PhotoView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        super.setScaleType(ScaleType.MATRIX);
        mAttacher = new PhotoViewAttacher(this);
        if (null != mPendingScaleType) {
            setScaleType(mPendingScaleType);
            mPendingScaleType = null;
        }
    }

    public PhotoView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @Override
    public boolean canZoom() {
        // TODO Auto-generated method stub
        return mAttacher.canZoom();
    }

    @Override
    public Matrix getDisplayMatrix() {
        // TODO Auto-generated method stub
        return mAttacher.getDrawMatrix();
    }

    @Override
    public RectF getDisplayRect() {
        // TODO Auto-generated method stub
        return mAttacher.getDisplayRect();
    }

    @Override
    public IPhotoView getIPhotoViewImplementation() {
        // TODO Auto-generated method stub
        return mAttacher;
    }

    @Override
    public float getMaxScale() {
        // TODO Auto-generated method stub
        return getMaximumScale();
    }

    @Override
    public float getMaximumScale() {
        // TODO Auto-generated method stub
        return mAttacher.getMaximumScale();
    }

    @Override
    public float getMediumScale() {
        // TODO Auto-generated method stub
        return mAttacher.getMediumScale();
    }

    @Override
    public float getMidScale() {
        // TODO Auto-generated method stub
        return getMediumScale();
    }

    @Override
    public float getMinScale() {
        // TODO Auto-generated method stub
        return getMinimumScale();
    }

    @Override
    public float getMinimumScale() {
        // TODO Auto-generated method stub
        return mAttacher.getMinimumScale();
    }

    @Override
    public OnPhotoTapListener getOnPhotoTapListener() {
        // TODO Auto-generated method stub
        return mAttacher.getOnPhotoTapListener();
    }

    @Override
    public OnViewTapListener getOnViewTapListener() {
        // TODO Auto-generated method stub
        return mAttacher.getOnViewTapListener();
    }

    @Override
    public float getScale() {
        // TODO Auto-generated method stub
        return mAttacher.getScale();
    }

    @Override
    public Bitmap getVisibleRectangleBitmap() {
        // TODO Auto-generated method stub
        return mAttacher.getVisibleRectangleBitmap();
    }

    @Override
    public void setAllowParentInterceptOnEdge(boolean allow) {
        // TODO Auto-generated method stub
        mAttacher.setAllowParentInterceptOnEdge(allow);
    }

    @Override
    public boolean setDisplayMatrix(Matrix finalMatrix) {
        // TODO Auto-generated method stub
        return mAttacher.setDisplayMatrix(finalMatrix);
    }

    @Override
    public void setMaxScale(float maxScale) {
        // TODO Auto-generated method stub
        mAttacher.setMaxScale(maxScale);
    }

    @Override
    public void setMaximumScale(float maximumScale) {
        // TODO Auto-generated method stub
        mAttacher.setMaximumScale(maximumScale);
    }

    @Override
    public void setMediumScale(float mediumScale) {
        // TODO Auto-generated method stub
        mAttacher.setMediumScale(mediumScale);
    }

    @Override
    public void setMidScale(float midScale) {
        // TODO Auto-generated method stub
        mAttacher.setMidScale(midScale);
    }

    @Override
    public void setMinScale(float minScale) {
        // TODO Auto-generated method stub
        mAttacher.setMinScale(minScale);
    }

    @Override
    public void setMinimumScale(float minimumScale) {
        // TODO Auto-generated method stub
        mAttacher.setMinimumScale(minimumScale);
    }

    @Override
    public void setImageResource(int resId) {
        // TODO Auto-generated method stub
        super.setImageResource(resId);
        if (null != mAttacher) {
            mAttacher.update();
        }
    }

    @Override
    public void setImageURI(Uri uri) {
        // TODO Auto-generated method stub
        super.setImageURI(uri);
        if (null != mAttacher) {
            mAttacher.update();
        }
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        // TODO Auto-generated method stub
        super.setImageDrawable(drawable);
        if(null !=mAttacher){
            mAttacher.update();
        }
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        // TODO Auto-generated method stub
        super.setImageBitmap(bm);
        if(null !=mAttacher){
            mAttacher.update();
        }
    }

    @Override
    public void setOnDoubleTapListener(
            OnDoubleTapListener newOnDoubleTapListener) {
        // TODO Auto-generated method stub
        mAttacher.setOnDoubleTapListener(newOnDoubleTapListener);
    }

    @Override
    public void setOnMatrixChangeListener(OnMatrixChangedListener listener) {
        // TODO Auto-generated method stub
        mAttacher.setOnMatrixChangeListener(listener);
    }

    @Override
    public void setOnPhotoTapListener(OnPhotoTapListener listener) {
        // TODO Auto-generated method stub
        mAttacher.setOnPhotoTapListener(listener);
    }

    @Override
    public void setOnLongClickListener(OnLongClickListener listener) {
        // TODO Auto-generated method stub
        mAttacher.setOnLongClickListener(listener);
    }

    @Override
    public void setOnViewTapListener(OnViewTapListener listener) {
        // TODO Auto-generated method stub
        mAttacher.setOnViewTapListener(listener);
    }

    @Override
    public void setPhotoViewRotation(float rotationDegrees) {
        // TODO Auto-generated method stub
        mAttacher.setRotationTo(rotationDegrees);
    }

    @Override
    public void setRotationBy(float rotationDegrees) {
        // TODO Auto-generated method stub
        mAttacher.setRotationBy(rotationDegrees);
    }

    @Override
    public void setRotationTo(float rotationDegrees) {
        // TODO Auto-generated method stub
        mAttacher.setRotationTo(rotationDegrees);
    }

    @Override
    public void setScale(float scale) {
        // TODO Auto-generated method stub
        mAttacher.setScale(scale);
    }

    @Override
    public void setScale(float scale, boolean animate) {
        // TODO Auto-generated method stub
        mAttacher.setScale(scale, animate);
    }

    @Override
    public void setScale(float scale, float focalX, float focalY,
            boolean animate) {
        // TODO Auto-generated method stub
        mAttacher.setScale(scale, focalX, focalY, animate);
    }

    @Override
    public void setZoomTransitionDuration(int milliseconds) {
        // TODO Auto-generated method stub
        mAttacher.setZoomTransitionDuration(milliseconds);
    }

    @Override
    public void setScaleType(ScaleType scaleType) {
        if (null != mAttacher) {
            mAttacher.setScaleType(scaleType);
        } else {
            mPendingScaleType = scaleType;
        }
    }

    @Override
    public void setZoomable(boolean zoomable) {
        // TODO Auto-generated method stub
        mAttacher.setZoomable(zoomable);
    }

    @Override
    protected void onDetachedFromWindow() {
        // TODO Auto-generated method stub
        mAttacher.cleanup();
        super.onDetachedFromWindow();
    }

}


2.创建类HackyViewPager,将下面代码复制进去

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

/**
 * Hacky fix for Issue #4 and
 * http://code.google.com/p/android/issues/detail?id=18990
 * 
 * ScaleGestureDetector seems to mess up the touch events, which means that
 * ViewGroups which make use of onInterceptTouchEvent throw a lot of
 * IllegalArgumentException: pointerIndex out of range.
 * 
 * There's not much I can do in my code for now, but we can mask the result by
 * just catching the problem and ignoring it.
 * 
 * @author Chris Banes
 */
/**
 * 自定义viewPager解决和photoView滑动的冲突事件
 * @author Administrator
 *
 */
public class HackyViewPager extends ViewPager {

	public HackyViewPager(Context context) {
		super(context);
	}

	public HackyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

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

}

   3.在显示界面的布局文件中添加一个自定义的HackyViewPager


  <com.xixiangfu.photoview.HackyViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

4.在activity中写代码,创建一个数据源,我这里用的是本地图片,放在drawable文件夹,建立了一个数组,将图片Id添加进去。
private int[] photoId = { R.drawable.kejiqianyan_02, R.drawable.chezai_01,R.drawable.shumadianzi_02 }

5.初始化自定义的HackyViewPager,然后给其设置PagerAdapter适配器。在onCreate中给viewPager设置adapter.如下
   viewPager = (ViewPager) findViewById(R.id.viewPager);

   这个适配器需要自定义,所有photoView的创建和图片设置都在这里完成操作,具体见代码。
   而且要特别注意是,一定要重写1.  instantiateItem()方法,2.  destroyItem()方法 3. isViewFromObject()方法。
   其中方法2和3的写法一般是固定的,按照下面代码中的写就可以了,方法1的话可以按照下面代码里的写,就可以实现图片的正常展示了。    如果还需要设置图片的属性的话,可以在这里直接设置,和imageView的属性是一样的。

     例如需要让图片拉伸充满全屏,photoView.setScaleType(ScaleType.FIT_XY);  //设置充满全屏

<pre name="code" class="java">/**
	 * 自定义pagerAdapter
	 */
	public class MyAdapter extends PagerAdapter {

		@Override
		public int getCount() {
			return photoId.length;
		}
		  @Override
	        public View instantiateItem(ViewGroup container, int position) {
	            PhotoView photoView = new PhotoView(container.getContext());
	            container.addView(photoView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
	            photoView.setImageResource(photoId[position]);
	            photoView.setScaleType(ScaleType.FIT_XY);//设置图片显示为充满全屏
	            return photoView;
	        }

	        @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;
	        }
	}



然后就可以运行这个程序了,效果很不错,但是还有一个问题,当前图片放大后,滑动到下一页,滑回来之后,当前页面的图片还是处于放大状态,没有恢复默认大小,这样用户体验非常不好,下一篇文章我会给出解决方法。


这里是eclipse使用的photoView的jar包下载地址
http://download.csdn.net/detail/beibaokongming/9540545

2
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:25177次
    • 积分:598
    • 等级:
    • 排名:千里之外
    • 原创:31篇
    • 转载:4篇
    • 译文:0篇
    • 评论:8条
    微信公众号
      微信公众号:beibaokekongming
      ====旅行·赚钱==== ====轻松·快乐====
    打赏是一种至高无上的荣誉
      如果对你有用,请打赏一杯咖啡
    最新评论