在做项目的时候,需要自定义一个日历的控件,一开始采用普遍的做法: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 view
private 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);
// attach
if (view == convert) { // reused
if (-1 != indexOfChild(convert))
detachViewFromParent(convert);
attachViewToParent(view, -1, params);
} else
addViewInLayout(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 position
mIsJumpToCurrent = 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);
}
但是有一个问题,在使用过程中,如果界面上有动画,滑动会出现问题,楼主还在解决中。
本文介绍了一种改进ViewPager滑动卡顿问题的方法。通过预加载三个页面并重用已加载页面而非每次重新加载,显著提高了滑动流畅度。文章还提供了实现这一优化的关键代码片段。
2133

被折叠的 条评论
为什么被折叠?



