說說 Android 的 Material Design 設計(四)——卡片式佈局
我們使用 CardView 與 RecyclerView 來·實現一個各種貓的卡片式展示列表吧O(∩_∩)O~
1 CardView 控制元件
1.1 引入依賴庫
開啟 app/build.gradle,新增依賴庫:
dependencies { ... compile 'com.android.support:recyclerview-v7:24.2.1' compile 'com.android.support:cardview-v7:24.2.1' compile 'com.github.bumptech.glide:glide:4.8.0' }
最後一行引入的 Glide,它是一個快速高效的 Android 圖片載入庫,注重於平滑的滾動 。 Glide 支援拉取,解碼和展示視訊快照,圖片,和 GIF 動畫 。
1.2 卡片式佈局
CardView 控制元件可實現卡片式佈局。它其實是一個 FrameLayout,只不過多了圓角與陰影功能。
佈局:
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:material="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer" android:layout_width="match_parent" android:layout_height="match_parent"> ... <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"/> ... </android.support.v4.widget.DrawerLayout>
我們在 DrawerLayout 中新增了 RecyclerView,並讓它佔滿整個空間(寬與高都是 match_parent)。
1.3 “貓”實體類
public class Cat { //型別 private String type; //圖片資源 ID private int imgId; public Cat(String type, int imgId) { this.type = type; this.imgId = imgId; } public String getType() { return type; } public int getImgId() { return imgId; } }
1.4 RecyclerView 的 item 佈局
在 layout 目錄下新建 cat_item.xml,內容為:
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:material="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" material:cardCornerRadius="4dp"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <ImageView android:id="@+id/cat_image" android:layout_width="200dp" android:layout_height="200dp" android:scaleType="centerCrop"/> <TextView android:id="@+id/cat_type" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_margin="5dp" android:textSize="16sp" /> </LinearLayout> </android.support.v7.widget.CardView>
注意:這裡事先已把貓的相關圖片放置在 res/drawable 目錄中。
因為每張圖片的長寬比例不一樣,所以我們把 android:scaleType
設定為 centerCrop,讓圖片按照原比例充滿整個 ImageView,並裁剪超出的部分。
1.5 RecyclerView 介面卡
public class CatAdapter extends RecyclerView.Adapter<CatAdapter.ViewHolder> { private Context context; private List<Cat> cats = new ArrayList<>(); public CatAdapter(List<Cat> cats) { this.cats = cats; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (context == null) {//設定上下文環境 context = parent.getContext(); } View view = LayoutInflater.from(context).inflate(R.layout.cat_item, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { Cat cat = cats.get(position); holder.type.setText(cat.getType()); Glide.with(context).load(cat.getImgId()).into(holder.image); } @Override public int getItemCount() { return cats.size(); } static class ViewHolder extends RecyclerView.ViewHolder { CardView cardView; ImageView image; TextView type; public ViewHolder(View itemView) { super(itemView); cardView = (CardView) itemView; image = (ImageView) itemView.findViewById(R.id.cat_image); type = (TextView) itemView.findViewById(R.id.cat_type); } } }
- 在 onBindViewHolder 中使用 Glide 來載入圖片。
- Glide.with() 可傳入 Context、Activity、FragmentActivity 或 Fragment,建立RequestManager 物件。
- RequestManager .load() 用於載入圖片,可以傳入 File、resourceId、URI 等型別的引數,建立 DrawableRequestBuilder 物件。
- DrawableRequestBuilder .into() 用於指定放置圖片的 ImageView。
- Glide 本身會對圖片進行壓縮,所以就算是很大的圖片,也可以放心使用啦O(∩_∩)O~
1.6 活動類
public class MainActivity extends AppCompatActivity { private DrawerLayout drawerLayout; private Cat[] cats = {new Cat("布偶貓", R.drawable.cat1), new Cat("異國短毛貓", R.drawable.cat2), new Cat("波斯貓", R.drawable.cat3), new Cat("美國短毛貓", R.drawable.cat4), new Cat("挪威森林貓", R.drawable.cat5), new Cat("日本短尾貓", R.drawable.cat6), new Cat("俄羅斯藍貓", R.drawable.cat7), new Cat("伯曼貓", R.drawable.cat8), new Cat("緬因貓", R.drawable.cat9), new Cat("埃及貓", R.drawable.cat10)}; private List<Cat> catList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ... initCats(); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); int spanCount = 2; GridLayoutManager layoutManager = new GridLayoutManager(this, spanCount); recyclerView.setLayoutManager(layoutManager); CatAdapter adapter = new CatAdapter(catList); recyclerView.setAdapter(adapter); } private void initCats() { catList.clear(); for (int i = 0; i < 100; i++) {//隨機新增 100 只貓的資訊 Random random = new Random(); int index = random.nextInt(cats.length); catList.add(cats[index]); } } ... }
- initCats() 在 cats 陣列中隨機挑選了 100 只貓。
- 使用了 GridLayoutManager 佈局,它接收兩個引數:Context 與總列數。

效果
卡片式佈局漂亮吧?O(∩_∩)O~
2 優化
2.1 解決頂部工具欄被遮擋問題
目前設計中的卡片式佈局存在一個問題,就是會遮擋頂部工具欄。
傳統做法是讓 RecyclerView 向下偏移頂部工具欄的高度。
AppBarLayout 是 Design Support 庫提供的一個垂直方向的 LinearLayout,它封裝很多滾動事件。
修改佈局檔案:
... <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" /> </android.support.design.widget.AppBarLayout> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" material:layout_behavior="@string/appbar_scrolling_view_behavior" /> ...
- 使用 AppBarLayout 包裹 Toolbar。
- 為 RecyclerView 的 material:layout_behavior 指定 appbar_scrolling_view_behavior 事件。

經過這兩步修改,工具欄與卡片式佈局就可以和諧共處啦O(∩_∩)O~
2.2 工具欄響應滾動事件
<android.support.v7.widget.Toolbar ... material:layout_scrollFlags="scroll|enterAlways|snap" />
我們在 Toolbar 中新增了 material:layout_scrollFlags 屬性,並設定了三種場景中的顯示策略。從左到右,場景依次為向上滾動時、向下滾動時和還未完全顯示與隱藏時。
屬性 | 說明 |
---|---|
scroll | 一起滾動,會被隱藏。 |
enterAlways | 一起滾動,一直顯示。 |
snap | 根據滾動距離,來判斷是顯示還是隱藏。 |

效果
當用戶向上滑動內容時,隱藏工具欄;當用戶向上滑動螢幕時,再顯示工具欄。這是 Material Design 中的一條重要設計,極大地提升了使用者的閱讀體驗O(∩_∩)O~