一、列表優(yōu)化問題
先來看一下 app 原來的列表效果:

之前發(fā)現(xiàn)的問題已經(jīng)優(yōu)化建議有:
- 使用 TabLayout + ViewPager 使該頁面可左右滑動(dòng);
- item 控件間距不規(guī)范,視覺效果不好;
- 使用 CardView。
1.1 TabLayout + ViewPager
這個(gè)沒什么好說的,給新司機(jī)的一點(diǎn)小建議:Fragment 的復(fù)用。
創(chuàng)建 ViewPager 時(shí)一般會(huì)有多種類似的 Fragment,可以在創(chuàng)建時(shí)通過 setArguments() 方法將 Bundle 設(shè)置給 Fragment,然后在 Fragment 的 onCreateView() 獲取該 Bundle。
舉個(gè)栗子:
public class OfferFragment extends BaseFragment {
private String mCurrentType = "";
public static OfferFragment newInstance(String type) {
Bundle args = new Bundle();
args.putString("type", type);
OfferFragment fragment = new OfferFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
...
if(null != getArguments()){
getBundleExtras(getArguments());
}
...
return v;
}
private void getBundleExtras(Bundle arguments) {
if (arguments.containsKey("type")) {
mCurrentType = arguments.getString("type");
}
}
這時(shí)就可以根據(jù) mCurrentType 來獲取不同類型的數(shù)據(jù),當(dāng)然也可以把這部分代碼寫到 BaseFragment 里。
1.2 item 布局規(guī)范
先來看一張從 MD 官網(wǎng)扣來的一張 三行列表(需科學(xué)上網(wǎng)) 的間距示意圖:

通過仔細(xì)觀察上圖可得出以下基本結(jié)論:
- item 最外層 padding 為 16dp;
- 第一行文字基線(Text baseline)與頂部距離為 28dp,再減去 padding 的 16dp,文字高度為 12dp;
- 第二行文字基線與第一行文字基線間距為 20dp,說明文字行間距為 8dp,也就是說第二行 marginTop=8dp。
- 帶圖片的可以根據(jù)以上標(biāo)注調(diào)整圖片位置以及大小。
然鵝,實(shí)際項(xiàng)目中一般 UI 會(huì)標(biāo)注各個(gè)文本間距,上面權(quán)當(dāng)是給沒有 UI 的童鞋們一些參考。像我們的項(xiàng)目,以前也沒有 UI,現(xiàn)在到我手上基本可以改改間距:

大概就是這樣子,看上去比之前好了很多,重點(diǎn)是 margin/pading 為 4dp 的倍數(shù)。比如第一行加粗標(biāo)題,為了突出它,第二行與第一行間距為 12dp。第二到三四行的間距為 8dp,因?yàn)樗鼈儗儆谕壝枋觥?/p>
在外層套了 CardView,看上去就比較有立體感了。上圖 item 布局 源碼。
二、 CardView 的使用
CardView 的基本使用已經(jīng)無需再提,本文記錄 CardView 使用要注意的一些地方。先大概看一下效果:

2.1 CardView Style
- values 文件夾下 Style 設(shè)置示例:
<style name="CardViewStyle" parent="Widget.MaterialComponents.CardView">
<item name="android:layout_margin">4dp</item>
<item name="cardCornerRadius">4dp</item>
<item name="cardElevation">4dp</item>
<item name="android:foreground">?android:attr/selectableItemBackground</item>
</style>
-
圓角弧度:
cardCornerRadius; -
陰影:
cardElevation; -
點(diǎn)擊相應(yīng):
android:foreground;
- values-v21 文件夾,適配 21 以上版本設(shè)備。也就是說 Android 5.0 以上的設(shè)備會(huì)優(yōu)先使用這個(gè)文件夾下的配置內(nèi)容。其中一些配置低版本使用無效或不可使用。
<style name="CardViewStyle" parent="Widget.MaterialComponents.CardView">
<item name="android:layout_margin">4dp</item>
<item name="cardCornerRadius">4dp</item>
<item name="cardElevation">4dp</item>
<item name="android:foreground">?android:attr/selectableItemBackgroundBorderless</item>
<item name="android:stateListAnimator">@animator/mtrl_card_state_list_anim</item>
</style>
這里的 android:foreground 使用的是 selectableItemBackgroundBorderless,android 內(nèi)置的水波紋效果,也可以自定義效果,用來實(shí)現(xiàn)點(diǎn)擊響應(yīng)。
-
點(diǎn)擊抬起陰影效果:
android:stateListAnimator:API Level 21 引入的 z 軸動(dòng)畫,簡單的說是 MD 的 UI 抬起動(dòng)畫??匆幌?mtrl_card_state_list_anim代碼:
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="true">
<set>
<objectAnimator
android:duration="150"
android:propertyName="translationZ"
android:valueTo="15dp"
android:startDelay="75"
android:interpolator="@anim/mtrl_card_fast_interpolator"
android:valueType="floatType"/>
</set>
</item>
<item>
<set>
<objectAnimator
android:duration="150"
android:propertyName="translationZ"
android:valueTo="0dp"
android:interpolator="@anim/mtrl_card_lowers_interpolator"
android:valueType="floatType"/>
</set>
</item>
</selector>
-
android:duration:動(dòng)畫時(shí)長; -
android:propertyName:屬性名稱,translationZ 表示 Z 軸移動(dòng); -
android:valueTo:移動(dòng)到 15 dp; -
android:startDelay:延時(shí)執(zhí)行; -
android:interpolator:插值器,控制動(dòng)畫執(zhí)行速率,比如先慢后快、勻速等; -
android:valueType:移動(dòng)類型,此處為浮點(diǎn)數(shù)。
MD 示例 Z 軸抬起動(dòng)畫是在 CardView 拖拽時(shí)執(zhí)行,本文 demo 中是在點(diǎn)擊時(shí)觸發(fā),推薦在 CardView 移動(dòng)時(shí)添加 Z 軸抬起下落動(dòng)畫。

有關(guān) CardView Style 設(shè)置還有更多屬性,大家可根據(jù)需要查閱和添加。
2.2 RecyclerView + CardView
在本項(xiàng)目中,把 CardView 用于列表,既然是列表就需要用到 RecyclerView 了。常見的列表有橫向的、縱向的,表格、瀑布流等等。上面展示的是縱向列表,接下來是瀑布流的實(shí)現(xiàn):

這樣展示列表信息,與普通縱向相比:
- 優(yōu)點(diǎn):新穎,美觀。同一頁面可以展示更多信息。
- 缺點(diǎn):信息展示過多過密集,容易引起視覺疲勞。
接下來看一下瀑布流的實(shí)現(xiàn),核心代碼在與給 RecyclerView 設(shè)置 LayoutManager:
//設(shè)置layoutManager
StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(2,
StaggeredGridLayoutManager.VERTICAL);
//解決item跳動(dòng)
manager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
mRecyclerView.setLayoutManager(manager);
布局的話就比較簡單了,使用 CardView 包裹 RelativeLayout,將所有 item 相對擺放即可。
2.3 item 展開動(dòng)畫
結(jié)合項(xiàng)目需求,假設(shè)貨主用戶發(fā)布某一訂單之后,會(huì)有承運(yùn)商來報(bào)價(jià)。頁面默認(rèn)展示最低報(bào)價(jià),因?yàn)橐话闱闆r下,貨主希望能以最低的價(jià)格把這批貨運(yùn)到目的地。那么如果想看其他承運(yùn)商的報(bào)價(jià),可以點(diǎn)擊按鈕展開報(bào)價(jià)信息。

這個(gè)效果的實(shí)現(xiàn)也比較簡單,使用 RecyclerView 的局部刷新功能,讓默認(rèn)隱藏的更多報(bào)價(jià)展示:
mOfferAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
switch (view.getId()){
case R.id.btn_expand:
OfferBean bean = mOfferAdapter.getItem(position);
bean.setExpand(!bean.isExpand());
mOfferAdapter.notifyItemChanged(position,"payload");
break;
}
}
});
關(guān)于列表寫到這里,下文記錄 跳轉(zhuǎn)動(dòng)畫 以及 CoordinatorLayout 的使用。
源碼地址 歡迎 Star。