photoView的九宫格全屏展示、结合ViewPager的使用(填坑)
photoView(‘com.github.chrisbanes.photoview:library:1.2.4’)作为github高分的手势操作的ImgView,开发中经常会用到该控件,这里记录一下开发类似好友动态的列表图片展示所遇到的关于photoView的坑;
1,结合九宫格布局全屏展示效果
跳转九宫格布局github点这里
九宫格布局效果还是很不错的,网上大神教学的文章也很完善,因此不多赘述。
这里的九宫格布局只是单纯的九宫格展示,不带有点击放大全屏展示的操作,因此,有大神在九宫格布局之上二次封装了可点击的九宫格控件
compile 'com.lzy.widget:ninegridview:0.2.0'
效果很好很强大,简单的看了一下源码,其实这个九宫格封装只是在原来的九宫格NineGridImageViewAdapter上的onItemImageClick()方法里加了个点击事件,跳转到了作者自己定义好的一个Activity中,用于全屏展示,是个功能比较完善的项目,但是我自己开发用的项目需要一点自己风格的东西,于是,根据这个原理,我也自己写了一个PhotoView+ViewPager的Activity,封装自己的一些需求,但是却遇到一个加一个的坑,再次记录填坑之路。
2,PhotoView+ViewPager
private void initView() {
for (int i = 0; i < mDataList.size(); i++) {
PhotoView view = new PhotoView(this);
view.setScaleType(ImageView.ScaleType.FIT_CENTER);
Glide.with(this).load(GlideUtils.glideUrl(mDataList.get(i))).placeholder(R.drawable.ic_empty).into(view);
mViewList.add(view);
}
initViewPage();
}
private void initViewPage() {
PagerAdapter adapter = new PagerAdapter() {
@Override
public int getCount() {
return mViewList.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
activityPhotoPageViewpager.addView(mViewList.get(position));
return mViewList.get(position);
}
};
activityPhotoPageViewpager.setAdapter(adapter);
if (mPosition >= 0 && mPosition < mViewList.size()) {
activityPhotoPageViewpager.setCurrentItem(mPosition);
}
}
这是一开始的思路,点击进入全屏时,初始化一个ViewPager,然后根据Data的数量,初始化一定个数的PhotoView加载一下图片展示下就可以了,但是问题来了,这个代码运行起来会发现一个小问题,点击进入全屏时没问题了,但是在此点击退出全屏这个,这个需要自己手写,然而发现一个问题,PhotoView 的OnclickListener是不能用的,set之后依旧没效果,而且,测试过在PhotoView外部套一个container布局,使用container布局的点击事件,依旧是没有效果的,后来检索了下源码,发现PhotoView给出了另一个方法用来处理,setOnPhotoTapListener();
只要简单的
//这里用了简单的Lambda表达式,应该都能看懂吧...
view.setOnPhotoTapListener((view1, x, y) -> finish());
实现效果。
如果只是单纯的实现点击退出全屏这个没问题,但是结合ViewPager使用时,就会出现问题了,
如果来回滚动ViewPage,就会出现这个问题,然后,就会发现点击事件又不能用了
I/PhotoViewAttacher: ImageView no longer exists. You should not use this PhotoViewAttacher any more.
查了一下源码,发现是photoView是类似MVC结构,作者将所有的操作抛给了PhotoViewAttacher这个类来处理,这个异常就是在这个类中抛出的:
public ImageView getImageView() {
ImageView imageView = null;
if (null != mImageView) {
imageView = mImageView.get();
}
// If we don't have an ImageView, call cleanup()
if (null == imageView) {
cleanup();
LogManager.getLogger().i(LOG_TAG,
"ImageView no longer exists. You should not use this PhotoViewAttacher any more.");
}
return imageView;
}
然而发现,只有在这个cleanUp()方法中,才会置空mImageView,同时这个方法还进行了一些操作,置空了监听器,所以监听失效了
/**
* Clean-up the resources attached to this object. This needs to be called when the ImageView is
* no longer used. A good example is from {@link android.view.View#onDetachedFromWindow()} or
* from {@link android.app.Activity#onDestroy()}. This is automatically called if you are using
* {@link uk.co.senab.photoview.PhotoView}.
*/
@SuppressWarnings("deprecation")
public void cleanup() {
if (null == mImageView) {
return; // cleanup already done
}
final ImageView imageView = mImageView.get();
if (null != imageView) {
// Remove this as a global layout listener
ViewTreeObserver observer = imageView.getViewTreeObserver();
if (null != observer && observer.isAlive()) {
observer.removeGlobalOnLayoutListener(this);
}
// Remove the ImageView's reference to this
imageView.setOnTouchListener(null);
// make sure a pending fling runnable won't be run
cancelFling();
}
if (null != mGestureDetector) {
mGestureDetector.setOnDoubleTapListener(null);
}
// Clear listeners too
mMatrixChangeListener = null;
mPhotoTapListener = null;
mViewTapListener = null;
// Finally, clear ImageView
mImageView = null;
}
而这个方法是在PhotoView中是这么用的
@Override
protected void onDetachedFromWindow() {
mAttacher.cleanup();
super.onDetachedFromWindow();
}
那么问题就很明朗了
因为我没有设置缓存setOffscreenPageLimit()控制,导致我的PhotoView会在
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
这里被干掉,设置上之后,一切解决。