以前在寫一個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