さくっとRecyclerViewを使ってリストを作成する

やぎすけAdventCalendar2016 Android

Posted on Dec 3


こんにちは、やぎにいです!
やぎすけ Advent Calendar 2016の3日目です。今のところ順調ですね。
2日目に昨日はうなすけがやぎすけ Advent Calendar 2日目 Gemfileの整頓を書いてくれました。
ここに出てきたRailsアプリはアドベントカレンダー後半で数日に渡って公開していきたいと思います。

RecyclerViewとは

Androidにはリストを表示するときにListViewなり、GridViewなりありますがAndroidのサポートライブラリv7で提供されているより柔軟なものがRecyclerViewになります。(ざっくり)
ListViewGridView表示を行えるのですが、じゃあそれらと何が違うの?と言うとそれらと比べて自由にカスタマイズできるという点があります。
ListView,GridViewで解決できないような物などに出会った際RecyclerViewを使うのが良いと思います。

単純にListViewなどで十分な場合はそれでいいと思いますが、個人的にあとで「あーやっぱRecyclerViewにしとけばよかった」みたいになった時に面倒なので、最近は最初からこちらを使うようにしています。
「カスタマイズ性が高い」ので最初最小構成でRecyclerViewを構築した際にはリストのアイテム間の区切り(devider)が無いなどありますが、この記事ではそういうカスタマイズを省いて最小構成でサクッとRecyclerViewを実装してアイテムを表示する流れを紹介します。

ひつようなもの

  • Android 2.1以上(API Level7以上)
  • サポートライブラリ

今回はNexus 5X(Android 7.1.1)で実機実行をしています。


ライブラリの導入

app/build.gradledependencies

1
compile 'com.android.support:recyclerview-v7:25.0.1'

を追加します。 Android Studioを使用している場合は、appを右クリックするとOpen Module Settingsがあるのでそこからrecyclerviewで検索するとライブラリが存在すると思います。


layoutファイルを作成する

書くものは2つです

  • RecyclerView本体
  • RecyclerViewのアイテムのレイアウト

順番にやっていきましょう
まず、RecyclerView本体。これは実際に配置したい場所に書いてあげます。
今回はlayout/activity_main.xmlの中に書きました。

1
2
3
4
<android.support.v7.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

次にRecyclerView内のアイテムのレイアウトです、今回はTextViewだけ配置します。

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"/>
</LinearLayout>

今回これはlayout/list_item.xmlとして配置しました。

以上でレイアウトの準備は完了です。

Adapterを作成する

続いてAdapterを作成します。 まず完成形をペタッと。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>  {
    private LayoutInflater mInflater;
    private ArrayList<String> mData;
    private Listener mListener;

    // アイテムタップ用interface
    public interface Listener {
        void onRecyclerClicked(View v, int position);
    }

    public RecyclerViewAdapter(Context context, ArrayList<String> data, Listener listener) {
        mInflater = LayoutInflater.from(context);
        mData = data;
        mListener = listener;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new ViewHolder(mInflater.inflate(R.layout.list_item, parent, false));
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        holder.textView.setText(mData.get(position));

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mListener.onRecyclerClicked(view, position);
            }
        });
    }

    @Override
    public int getItemCount() {
        if (mData == null) {
            return 0;
        }
        else {
            return mData.size();
        }
    }

    // ViewHolder
    public class ViewHolder extends RecyclerView.ViewHolder {
        TextView textView;

        public ViewHolder(View itemView) {
            super(itemView);
            textView = (TextView)itemView.findViewById(R.id.text);
        }
    }
}

継承するのはRecyclerView.Adapter<ViewHolder>になります。今回はインナークラスRecyclerViewAdapter.ViewHolderとして実装しました。 TextViewしかアイテムが存在しないのでそれだけ書いてあげます。

アイテムをタップしたときのイベント用にinterfaceを作成しています。RecyclerViewAdapter.Listenerとして実装しています。
onRecyclerClicked()としてタップされた場所とviewを引数として定義しています。

コンストラクタではコンテキストと実際のデータ(今回はTextViewに表示するためのArrayList<String>)とインターフェースを受け取ってセットしています。

onCreateViewHolderでは先ほど作成したアイテムのレイアウトを指定して、ViewHolderを作成しています。

onBindViewHolderでは実際にアイテムに受け取ったデータをセットして、イベントリスナーをセットしています。

タップイベント用のインターフェース、及びViewHolderは別ファイルとしてもいいですが、この程度の規模であればクラス内に実装してあげて大丈夫でしょう。

RecyclerViewにAdapterをセットする

Adapterが完成したらあとはもうデータを渡してRecyclerViewにセットすれば完了です。
今回はFragmentではなくActivity(MainActivity)でやっていきます。 まず完成形をペタリ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MainActivity extends AppCompatActivity implements RecyclerViewAdapter.Listener {

    private RecyclerView mRecyclerView;
    private RecyclerViewAdapter mRecyclerViewAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mRecyclerView = (RecyclerView)findViewById(R.id.recycler_view);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

        ArrayList<String> data = new ArrayList<>();
        data.add("うなすけ");
        data.add("やぎにい");
        data.add("アドベントカレンダー");
        data.add("やっていき!");

        mRecyclerViewAdapter = new RecyclerViewAdapter(this, data, this);
        mRecyclerView.setAdapter(mRecyclerViewAdapter);
    }

    @Override
    public void onRecyclerClicked(View v, int position) {
        TextView textView = (TextView)v.findViewById(R.id.text);
        Toast.makeText(this, textView.getText().toString(), Toast.LENGTH_SHORT).show();
    }
}

必要なのは以下の部分。

1
2
3
4
5
6
7
8
9
10
11
12
mRecyclerView = (RecyclerView)findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

//データの作成
ArrayList<String> data = new ArrayList<>();
data.add("うなすけ");
data.add("やぎにい");
data.add("アドベントカレンダー");
data.add("やっていき!");

mRecyclerViewAdapter = new RecyclerViewAdapter(this, data, this);
mRecyclerView.setAdapter(mRecyclerViewAdapter);

簡単ですね!基本的な感じはListViewGridViewと変わりません。
このコードで実行するとListViewになりますが、GridViewにしたい場合は2行目の部分を

1
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));

としてあげれば良いです。(第2引数はspanの数です)

さらに横方向にスクロールするようなリストにしたい場合は

1
2
3
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
mRecyclerView.setLayoutManager(linearLayoutManager);

Activityは先ほどAdapterで作成したインターフェースをimplementsで渡してあげて、オーバーライドしてあげます。 今回はタップされたら、そのアイテムの文字をトーストで表示するような実装をしています。

1
2
3
4
5
6
7
8
9
public class MainActivity extends AppCompatActivity implements RecyclerViewAdapter.Listener {
...省略...

    @Override
    public void onRecyclerClicked(View v, int position) {
        TextView textView = (TextView)v.findViewById(R.id.text);
        Toast.makeText(this, textView.getText().toString(), Toast.LENGTH_SHORT).show();
    }
}

これでRecyclerViewの一通りの実装は完了です。
このままだと区切り線などがないので、必要な方は実装する形になります。
途中で横スクロールのリストを設定する際にLinearLayoutManagerを自分で作成したことからわかるように、こうやって自分で作成することよって様々にカスタマイズをすることが出来ます。
ListViewからGridViewに簡単に移行できるのも結構便利ですね。


おわりに

いかがでしたでしょうか。僕も最初はとっつきにくいと思いListViewなどで頑張っていたのですがやってみると意外と簡単に実装できてしまいます。
確かにそれらと比べて自前で実装しなければならないのがとても多いですが、意外ときれいに実装できるので最初にぐっと実装してしまえば以降は柔軟に使っていくことができると思います。

今回ここで紹介したコードはAndroid ProjectとしてGithubに公開しておきました。
yagi2/RecyclerView-sample
どなたかの参考に慣れれば幸いです。

以上、やぎにいでした!


このエントリーをはてなブックマークに追加
comments powered by Disqus

<< Androidプロジェクトを作って結構な確率で導入するライブラリ     やぎすけ Advent Calendar 2016 >>



2018やぎ小屋