今回は、Android 5 の新しい Widget「CardView」と、前にご紹介した RecyclerView で利用可能な Layout の1つ、「StaggeredGridLayoutManager」を使ってみましたので、ご紹介します。
前回の記事はコチラ
Material Design な Navigation Drawer を目指す(1)
Material Design な Navigation Drawer を目指す(2)
RecyclerView のアイテムとして複数の CardView と、RecyclerView.LayoutManager には StaggeredGridLayoutManager を利用して、上図のような複数カラムのリスト表示を行います。
CardView の準備
まずは build.gradle の dependencies に以下のライブラリを追加します。
dependencies {...compile "com. android.support: cardview-v7:+"} |
今回のサンプルでは大・中・小の3種類の CardView を利用します。それぞれのレイアウトは、Components > Cardsの Card layout guidelines を参考に設定しています。
CardView は FrameLayout を継承したクラスで、異なるプラットフォーム間でも一貫した外観を表示することができます。
<android.support.v7.widget.CardViewxmlns: android="http://schemas.android.com/apk/res/android"xmlns: card_view="http://schemas.android.com/apk/res-auto"android: layout_width="match_parent"android: layout_height="wrap_content"card_view: cardBackgroundColor="#ffffff"android: elevation="2dp"card_view:cardCornerRadius="2dp"> <!-- CardView に表示したいViewを配置 -- > </android.support.v7.widget.CardView> |
表示データXMLの準備
前回と同じような形式で、RecyclerView に表示するデータをXMLで定義しています。
<!-- Cardの構造 menu --><array name="card_list_data"> <item>@array/card1</item> <item>@array/card2</item> <item>@array/card3</item>...</array> <!-- Cardの要素種別 +type --> <array name="type_bg_card"> <item name="key">type</item> <item name="value">bigCard</item></array> <array name="type_md_card"> <item name="key">type</item> <item name="value">middleCard</item></array> <array name="type_sm_card"> <item name="key">type</item> <item name="value">smallCard</item> </array>... <!-- Cardの1要素内の構造 item --> <array name="card1"><item>@array/type_bg_card</item> <item>@array/card_image1</item> <item>@array/card_headline_text_1</item> <item>@array/card_body_text_1</item> </array>... <!-- Cardの表示内容・設定 content --> <array name="card_image1"> <item name="key">image</item> <item name="value">@drawable/photo</item> </array> <array name="card_headline_text_1"> <item name="key">headlineTxt</item> <item name="value">headline 1</item> </array> <array name="card_body_text_1"> <item name="key">bodyTxt</item> <item name="value">body 1</item> </array>... |
StaggeredGridLayoutManager の設定
StaggeredGridLayoutManager の第1引数 spanCount の値でカラムを設定し、第2引数で VERTICAL or HORIZONTAL を指定することができます。
StaggeredGridLayoutManager mLayoutManager = new StaggeredGridLayoutManager (spanCount,StaggeredGridLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(mLayoutManager); |
Adapter の記述
表示するアイテムの種類によって処理を分岐するのは前回と同様なので省略しますが、
onBindViewHolder 内の処理で、大・中サイズの CardView の場合は、2カラム表示を無効にして全幅表示(setFullSpan)になるようにレイアウトパラメータを設定しています。
// SmallサイズのCard以外は、 全幅表示 final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); if (lp instanceof StaggeredGridLayoutManager.LayoutParams) { StaggeredGridLayoutManager.LayoutParams sglp = (StaggeredGridLayoutManager.LayoutParams) lp;sglp.setFullSpan(holder.getItemViewType() != TYPE_SM_CARD_ID);holder.itemView.setLayoutParams(sglp); } |
加えて CardView 内のボタンのクリックイベントを検知できるように、以下のような独自リスナーを設定します。CardView の場合、1アイテム内に複数アクション(今回の例では、Done/Cancelボタン)を含む場合は、前回のタップ座標値からViewを割り出すよりは、今回のように直接監視対象のViewにリスナーを設定しておく方が適しているかと思います。
// Done・Cancelボタンにタグ設定 holder.mDoneBtn.setOnClickListener(this); holder.mDoneBtn.setTag(position); holder.mCancelBtn.setOnClickListener(this); holder.mCancelBtn.setTag(position); private OnItemClickListener mListener; public void setOnItemClickListener (OnItemClickListener listener) { mListener = listener; } public static interface OnItemClickListener { public void onItemClick (CardAdapter adapter, int position, HashMap<String, Object> item, View clickView); } @Overridepublic void onClick(View view) { if (mRecyclerView == null) {return;} if (mListener != null) { int position = (Integer) view.getTag(); HashMap<String, Object> item = mCardDataArr.get(position); mListener.onItemClick(this, position, item, view); } } |
上記で用意したリスナーを使って、Activity にて監視&検知を行います。
mCardAdapter.setOnItemClickListener (new CardAdapter.OnItemClickListener() { @Overridepublic void onItemClick (CardAdapter adapter, int position, HashMap<String, Object> item, View clickView) { // 独自実装したアイテムクリックの検知switch (clickView.getId()) { case R.id.doneBtn:Toast.makeText(getActivity(), "DONE:" + item.toString(), Toast.LENGTH_LONG).show(); break; case R.id.cancelBtn:Toast.makeText(getActivity(), "CANCEL:" + item.toString(), Toast.LENGTH_LONG).show(); break;} } } ); |