另一种方法:当使用ViewPager加载大量View时卡顿严重的简单解决方法

来源:互联网 发布:mac系统怎么安装ae插件 编辑:程序博客网 时间:2024/04/30 14:27

在做项目的时候,需要自定义一个日历的控件,一开始采用普遍的做法:ViewPager+GridView。很容易想到,在使用的时候非常卡,加载非常慢。查了相关资料,发现基本上都是这种方法:ViewPager嵌套GridView引发的一系列UI卡顿不顺畅的问题,但都未曾从根本上解决问题。后来想到使用异步加载数据的方法,在初始化控件的时候,异步加载需要的日历数据,然后post更新界面,这种方法虽然加快了加载速度,但是滑动还是非常卡,严重影响体验。这时,作者查看了源代码,每次ViewPager在滑动的时候会每次new它的Adapter里面的page并加载数据,这样的方式效率极其低下,基本上没有重用。

既然是Page,一次只显示一页,每页的View都一样,那么何必每次在加载的时候再去new一页page,直接使用已经加载过的Page,只改变Page里面的数据就行了。

基于这种想法,在设计的时候就想着控件继承自AdapterView,通过适配器来适应数据;控件需要3个Page,首次加载3页数据,在Page滑动的时候,判断当前Page是否达到边界,然后交换Page,如图一,达到Page重用的目的。

当向右滑动时,当前Page(Page2)将变得不可见,当Page2完全不可见时,Page1变为当前Page(Page2),Page2变成Page3,而Page2变成page1,以此类推。

代码非常简单,下面贴出一部分关键代码:

 <pre class="java" name="code">                // set up adapter viewprivate View setupPage(int position, View convert) {View view = mAdapter.getView(position, convert, this);LayoutParams params = view.getLayoutParams();if (null == params)params = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);// attachif (view == convert) { // reusedif (-1 != indexOfChild(convert))detachViewFromParent(convert);attachViewToParent(view, -1, params);} elseaddViewInLayout(view, -1, params, true);if (null != mItemClickListener) {view.setOnClickListener(mPageClickListener);}return view;}

然后是配置交换:

private void swapPage(boolean leftToRight) {if (leftToRight) {/** * if should swap the first buffered-page to the last buffered-page  */mPosition++;View temp = mBufferedPages[0];mBufferedPages[0] = mBufferedPages[1];mBufferedPages[1] = mBufferedPages[2];mBufferedPages[2] = temp;if (mPageCount - 1 != mPosition)mBufferedPages[2] = setupPage(mPosition + 1, temp);if (mIsJumpToCurrent) { // if is jumped to current positionmIsJumpToCurrent = false;mBufferedPages[0] = setupPage(mPosition - 1, mBufferedPages[0]);}} else {mPosition--;View temp = mBufferedPages[2];mBufferedPages[2] = mBufferedPages[1];mBufferedPages[1] = mBufferedPages[0];mBufferedPages[0] = temp;if (0 != mPosition)mBufferedPages[0] = setupPage(mPosition - 1, temp);if (mIsJumpToCurrent) {mIsJumpToCurrent = false;mBufferedPages[2] = setupPage(mPosition + 1, mBufferedPages[2]);}}requestLayout();if (null != mPageSelectedListener)mPageSelectedListener.onPageSelected(mBufferedPages[1], mPosition);}

但是有一个问题,在使用过程中,如果界面上有动画,滑动会出现问题,楼主还在解决中。

 

0 1