PhotoView 与九宫格和ViewPager

来源:互联网 发布:php求职宝典 pdf 下载 编辑:程序博客网 时间:2024/06/03 16:36

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

这里被干掉,设置上之后,一切解决。

阅读全文
0 0