以前在写一个stickScrollView的时候对很多人有必定的启示做用,此次针对stickScrollView再实现双列表的联动效果,但愿对后续的开发者要实现一样的效果能有必定的启示,在实现的思路上比较简单,可是期间碰到了性能的问题,也会针对我优化的过程当中提出本身优化的思路,让后面有遇到相似的问题的伙伴少走点弯路。git
如图的效果图是左边列表点击以后,会滚动到左列表对应的右边字类目列表;当滑动右边的列表的时候,又能够反过来做用于左边列表,实现勾选上对应的左边列表。github
mLlRight.scrollToPositionWithOffset(scrollIndex, 0);//scrollIndex就是根据左边的点击项,计算右边滑动的位置
网上一直有思路是根据滑动的postion是否在第一个可见的item以前,可见item以后和最后可见item以后,最后的可见item以前三种状况来处理:网络
if (scrollIndex <= firstItem) { //当要置顶的项在当前显示的第一个项的前面时 mChildRecyclerviewRight.smoothScrollToPosition(scrollIndex); } else if (scrollIndex <= lastItem) { //当要置顶的项已经在屏幕上显示时,计算它离屏幕原点的距离 int top = mChildRecyclerviewRight.getChildAt(scrollIndex - firstItem).getTop(); mChildRecyclerviewRight.smoothScrollBy(0, top); } else { //当要置顶的项在当前显示的最后一项的后面时 mChildRecyclerviewRight.smoothScrollToPosition(scrollIndex); //记录当前须要在RecyclerView滚动监听里面继续第二次滚动 move = true; }
可是我发现这样的处理的话,能实现右边的定位的效果,可是走else判断的时候会触发右边列表的二次滚动,这个会触发右边列表的监听事件,相似手指滑动右边又从新进行左边的定位,虽然作了各类判断,可是在个人暴力测试下,仍是会有这样的状况出现,很头疼,经测试仍是LiearLayoutManager的方法比较靠谱。
### 2.当右边的列表滑动的时候,给recyclerview设置滚动监听就能够了:app
@Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); //在这里进行第二次滚动(最后的距离) if (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) { if (!mIsLeftTouch) { leftLocation(); } } }
在真实状况是每一个fragment的右侧列表数据都会很庞大,咱们之前在列表上面能够用分页,可是如今必须一次性加载这么多数据,会出现如下的几个问题,针对这几个问题,我本身有进行优化,所以将优化的方案也贴出来,旨在但愿你们不只能开发功能性的app,还要开发出性能高的app,我如今是用了700条数据进行测试,每一个item有图片和文案。没优化以前的使用是这个体验,启动是4s,以下图:ide
解决办法:咱们在Activity加载的时候,咱们就应该对viewPager,fragment初始化好,在网络请求拿到数据以后,咱们只须要拿到初始化的fragment和tabLayout进行刷新数据就能够了。以下面就是在网络请求完成以后,回调fragment提供的接口的notifyDataChange方法,执行fragment刷新界面,同时咱们对tablayout取到每个须要赋值的view,进行设值,代码以下:post
private void initVP() { for (FragmentWithTitleBean fragmentWithTitleBean : mFragments) { ((CheckListFragment) (fragmentWithTitleBean.getFragment())).notifyDataChange(); } //通知tablayout进行改变 for (int i = 0, size = mOrderManagerTabs.getTabCount(); i < size; i++) { TabLayout.Tab tab = mOrderManagerTabs.getTabAt(i); if (tab != null && tab.getCustomView() != null) { TextView tvNum = tab.getCustomView().findViewById(R.id.tv_num); int intNum = 0; if (i == 0) intNum = getCheckInfoBean().getItemAllCount(); else if (i == 1) intNum = getCheckInfoBean().getItemDoneCount(); else if (i == 2) intNum = getCheckInfoBean().getItemAllCount() - getCheckInfoBean().getItemDoneCount(); setTabNum(tvNum, intNum); } } }
RecycerlView在加载的时候,有这样的机制,若是是height为wrap_content的话,那么你的recyclerview在加载的时候,会一次性将全部数据加载进来?what fuck,那这样1000条数据同时设置,那不是卡爆了?可是当咱们给recyclerview设置指定的高度的话,那么它一开始只会加载只须要显示的View,这样无论数据多少条,那也会好不少,那这样有思路,那么咱们接下来就是要给右侧的recyclerview设定指定的高度:性能
private void initRightRVHeight() { mChildRecyclerviewRight.post(new Runnable() { @Override public void run() { ViewGroup.LayoutParams layoutParams = mChildRecyclerviewRight.getLayoutParams(); layoutParams.height = mParentActivity.getVpHeight(); mChildRecyclerviewRight.setLayoutParams(layoutParams); } }); }
那这样的话,就须要用到业内的懒加载机制,相信不少人都会有解决方案,这里我就贴下个人代码实现吧:测试
public abstract class LazyFragment extends Fragment { boolean isViewPrepared; // 标识fragment视图已经初始化完毕 boolean hasFetchData; // 标识已经触发过懒加载数据 @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (isVisibleToUser) {//当当前为显示页面时 lazyFetchDataIfPrepared(); } } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); isViewPrepared = true; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); lazyFetchDataIfPrepared(); } void lazyFetchDataIfPrepared() { // 用户可见fragment && 没有加载过数据 && 视图已经准备完毕 if (getUserVisibleHint() && !hasFetchData && isViewPrepared) { hasFetchData = true; //已加载过数据 lazyFetchData(); } } abstract void lazyFetchData(); }
通过上面三步以后,你再使用过的时候,就会有第一张图的体验了,真是快太多了呀,从原来的4s到如今的1s开,并且滑动也明显流畅了。优化
代码已经上传,有须要的能够去看下,github地址,您的点赞或者star是我持续开源的最大动力。spa