前言
最近发现自己有很多颇为基础的内容“不会写”了,就比如今天写的内容:ViewPager。
最近有小伙伴,在后台私信一些技术细节,大家真的好勤奋~~因为工作的原因,有些私信回复的不是很及时,多多包涵。996伤不起啊!
正文
平时我们很容易遇到这样的需求:页面底部很多Tab,可以点击或者活动切换不同的页面...估计话还没有说完,有朋友就会脱口而出: ViewPager + Fragment实现。
说起 ViewPager,日常需求中必不可少的角色。无论是轮播,还是Tab页面效果,ViewPager都帮咱们输出了成吨的伤害。
没错,今天我们就聊一聊这个“传统”的用法。
一、最最基本的写法
ViewPager + Fragment实现这种效果很简单。直接上代码:
当然, Fragment也很简单:
这个效果难不倒我们。但是,我们日常需求肯定不可能这么的简单。最直接来说,如果我们页面需要动态的更换内容,怎么办?
有朋友可能会说: notifyDataSetChanged()。
二、notifyDataSetChanged()
最开始,我是这么想的:当Fragment数据需要变化时,改变 fragmentData的内容,然后调Adapter中的 notifyDataSetChanged()。比如这样:
然而run起来,我并没有发现页面有任何的变化。并且没有发现任何方法被重新调用!这也就是说明, notifyDataSetChanged()一定需要特定的条件。
我猜踩过坑的小伙伴应该知道,此时应该重写 getItemPosition(@NonNullObjectobject)方法
那么接下来就让我们从源码中一探究竟,如何才能使 notifyDataSetChanged()生效...
三、源码分析
而逻辑的关键就在 dataSetChage()中:
点进 setCurrentItemInternal()方法,我们会发现细节比较多,这里我们就不深究这么多的边界条件,直接进入它内部的 populate(),而这个方法内部又会调用 addNewItem(),这个方法我们需要看一下:
这里的实现,有一个我们比较熟悉的方法 instantiateItem()。而这个方法在 FragmentPagerAdapter里被重写了:
注意看这个方法,有很多细节藏在里边!
看完这个方法,我们能得到俩个信息:
- 1、如果FragmentManager能通过Tag找到Fragment的实例,那么就直接attch()上这个Fragment
- 2、如果找不到,才会调 用getItem()去初始化这个Fragment
基于这个实现,我们就明白了。前文中因为POSITION_NONE被detach掉的Fragment在这里被attach上的。
四、解决问题
既然如此,那么对于我们开篇的那个动态改Fragment内容信息的需求,也就迎刃而解了:
这里我们只需写getItemPosition(),让 object是 TestFragment2类型的时候,返回PagerAdapter.POSITION_NONE。就可以解决这个问题了。
detach/attach过程,会使Fragment重绘,也就是重走 onCreateView()、 onViewCreated()。因此此时我们的数据源已经发生了变化,所以Fragment重绘就可以更新为最新的数据了。
尾声
代码写的很糙,大家勿喷。主要是通过这么一个小需求,记录一下自己那些年无视的源码细节~~