Androidアプリ開発 RecyclerViewで一覧画面の区切り線を作成する

2016年04月10日(編集2017年03月12日)
このエントリーをはてなブックマークに追加

Androidアプリで一覧データのUI(ユーザーインターフェース)を作成する場合は、ListViewかRecyclerViewを使います。RecyclerViewで区切り線を利用するには、コードで実装する必要があります。

この記事は、RecyclerViewで区切り線の実装方法を記載した記事です。
環境はAndroid 7.1 (API level 25) です。

環境

  • android sdk 25
  • Build Tools, Revision 25.0.2
  • support recyclerview 25.1.1

難易度

中級者向け

サンプルコード

Android-Recycleview_Demo

RecyclerViewとは

RecyclerViewクラスは、Androidアプリで一覧画面のUIを作成する時に利用します。

RecyclerViewで作成した一覧画面

区切り線

区切り線は、一覧画面で項目ごとに線を引きます。

RecyclerViewで実装した区切り線

区切り線の実装

RecyclerViewで区切り線を実装するには、一覧表示の実装ができることが前提です。
一覧表示の実装方法を理解してないなら、

RecyclerViewで一覧画面を作成する

の記事を読んで、一覧表示の実装をおこなえるようにしてください。

Recyclerviewバージョン25以上

RecyclerViewバージョン25からは、DividerItemDecorationが導入されました。

このクラスは、この記事で説明している内容とほぼ同じコードが実装された純正ライブラリです。

実装内容の理解が必要ない場合は、

Androidアプリ開発 RecyclerView DividerItemDecorationで下線を引く

の記事を参考にした実装で下線を引けば良いと思います。

使用クラス

RecyclerView.ItemDecorationクラスを利用します。

ItemDecorationクラスは、adapterのデータ設定で、特定の項目にレイアウトのオフセットと特別な描画を加えることができます。

区切り線実装

一覧表示のRecycleViewに、区切り線を追加します。

区切り線の生成にはRecyclerView.ItemDecorationクラスを利用します。コードで以下のようにItemDecorationの子クラスを作成します。

{project_folder}/app/java/package/ui/DividerItemDecoration.java
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

public class DividerItemDecoration extends RecyclerView.ItemDecoration {

    private static final int[] ATTRS = new int[]{
            android.R.attr.listDivider
    };

    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;

    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;

    private Drawable mDivider;

    private int mOrientation;

    public DividerItemDecoration(Context context, int orientation) {
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
        setOrientation(orientation);
    }

    public void setOrientation(int orientation) {
        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
            throw new IllegalArgumentException("invalid orientation");
        }
        mOrientation = orientation;
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            drawVertical(c, parent);
        } else {
            drawHorizontal(c, parent);
        }
    }

    public void drawVertical(Canvas c, RecyclerView parent) {
        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    public void drawHorizontal(Canvas c, RecyclerView parent) {
        final int top = parent.getPaddingTop();
        final int bottom = parent.getHeight() - parent.getPaddingBottom();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
        if (mOrientation == VERTICAL_LIST) {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        }
    }
}
        

onDrawメソッドをオーバーライドして呼び出します。
このメソッドで記述された内容が、項目のviewを生成する前にCanvasで記述されます。

@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
    if (mOrientation == VERTICAL_LIST) {
        drawVertical(c, parent);
    } else {
        drawHorizontal(c, parent);
    }
}
        

drawVerticalメソッドとdrawHorizontalメソッドは前もって用意されているメソッドではありません。 区切り線を引くため、自分で実装したメソッドです。
このメソッドは、RecyclerViewのviewを取得し、padding, margin, 高さ、幅などの値から区切り線を描画する位置を計算しています。
viewの計算には慣れが必要です。viewの計算で得られる値は以下のようになります。

viewの計算は左上が基準座標として計算する

上記の値からCanvasに線を引く座標を設定します。

子供viewの計算から、区切り線の位置を決める

子viewの値で、Canvasを塗りつぶします。

mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
        

RecyclerViewに設定

上記で作成したDividerItemDecorationの子クラスをRecyclerViewに設定します。

{project_folder}/app/java/package/ui/RecyclerViewDividerLineFragment.java
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_item_list, container, false);

        // Set the adapter
        if (view instanceof RecyclerView) {
            Context context = view.getContext();
            RecyclerView recyclerView = (RecyclerView) view;
            recyclerView.setLayoutManager(new LinearLayoutManager(context));
            recyclerView.setAdapter(new MyItemRecyclerViewAdapter(DummyContent.ITEMS));

            RecyclerView.ItemDecoration itemDecoration = new
                    DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST);
            +recyclerView.addItemDecoration(itemDecoration);
        }
        return view;
    }
        

RecyclerViewのaddItemDecorationメソッドの引数にitemDecorationオブジェクトを渡します。

RecyclerView.ItemDecoration itemDecoration = new
        DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST);
recyclerView.addItemDecoration(itemDecoration);
        

ビルドして実行

ビルドしてアプリを実行します。

ItemDecorationで区切り線を生成

区切り線が表示されました。

まとめ

ItemDecorationを利用すると、RecyclerViewのviewに様々な装飾ができます。

区切り線以外の描写は、Googleカレンダー、Gmail、Inboxのインターフェースが参考になると思います。また、Canvasオブジェクトの使い方は慣れるまで大変なので、手元にメモを用意し、図と数値を書きながらイメージを固めていくと理解が早まるでしょう。

是非挑戦してみてください。

関連記事

タグ検索で調べてみよう

Android7.1 UI