[置顶] viewPager+photoView实现图片轮播和手势缩放功能 支持手势缩放的imageView 如何实现相册左右滑动和手势缩放 如何让图片自适应控件大小 photoView如何使用(上)
2016-06-01 21:38
1051 查看
很多朋友都可能遇到这这个问题,实现一个支持手势缩放的图片轮播功能。就像我们的手机相册一样。而且有时候还需要让图片拉伸自动充满全屏。
图片轮播我们自然而然,想到了viewPager+imageView来实现,但是想要实现手势缩放就遇到了很大的难度,imageView根本不支持缩放。
那么打造支持手势缩放的imageView那肯定就需要自定义了,网上有很多这样的自定义view我们可以直接拿来用,可以有一个问题就是,这样的自定义imageView很多的手势操作会和ViewPager的手势操作冲突,那么我们怎样来解决这个问题了?
答案:用开源框架photoView
支持单点/多点触摸,即时缩放图片;
支持平滑滚动;
在滑动父控件下能够运行良好;(例如:ViewPager)
当用户的触点改变是可以触发通知
当和ViewPager嵌套使用的时候,放大缩小会出现一个异常:IllegalArgumentException: pointerIndex out of range.
这是Android ViewPager的一个BUG
这里可以更改为HackyViewPager,它是继承的ViewPaer.
下面我们就来一步一步教大家如何使用photoView和HackyViewPager。
1.创建一个类PhotoView,然后复制下面代码放到这个类中。
2.创建类HackyViewPager,将下面代码复制进去
3.在显示界面的布局文件中添加一个自定义的HackyViewPager
4.在activity中写代码,创建一个数据源,我这里用的是本地图片,放在drawable文件夹,建立了一个数组,将图片Id添加进去。
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); //设置充满全屏
然后就可以运行这个程序了,效果很不错,但是还有一个问题,当前图片放大后,滑动到下一页,滑回来之后,当前页面的图片还是处于放大状态,没有恢复默认大小,这样用户体验非常不好,下一篇文章我会给出解决方法。
这里是eclipse使用的photoView的jar包下载地址
http://download.csdn.net/detail/beibaokongming/9540545
图片轮播我们自然而然,想到了viewPager+imageView来实现,但是想要实现手势缩放就遇到了很大的难度,imageView根本不支持缩放。
那么打造支持手势缩放的imageView那肯定就需要自定义了,网上有很多这样的自定义view我们可以直接拿来用,可以有一个问题就是,这样的自定义imageView很多的手势操作会和ViewPager的手势操作冲突,那么我们怎样来解决这个问题了?
答案:用开源框架photoView
支持单点/多点触摸,即时缩放图片;
支持平滑滚动;
在滑动父控件下能够运行良好;(例如:ViewPager)
当用户的触点改变是可以触发通知
当和ViewPager嵌套使用的时候,放大缩小会出现一个异常:IllegalArgumentException: pointerIndex out of range.
这是Android ViewPager的一个BUG
这里可以更改为HackyViewPager,它是继承的ViewPaer.
下面我们就来一步一步教大家如何使用photoView和HackyViewPager。
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
相关文章推荐
- Poj1745 Divisibility
- 阿里云ECS—访问
- Imageloader配置和设置圆形
- 第二阶段个人冲刺07
- oracle查询多个字段其中一个字段去重
- mapreduce采用多进程与spark采用多线程比较
- centos6.5上NFS服务器搭建
- 手机开发实战50——CALL介绍
- Bathy2010 3.5k 水箱装配图(1)----零件列表图
- POJ 2485-Highways(最小生成树裸题-prim/kruskal)
- Spark 1.6.1 单机安装配置
- 工作两年的编程感想
- 第二阶段--团队冲刺--第十天
- 【bzoj3527】[Zjoi2014]力 FFT
- hdu5672 string(尺取法)
- 编译原理之后缀表达式生成与计算(2)
- 定位 -- 百度地图SDK
- Javascript对象定义的几种方式
- 最全面的 Android 编码规范指南
- nrm —— 快速切换 NPM 源