引文:之前在寫一個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