Android雙列表聯(lián)動和固定頭部ScrollView效果實現(xiàn)

引文:之前在寫一個stickScrollView的時候?qū)Σ簧偃擞幸欢ǖ膯⑹咀饔茫@次針對stickScrollView再實現(xiàn)雙列表的聯(lián)動效果,希望對后續(xù)的開發(fā)者要實現(xiàn)同樣的效果能有一定的啟示,可能在實現(xiàn)的思路上比較簡單,但是還是碰到了性能的問題,也會針對我優(yōu)化的過程中提出自己優(yōu)化的思路,讓后面有遇到類似的問題的伙伴少走點彎路。

一.首先貼下效果圖吧:

image

如圖的效果圖是左邊列表點擊之后,會滾動到左列表對應的右邊字類目列表;當滑動右邊的列表的時候,又可以反過來作用于左邊列表,實現(xiàn)勾選上對應的左邊列表。

1.實現(xiàn)思路,當左邊列表點擊的時候:

 mLlRight.scrollToPositionWithOffset(scrollIndex, 0);

網(wǎng)上一直有思路是根據(jù)滑動的postion是否在第一個可見的item之前,可見item之后和最后可見item之前,最后的可見item之后三種情況來處理:

   if (scrollIndex <= firstItem) {
       //當要置頂?shù)捻椩诋斍帮@示的第一個項的前面時
       mChildRecyclerviewRight.smoothScrollToPosition(scrollIndex);
       } else if (scrollIndex <= lastItem) {
           //當要置頂?shù)捻椧呀?jīng)在屏幕上顯示時,計算它離屏幕原點的距離
           int top = mChildRecyclerviewRight.getChildAt(scrollIndex - firstItem).getTop();
           mChildRecyclerviewRight.smoothScrollBy(0, top);
       } else {
       //當要置頂?shù)捻椩诋斍帮@示的最后一項的后面時
       mChildRecyclerviewRight.smoothScrollToPosition(scrollIndex);
       //記錄當前需要在RecyclerView滾動監(jiān)聽里面繼續(xù)第二次滾動
       move = true;
   }

但是我發(fā)現(xiàn)這樣的處理的話,能實現(xiàn)右邊的定位的效果,但是會觸發(fā)右邊列表的二次滾動,這個會導致右邊列表的二次滾動觸發(fā)左邊列表的重新定位,雖然做了各種判斷,但是在我的暴力測試下,還是會有這樣的情況出現(xiàn),很頭疼,經(jīng)測試LiearLayoutManager的方法比較靠譜,就是有個問題數(shù)據(jù)量多的時候,左邊列表點擊的時候會很卡,當然了,這個在后邊有我的優(yōu)化之路。

2.當右邊的列表滑動的時候,給recyclerview設置滾動監(jiān)聽就可以了:

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        //在這里進行第二次滾動(最后的距離)
        if (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {
            if (!mIsLeftTouch) {
                leftLocation();
               }
           }
       }

雖然這樣聯(lián)動的效果實現(xiàn)了,但是個人發(fā)現(xiàn)整體界面的流暢性有很大問題,綜合原因是因為一次性加載了右邊的列表,右邊的列表數(shù)據(jù)量太過龐大了,而且有三個tab加載這樣就導致整個界面異??D,下面就這個提下我的優(yōu)化方案:

二.其實在整體的實現(xiàn)當中,真實情況是每個fragment的右側(cè)列表數(shù)據(jù)都會很龐大,我們以前在列表上面可以用分頁,但是現(xiàn)在必須一次性加載這么多數(shù)據(jù),會出現(xiàn)以下的幾個問題,針對這幾個問題,我自己有進行優(yōu)化,因此將優(yōu)化的方案也貼出來,旨在希望大家不僅能開發(fā)功能性的app,還要開發(fā)出性能高的app,我現(xiàn)在是用了700條數(shù)據(jù)進行測試,每個item有圖片和文案。

1.沒優(yōu)化之前的使用是這個體驗,啟動是4s:

image

2.問題1:當進界面的時候,由于右側(cè)列表數(shù)據(jù)過于龐大,一次性加載fragment顯示很慢,將近4s?

1.因為這個界面的tab上面有角標,這個時候通常的做法,是在網(wǎng)絡數(shù)據(jù)請求完成之后,再去進行ViewPager和TabLayout的初始化,這個時候很明顯會有一片空白的時候?

解決辦法:我們在Activity加載的時候,我們就應該viewPager,fragment初始化好,在網(wǎng)絡請求拿到數(shù)據(jù)之后,我們只需要拿到初始化的fragment和tabLayout進行刷新數(shù)據(jù)就可以了。如下面就是在網(wǎng)絡請求完成之后,回調(diào)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.RecycerlView在加載的時候,有這樣的機制,如果是height為wrap_content的話,那么你的recyclerview在加載的時候,會一次性將所有數(shù)據(jù)加載進來?what fuck,那這樣1000條數(shù)據(jù)同時設置,那不是卡爆了?但是當我們給recyclerview設置指定的高度的話,那么它一開始只會加載部分的顯示的View,這樣不管數(shù)據(jù)多少條,那也會好很多,那這樣有思路,那么我們接下來就是要給右側(cè)的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:我們在一進來,三個tab下面的fragment都有這么大的數(shù)據(jù),同時執(zhí)行cpu會有點吃力吧,沒錯就是這樣?那這樣的話,就需要用到業(yè)內(nèi)的懶加載機制,相信他們都會解決方案,這里我貼我的實現(xiàn)吧:

public abstract class LazyFragment extends Fragment {
    boolean isViewPrepared; // 標識fragment視圖已經(jīng)初始化完畢
    boolean hasFetchData; // 標識已經(jīng)觸發(fā)過懶加載數(shù)據(jù)


    @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 && 沒有加載過數(shù)據(jù) && 視圖已經(jīng)準備完畢
        if (getUserVisibleHint() && !hasFetchData && isViewPrepared) {
            hasFetchData = true; //已加載過數(shù)據(jù)
            lazyFetchData();
        }
    }

    abstract void lazyFetchData();
}

三.經(jīng)過上面三步之后,你再使用過的時候,有這樣的體驗,真是快太多了呀,從原來的4s到現(xiàn)在的1s開,體驗圖如下:

image

四.代碼已經(jīng)上傳,有需要的可以去看下,github地址,您的點贊或者star是我持續(xù)開源的最大動力。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • #一練每日晨問#6月第1周 習慣 一種不假思索就能夠自然流現(xiàn)的思考和行為方式。在這種狀態(tài)中的人往往是沒有覺察的。改...
    劍峰_簡書閱讀 167評論 0 0
  • 震耳的鞭炮聲慢慢消散 歡騰的鑼鼓聲漸行漸遠 在外工作的你收拾行囊 春節(jié)的長假一晃就休完 媽媽身前身后圍著你轉(zhuǎn) 強忍...
    隨緣青青閱讀 303評論 1 4
  • 我是日記星球89號星寶寶,我正在參加日記星球21日蛻變之旅,這是我的第33篇原創(chuàng)日記 今天是女神節(jié),我心情好到爆,...
    富足喜悅的江華閱讀 235評論 1 1

友情鏈接更多精彩內(nèi)容