Android雙列表聯動和固定頭部ScrollView效果實現

引文:

以前在寫一個stickScrollView的時候對很多人有必定的啓示做用,此次針對stickScrollView再實現雙列表的聯動效果,但願對後續的開發者要實現一樣的效果能有必定的啓示,在實現的思路上比較簡單,可是期間碰到了性能的問題,也會針對我優化的過程當中提出本身優化的思路,讓後面有遇到相似的問題的夥伴少走點彎路。git

一.首先貼下效果圖吧:

如圖的效果圖是左邊列表點擊以後,會滾動到左列表對應的右邊字類目列表;當滑動右邊的列表的時候,又能夠反過來做用於左邊列表,實現勾選上對應的左邊列表。github

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設置滾動監聽就能夠了: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

2.1由於這個界面的tab上面有角標,這個時候一般的作法,是在網絡數據請求完成以後,再去進行ViewPager和TabLayout的初始化?

解決辦法:咱們在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);
            }
        }

    }

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開,並且滑動也明顯流暢了。優化

代碼已經上傳,有須要的能夠去看下,github地址,您的點贊或者star是我持續開源的最大動力。spa

相關文章
相關標籤/搜索