前文
长复杂页面在项目中采用listview
实现的形式,利用mergeAdapter
来对界面做控制,偏偏有个itemView
是viewpager
的形式,于是该itemView
里有个ViewPager
作为子view
来做横滑操作。做出后,看上去很美。但是,突然发现当该item
划出屏幕,再划回来的时候,第一次切换viewPager
总会秒切,而且不丝滑,但之后的切换操作并无什么异常,都很丝滑。强迫症受不了,必须搞。而且只在7.x的版本上有问题,在4.X,6.X上都很perfect。
分析
- 首先是冥想阶段
- 既然和划出屏幕有关系,那么可以认为:
listView
的Item
回收机制造成的影响。 - 可能是
ViewPager
在划出划回的状态有问题。
排查阶段
先看看
ViewPager
的OnPageChangeListener
在正常与异常情况下切换时回调的状态。发现在onPageScrollStateChanged
的回调中,异常状态少了IDLE
(0) 和SETTLING
(2),只有DRAGGING
(1)。查看源码
IDLE
(0) 只在smoothScrollTo
方法中设置过此状态,依次上溯,发现在setCurrentItemInternal
方法中有代码块:
|
|
- 很大概率是此代码块的
if else
语句造成的,换言之就是mFirstLayout
变量造成的。打个断点试试看! 哇,果然是 当划出屏幕后再回来 走的是
mFirstLayout=true
,而正常情况下则是走的else
方法。接下来看看
mFirstLayout
在哪被赋值过。
|
|
mFirstLayout在上述方法中赋值过,那么问题就显而易见了。
原因:当该itemView
被划出屏幕时,会被detach
掉,再划回来则会走onAttachedToWindow
方法,此时mFirstLayout
被设置为true
,所以在划回来,第一次切换时会造成前文提到的情况。
解决方案也随之出现(回字有几种写法?):
- 设置
viewpager
的OnAttachStateChangeListener
侦听,在onViewAttachedToWindow
回调中,调用ViewPager.requestLayout()
;方法将mFirstLayout
置为false
。(对应onLayout
) - 利用反射,在
onViewAttachedToWindow
回调中,将mFirstLayout
置为false
。这个方法有人会有疑问就是 那岂不是在第一次onViewAttachedToWindow
的时候mFirstLayout
也为false
?答案是yes
,但是别忘了,setAdapter
里会置为true
。往往我们第一次onViewAttachedToWindow
之后都会给ViewPager
setAdapter
啊。所以整体还是对的。 - 投机取巧法。当
itemView
划出时调用两次setCurrentItem(currentItem)
方法,这样第二次就走else
的代码了。但是此方法需要写的代码有点多,而且罗嗦,耦合高,我压根就没试。
方法一:
|
|
方法二:
|
|
resetFirstLayout
的主要语句为:
|
|
mFirstLayout.setAccessible(true);
mFirstLayout.set(viewPager, false);
(这两句加到代码块生成不了html,蛋疼,拿出来意会就好)
好了,就这么多吧。。