Android双列表联动和固定头部ScrollView效果实现
引文:
之前在寫一個stickScrollView的時候對不少人有一定的啟示作用,這次針對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設置滾動監聽就可以了:
二.功能實現了,那現在咱們就談談性能問題了?
在真實情況是每個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() {@Overridepublic 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; // 標識已經觸發過懶加載數據@Overridepublic void setUserVisibleHint(boolean isVisibleToUser) {super.setUserVisibleHint(isVisibleToUser);if (isVisibleToUser) {//當當前為顯示頁面時lazyFetchDataIfPrepared();}}@Overridepublic void onViewCreated(View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);isViewPrepared = true;}@Overridepublic 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是我持續開源的最大動力。
總結
以上是生活随笔為你收集整理的Android双列表联动和固定头部ScrollView效果实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java深入研究】9、HashMap源
- 下一篇: 【LVS】简介与说明