引文:
之前在寫一個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設定滾動監聽就可以了:
@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開,而且滑動也明顯流暢了。
代碼已經上傳,有需要的可以去看下,github位址,您的點贊或者star是我持續開源的最大動力。