博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android双列表联动和固定头部ScrollView效果实现
阅读量:6452 次
发布时间:2019-06-23

本文共 4810 字,大约阅读时间需要 16 分钟。

引文:之前在写一个的时候对不少人有一定的启示作用,这次针对stickScrollView再实现双列表的联动效果,希望对后续的开发者要实现同样的效果能有一定的启示,在实现的思路上比较简单,但是期间碰到了性能的问题,也会针对我优化的过程中提出自己优化的思路,让后面有遇到类似的问题的伙伴少走点弯路。

一.首先贴下效果图吧:

如图的效果图是左边列表点击之后,会滚动到左列表对应的右边字类目列表;当滑动右边的列表的时候,又可以反过来作用于左边列表,实现勾选上对应的左边列表。

1.实现思路,当左边列表点击的时候执行下面的代码:

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设置滚动监听就可以了:

@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,如下图:

2.1因为这个界面的tab上面有角标,这个时候通常的做法,是在网络数据请求完成之后,再去进行ViewPager和TabLayout的初始化?

解决办法:我们在Activity加载的时候,我们就应该对viewPager,fragment初始化好,在网络请求拿到数据之后,我们只需要拿到初始化的fragment和tabLayout进行刷新数据就可以了。如下面就是在网络请求完成之后,回调fragment提供的接口的notifyDataChange方法,执行fragment刷新界面,同时我们对tablayout取到每一个需要赋值的view,进行设值,代码如下:

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);            }        }    }复制代码

2.2这么多的数据一次性设置给右侧的recyclerView,加载肯定会很慢?

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);            }        });    }复制代码

2.3三个tab下面的fragment都有这么大的数据,都加载,cpu会有点吃力吧?没错就是这样!

那这样的话,就需要用到业内的懒加载机制,相信很多人都会有解决方案,这里我就贴下我的代码实现吧:

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开,而且滑动也明显流畅了。代码已经上传,有需要的可以去看下,,您的点赞或者star是我持续开源的最大动力。

转载地址:http://oxgwo.baihongyu.com/

你可能感兴趣的文章
通过原生js添加div和css
查看>>
[训练日志] 7月13日
查看>>
Python 模块 和 包
查看>>
简单的导出表格和将表格下载到桌面上。
查看>>
《ArcGIS Engine+C#实例开发教程》第一讲桌面GIS应用程序框架的建立
查看>>
递归查询上一级
查看>>
JAVA - 大数类详解
查看>>
查询指定名称的文件
查看>>
批处理文件
查看>>
1.每次按一下pushbutton控件,切换图片?
查看>>
Python 嵌套列表解析
查看>>
[GXOI/GZOI2019]旧词——树链剖分+线段树
查看>>
android 补间动画的实现
查看>>
2017年广东省ACM省赛(GDCPC-2017)总结
查看>>
第十届蓝桥杯B组C++题目详解和题型总结
查看>>
树的存储结构2 - 数据结构和算法42
查看>>
函数的嵌套调用
查看>>
OC中使用 static 、 extern、 const使用
查看>>
简单理解函数回调——同步回调与异步回调
查看>>
POJ 1007
查看>>